@aptre/protobuf-es-lite 0.4.0 → 0.4.2
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.d.ts +1 -1
- package/dist/binary.js +11 -15
- package/dist/field-wrapper.d.ts +13 -0
- package/dist/field-wrapper.js +7 -0
- package/dist/field.d.ts +1 -1
- package/dist/field.js +9 -5
- package/dist/google/protobuf/timestamp.pb.d.ts +2 -1
- package/dist/google/protobuf/timestamp.pb.js +12 -0
- package/dist/json.js +46 -32
- package/dist/message.d.ts +1 -1
- package/dist/message.js +36 -102
- package/dist/names.js +3 -1
- package/dist/partial.d.ts +2 -2
- package/dist/partial.js +9 -7
- package/dist/protoc-gen-es-lite/typescript.js +33 -1
- package/dist/scalar.d.ts +3 -2
- package/dist/scalar.js +6 -5
- package/example/tsconfig.json +1 -3
- package/package.json +11 -9
package/dist/binary.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ declare function readMapEntry(field: FieldInfo & {
|
|
|
50
50
|
}, reader: IBinaryReader, options: BinaryReadOptions): [string | number, ScalarValue | AnyMessage | undefined];
|
|
51
51
|
declare function readScalar(reader: IBinaryReader, type: ScalarType): ScalarValue;
|
|
52
52
|
declare function readScalarLTString(reader: IBinaryReader, type: ScalarType): Exclude<ScalarValue, bigint>;
|
|
53
|
-
declare function readMessage<T>(message: T, fields: FieldList, reader: IBinaryReader, lengthOrEndTagFieldNo: number, options: BinaryReadOptions, delimitedMessageEncoding
|
|
53
|
+
declare function readMessage<T>(message: T, fields: FieldList, reader: IBinaryReader, lengthOrEndTagFieldNo: number, options: BinaryReadOptions, delimitedMessageEncoding: boolean): void;
|
|
54
54
|
/**
|
|
55
55
|
* Serialize a message to binary data.
|
|
56
56
|
*/
|
package/dist/binary.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isFieldSet, resolveMessageType, } from "./field.js";
|
|
2
2
|
import { handleUnknownField, unknownFieldsSymbol } from "./unknown.js";
|
|
3
|
-
import { wrapField } from "./field-wrapper.js";
|
|
3
|
+
import { unwrapField, wrapField } from "./field-wrapper.js";
|
|
4
4
|
import { LongType, ScalarType, scalarZeroValue, } from "./scalar.js";
|
|
5
5
|
import { assert } from "./assert.js";
|
|
6
6
|
import { BinaryReader, BinaryWriter, WireType, } from "./binary-encoding.js";
|
|
@@ -26,7 +26,7 @@ reader, field, wireType, options) {
|
|
|
26
26
|
if (field.oneof) {
|
|
27
27
|
var oneofMsg = target[field.oneof.localName];
|
|
28
28
|
if (!oneofMsg) {
|
|
29
|
-
oneofMsg = target[field.oneof.localName] =
|
|
29
|
+
oneofMsg = target[field.oneof.localName] = Object.create(null);
|
|
30
30
|
}
|
|
31
31
|
target = oneofMsg;
|
|
32
32
|
if (target.case != localName) {
|
|
@@ -74,19 +74,16 @@ reader, field, wireType, options) {
|
|
|
74
74
|
if (!Array.isArray(tgtArr)) {
|
|
75
75
|
tgtArr = target[localName] = [];
|
|
76
76
|
}
|
|
77
|
-
tgtArr.push(readMessageField(reader,
|
|
77
|
+
tgtArr.push(unwrapField(messageType.fieldWrapper, readMessageField(reader, Object.create(null), messageType.fields, options, field)));
|
|
78
78
|
}
|
|
79
79
|
else {
|
|
80
|
-
target[localName] = readMessageField(reader,
|
|
81
|
-
if (messageType.fieldWrapper && !field.oneof && !field.repeated) {
|
|
82
|
-
target[localName] = messageType.fieldWrapper.unwrapField(target[localName]);
|
|
83
|
-
}
|
|
80
|
+
target[localName] = unwrapField(messageType.fieldWrapper, readMessageField(reader, Object.create(null), messageType.fields, options, field));
|
|
84
81
|
}
|
|
85
82
|
break;
|
|
86
83
|
case "map":
|
|
87
84
|
let [mapKey, mapVal] = readMapEntry(field, reader, options);
|
|
88
85
|
if (typeof target[localName] !== "object") {
|
|
89
|
-
target[localName] =
|
|
86
|
+
target[localName] = Object.create(null);
|
|
90
87
|
}
|
|
91
88
|
// safe to assume presence of map object, oneof cannot contain repeated values
|
|
92
89
|
target[localName][mapKey] = mapVal;
|
|
@@ -113,7 +110,7 @@ function readMapEntry(field, reader, options) {
|
|
|
113
110
|
break;
|
|
114
111
|
case "message":
|
|
115
112
|
const messageType = resolveMessageType(field.V.T);
|
|
116
|
-
val = readMessageField(reader,
|
|
113
|
+
val = readMessageField(reader, Object.create(null), messageType.fields, options, undefined);
|
|
117
114
|
break;
|
|
118
115
|
}
|
|
119
116
|
break;
|
|
@@ -135,7 +132,7 @@ function readMapEntry(field, reader, options) {
|
|
|
135
132
|
val = field.V.T.values[0].no;
|
|
136
133
|
break;
|
|
137
134
|
case "message":
|
|
138
|
-
val =
|
|
135
|
+
val = Object.create(null);
|
|
139
136
|
break;
|
|
140
137
|
}
|
|
141
138
|
}
|
|
@@ -184,13 +181,10 @@ function readScalarLTString(reader, type) {
|
|
|
184
181
|
// Read a message, avoiding MessageType.fromBinary() to re-use the
|
|
185
182
|
// BinaryReadOptions and the IBinaryReader.
|
|
186
183
|
function readMessageField(reader, message, fields, options, field) {
|
|
187
|
-
|
|
188
|
-
readMessage(message, fields, reader, delimited ? field.no : reader.uint32(), // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
189
|
-
options, delimited);
|
|
184
|
+
readMessage(message, fields, reader, field?.delimited ? field.no : reader.uint32(), options, field?.delimited ?? false);
|
|
190
185
|
return message;
|
|
191
186
|
}
|
|
192
187
|
function readMessage(message, fields, reader, lengthOrEndTagFieldNo, options, delimitedMessageEncoding) {
|
|
193
|
-
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
194
188
|
const end = delimitedMessageEncoding ? reader.len : reader.pos + lengthOrEndTagFieldNo;
|
|
195
189
|
let fieldNo, wireType;
|
|
196
190
|
while (reader.pos < end) {
|
|
@@ -227,7 +221,9 @@ function writeMessage(message, fields, writer, options) {
|
|
|
227
221
|
const value = field.oneof ?
|
|
228
222
|
message[field.oneof.localName].value
|
|
229
223
|
: message[field.localName];
|
|
230
|
-
|
|
224
|
+
if (value !== undefined) {
|
|
225
|
+
writeField(field, value, writer, options);
|
|
226
|
+
}
|
|
231
227
|
}
|
|
232
228
|
if (options.writeUnknownFields) {
|
|
233
229
|
writeUnknownFields(message, writer);
|
package/dist/field-wrapper.d.ts
CHANGED
|
@@ -5,7 +5,15 @@ import { ScalarType } from "./scalar.js";
|
|
|
5
5
|
* ergonomic for use as a message field.
|
|
6
6
|
*/
|
|
7
7
|
export interface FieldWrapper<T = any, U = any> {
|
|
8
|
+
/**
|
|
9
|
+
* Wrap a primitive message field value in its corresponding wrapper
|
|
10
|
+
* message. This function is idempotent.
|
|
11
|
+
*/
|
|
8
12
|
wrapField(value: U | null | undefined): T;
|
|
13
|
+
/**
|
|
14
|
+
* If the given field uses one of the well-known wrapper types, return
|
|
15
|
+
* the primitive type it wraps.
|
|
16
|
+
*/
|
|
9
17
|
unwrapField(value: T): U | null | undefined;
|
|
10
18
|
}
|
|
11
19
|
/**
|
|
@@ -13,6 +21,11 @@ export interface FieldWrapper<T = any, U = any> {
|
|
|
13
21
|
* message. This function is idempotent.
|
|
14
22
|
*/
|
|
15
23
|
export declare function wrapField<T>(fieldWrapper: FieldWrapper<T> | undefined, value: any): T;
|
|
24
|
+
/**
|
|
25
|
+
* Wrap a primitive message field value in its corresponding wrapper
|
|
26
|
+
* message. This function is idempotent.
|
|
27
|
+
*/
|
|
28
|
+
export declare function unwrapField<T, U = T>(fieldWrapper: FieldWrapper<T> | undefined, value: any): U;
|
|
16
29
|
/**
|
|
17
30
|
* If the given field uses one of the well-known wrapper types, return
|
|
18
31
|
* the primitive type it wraps.
|
package/dist/field-wrapper.js
CHANGED
|
@@ -9,6 +9,13 @@ export function wrapField(fieldWrapper, value) {
|
|
|
9
9
|
}
|
|
10
10
|
return fieldWrapper.wrapField(value);
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Wrap a primitive message field value in its corresponding wrapper
|
|
14
|
+
* message. This function is idempotent.
|
|
15
|
+
*/
|
|
16
|
+
export function unwrapField(fieldWrapper, value) {
|
|
17
|
+
return !!fieldWrapper ? fieldWrapper.unwrapField(value) : value;
|
|
18
|
+
}
|
|
12
19
|
/**
|
|
13
20
|
* If the given field uses one of the well-known wrapper types, return
|
|
14
21
|
* the primitive type it wraps.
|
package/dist/field.d.ts
CHANGED
|
@@ -113,7 +113,7 @@ export declare function newFieldList(fields: FieldListSource, packedByDefault: b
|
|
|
113
113
|
/**
|
|
114
114
|
* Returns true if the field is set.
|
|
115
115
|
*/
|
|
116
|
-
export declare function isFieldSet(field: FieldInfo, target: Record<string, any>): boolean;
|
|
116
|
+
export declare function isFieldSet(field: FieldInfo, target: Record<string, any> | null | undefined): boolean;
|
|
117
117
|
/**
|
|
118
118
|
* Returns the JSON name for a protobuf field, exactly like protoc does.
|
|
119
119
|
*/
|
package/dist/field.js
CHANGED
|
@@ -95,28 +95,32 @@ export function newFieldList(fields, packedByDefault) {
|
|
|
95
95
|
*/
|
|
96
96
|
export function isFieldSet(field, target) {
|
|
97
97
|
const localName = field.localName;
|
|
98
|
+
if (!target) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
98
101
|
if (field.repeated) {
|
|
99
|
-
return target[localName]
|
|
102
|
+
return !!target[localName]?.length;
|
|
100
103
|
}
|
|
101
104
|
if (field.oneof) {
|
|
102
|
-
return target[field.oneof.localName]
|
|
105
|
+
return target[field.oneof.localName]?.case === localName; // eslint-disable-line @typescript-eslint/no-unsafe-member-access
|
|
103
106
|
}
|
|
104
107
|
switch (field.kind) {
|
|
105
108
|
case "enum":
|
|
106
109
|
case "scalar":
|
|
107
110
|
if (field.opt || field.req) {
|
|
108
111
|
// explicit presence
|
|
109
|
-
return target[localName]
|
|
112
|
+
return target[localName] != null;
|
|
110
113
|
}
|
|
111
114
|
// implicit presence
|
|
112
115
|
if (field.kind == "enum") {
|
|
113
116
|
return target[localName] !== field.T.values[0].no;
|
|
114
117
|
}
|
|
118
|
+
// not zero value
|
|
115
119
|
return !isScalarZeroValue(field.T, target[localName]);
|
|
116
120
|
case "message":
|
|
117
|
-
return target[localName]
|
|
121
|
+
return target[localName] != null;
|
|
118
122
|
case "map":
|
|
119
|
-
return Object.keys(target[localName]).length
|
|
123
|
+
return (target[localName] != null && !!Object.keys(target[localName]).length); // eslint-disable-line @typescript-eslint/no-unsafe-argument
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
/**
|
|
@@ -118,7 +118,8 @@ export type Timestamp = Message<{
|
|
|
118
118
|
declare const Timestamp_Wkt: {
|
|
119
119
|
fromJson(json: JsonValue): Timestamp;
|
|
120
120
|
toJson(msg: Timestamp): JsonValue;
|
|
121
|
-
toDate(msg: Timestamp): Date;
|
|
121
|
+
toDate(msg: Timestamp | null | undefined): Date | null;
|
|
122
|
+
fromDate(value: Date | null | undefined): Timestamp;
|
|
122
123
|
};
|
|
123
124
|
export declare const Timestamp: MessageType<Timestamp> & typeof Timestamp_Wkt;
|
|
124
125
|
export {};
|
|
@@ -89,8 +89,20 @@ const Timestamp_Wkt = {
|
|
|
89
89
|
return new Date(ms).toISOString().replace(".000Z", z);
|
|
90
90
|
},
|
|
91
91
|
toDate(msg) {
|
|
92
|
+
if (!msg?.seconds && !msg?.nanos) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
92
95
|
return new Date(Number(msg.seconds ?? 0) * 1000 + Math.ceil((msg.nanos ?? 0) / 1000000));
|
|
93
96
|
},
|
|
97
|
+
fromDate(value) {
|
|
98
|
+
if (value == null) {
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
const ms = value.getTime();
|
|
102
|
+
const seconds = Math.floor(ms / 1000);
|
|
103
|
+
const nanos = (ms % 1000) * 1000000;
|
|
104
|
+
return { seconds: protoInt64.parse(seconds), nanos: nanos };
|
|
105
|
+
},
|
|
94
106
|
};
|
|
95
107
|
// Timestamp contains the message type declaration for Timestamp.
|
|
96
108
|
export const Timestamp = createMessageType({
|
package/dist/json.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { isFieldSet, resolveMessageType, } from "./field.js";
|
|
2
2
|
import { assert, assertFloat32, assertInt32, assertUInt32 } from "./assert.js";
|
|
3
|
-
import { LongType, ScalarType, scalarZeroValue, } from "./scalar.js";
|
|
4
|
-
import { wrapField } from "./field-wrapper.js";
|
|
3
|
+
import { LongType, ScalarType, isScalarZeroValue, normalizeScalarValue, scalarZeroValue, } from "./scalar.js";
|
|
4
|
+
import { unwrapField, wrapField } from "./field-wrapper.js";
|
|
5
|
+
import { enumZeroValue, normalizeEnumValue } from "./enum.js";
|
|
5
6
|
import { protoInt64 } from "./proto-int64.js";
|
|
6
7
|
import { protoBase64 } from "./proto-base64.js";
|
|
8
|
+
import { throwSanitizeKey } from "./names.js";
|
|
7
9
|
// Default options for parsing JSON.
|
|
8
10
|
const jsonReadDefaults = {
|
|
9
11
|
ignoreUnknownFields: false,
|
|
@@ -65,7 +67,7 @@ function readMessage(fields, typeName, json, options, message) {
|
|
|
65
67
|
return message;
|
|
66
68
|
}
|
|
67
69
|
function writeMessage(message, fields, options) {
|
|
68
|
-
const json =
|
|
70
|
+
const json = Object.create(null);
|
|
69
71
|
let field;
|
|
70
72
|
try {
|
|
71
73
|
for (field of fields.byNumber()) {
|
|
@@ -123,7 +125,7 @@ function readField(target, jsonValue, field, options) {
|
|
|
123
125
|
switch (field.kind) {
|
|
124
126
|
case "message":
|
|
125
127
|
const messageType = resolveMessageType(field.T);
|
|
126
|
-
targetArray.push(messageType.fromJson(jsonItem, options));
|
|
128
|
+
targetArray.push(unwrapField(messageType.fieldWrapper, messageType.fromJson(jsonItem, options)));
|
|
127
129
|
break;
|
|
128
130
|
case "enum":
|
|
129
131
|
const enumValue = readEnum(field.T, jsonItem, options.ignoreUnknownFields, true);
|
|
@@ -155,7 +157,7 @@ function readField(target, jsonValue, field, options) {
|
|
|
155
157
|
}
|
|
156
158
|
var targetMap = target[localName];
|
|
157
159
|
if (typeof targetMap !== "object") {
|
|
158
|
-
targetMap = target[localName] =
|
|
160
|
+
targetMap = target[localName] = Object.create(null);
|
|
159
161
|
}
|
|
160
162
|
for (const [jsonMapKey, jsonMapValue] of Object.entries(jsonValue)) {
|
|
161
163
|
if (jsonMapValue === null) {
|
|
@@ -172,6 +174,7 @@ function readField(target, jsonValue, field, options) {
|
|
|
172
174
|
}
|
|
173
175
|
throw new Error(m);
|
|
174
176
|
}
|
|
177
|
+
throwSanitizeKey(key);
|
|
175
178
|
switch (field.V.kind) {
|
|
176
179
|
case "message":
|
|
177
180
|
const messageType = resolveMessageType(field.V.T);
|
|
@@ -210,11 +213,7 @@ function readField(target, jsonValue, field, options) {
|
|
|
210
213
|
messageType.typeName != "google.protobuf.Value") {
|
|
211
214
|
return;
|
|
212
215
|
}
|
|
213
|
-
|
|
214
|
-
target[localName] = currentValue = messageType.fromJson(jsonValue, options);
|
|
215
|
-
if (messageType.fieldWrapper && !field.oneof) {
|
|
216
|
-
target[localName] = messageType.fieldWrapper.unwrapField(currentValue);
|
|
217
|
-
}
|
|
216
|
+
target[localName] = unwrapField(messageType.fieldWrapper, messageType.fromJson(jsonValue, options));
|
|
218
217
|
break;
|
|
219
218
|
case "enum":
|
|
220
219
|
const enumValue = readEnum(field.T, jsonValue, options.ignoreUnknownFields, false);
|
|
@@ -418,7 +417,7 @@ export function clearField(field, target) {
|
|
|
418
417
|
else {
|
|
419
418
|
switch (field.kind) {
|
|
420
419
|
case "map":
|
|
421
|
-
target[localName] =
|
|
420
|
+
target[localName] = Object.create(null);
|
|
422
421
|
break;
|
|
423
422
|
case "enum":
|
|
424
423
|
target[localName] = implicitPresence ? field.T.values[0].no : undefined;
|
|
@@ -436,7 +435,6 @@ export function clearField(field, target) {
|
|
|
436
435
|
// Decide whether an unset field should be emitted with JSON write option `emitDefaultValues`
|
|
437
436
|
function canEmitFieldDefaultValue(field) {
|
|
438
437
|
if (field.repeated || field.kind == "map") {
|
|
439
|
-
// maps are {}, repeated fields are []
|
|
440
438
|
return true;
|
|
441
439
|
}
|
|
442
440
|
if (field.oneof) {
|
|
@@ -456,9 +454,9 @@ function canEmitFieldDefaultValue(field) {
|
|
|
456
454
|
}
|
|
457
455
|
function writeField(field, value, options) {
|
|
458
456
|
if (field.kind == "map") {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const entries = Object.entries(value);
|
|
457
|
+
const jsonObj = Object.create(null);
|
|
458
|
+
assert(!value || typeof value === "object");
|
|
459
|
+
const entries = value ? Object.entries(value) : [];
|
|
462
460
|
switch (field.V.kind) {
|
|
463
461
|
case "scalar":
|
|
464
462
|
for (const [entryKey, entryValue] of entries) {
|
|
@@ -485,24 +483,28 @@ function writeField(field, value, options) {
|
|
|
485
483
|
: undefined;
|
|
486
484
|
}
|
|
487
485
|
if (field.repeated) {
|
|
488
|
-
assert(Array.isArray(value));
|
|
486
|
+
assert(!value || Array.isArray(value));
|
|
489
487
|
const jsonArr = [];
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
488
|
+
const valueArr = value;
|
|
489
|
+
if (valueArr && valueArr.length) {
|
|
490
|
+
switch (field.kind) {
|
|
491
|
+
case "scalar":
|
|
492
|
+
for (let i = 0; i < valueArr.length; i++) {
|
|
493
|
+
jsonArr.push(writeScalar(field.T, valueArr[i]));
|
|
494
|
+
}
|
|
495
|
+
break;
|
|
496
|
+
case "enum":
|
|
497
|
+
for (let i = 0; i < valueArr.length; i++) {
|
|
498
|
+
jsonArr.push(writeEnum(field.T, valueArr[i], options.enumAsInteger));
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
501
|
+
case "message":
|
|
502
|
+
const messageType = resolveMessageType(field.T);
|
|
503
|
+
for (let i = 0; i < valueArr.length; i++) {
|
|
504
|
+
jsonArr.push(messageType.toJson(wrapField(messageType.fieldWrapper, valueArr[i])));
|
|
505
|
+
}
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
506
508
|
}
|
|
507
509
|
return options.emitDefaultValues || jsonArr.length > 0 ?
|
|
508
510
|
jsonArr
|
|
@@ -510,10 +512,22 @@ function writeField(field, value, options) {
|
|
|
510
512
|
}
|
|
511
513
|
switch (field.kind) {
|
|
512
514
|
case "scalar":
|
|
515
|
+
const scalarValue = normalizeScalarValue(field.T, value, false);
|
|
516
|
+
if (!options.emitDefaultValues
|
|
517
|
+
&& isScalarZeroValue(field.T, scalarValue)) {
|
|
518
|
+
return undefined;
|
|
519
|
+
}
|
|
513
520
|
return writeScalar(field.T, value);
|
|
514
521
|
case "enum":
|
|
522
|
+
const enumValue = normalizeEnumValue(field.T, value);
|
|
523
|
+
if (!options.emitDefaultValues && enumZeroValue(field.T) === enumValue) {
|
|
524
|
+
return undefined;
|
|
525
|
+
}
|
|
515
526
|
return writeEnum(field.T, value, options.enumAsInteger);
|
|
516
527
|
case "message":
|
|
528
|
+
if (!options.emitDefaultValues && value == null) {
|
|
529
|
+
return undefined;
|
|
530
|
+
}
|
|
517
531
|
const messageType = resolveMessageType(field.T);
|
|
518
532
|
return messageType.toJson(wrapField(messageType.fieldWrapper, value));
|
|
519
533
|
}
|
package/dist/message.d.ts
CHANGED
|
@@ -111,7 +111,7 @@ export type MessageTypeParams<T extends Message<T>> = Pick<MessageType<T>, "fiel
|
|
|
111
111
|
*/
|
|
112
112
|
export declare function createMessageType<T extends Message<T>, E extends Record<string, Function> = {}>(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
|
-
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;
|
|
115
115
|
/**
|
|
116
116
|
* createCompleteMessage recursively builds a message filled with zero values based on the given FieldList.
|
|
117
117
|
*/
|
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
|
*
|
|
@@ -52,7 +54,7 @@ export function createMessageType(params, exts) {
|
|
|
52
54
|
const message = {};
|
|
53
55
|
if (bytes && bytes.length) {
|
|
54
56
|
const opt = binaryMakeReadOptions(options);
|
|
55
|
-
binaryReadMessage(message, fields, opt.readerFactory(bytes), bytes.byteLength, opt, delimitedMessageEncoding);
|
|
57
|
+
binaryReadMessage(message, fields, opt.readerFactory(bytes), bytes.byteLength, opt, delimitedMessageEncoding ?? false);
|
|
56
58
|
}
|
|
57
59
|
return message;
|
|
58
60
|
},
|
|
@@ -109,9 +111,12 @@ export function compareMessages(fields, a, b) {
|
|
|
109
111
|
const va = a[m.localName];
|
|
110
112
|
const vb = b[m.localName];
|
|
111
113
|
if (m.repeated) {
|
|
112
|
-
if (va
|
|
114
|
+
if ((va?.length ?? 0) !== (vb?.length ?? 0)) {
|
|
113
115
|
return false;
|
|
114
116
|
}
|
|
117
|
+
if (!va?.length) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
115
120
|
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- repeated fields are never "map"
|
|
116
121
|
switch (m.kind) {
|
|
117
122
|
case "message":
|
|
@@ -132,9 +137,12 @@ export function compareMessages(fields, a, b) {
|
|
|
132
137
|
case "scalar":
|
|
133
138
|
return scalarEquals(m.T, va, vb);
|
|
134
139
|
case "oneof":
|
|
135
|
-
if (va
|
|
140
|
+
if (va?.case !== vb?.case) {
|
|
136
141
|
return false;
|
|
137
142
|
}
|
|
143
|
+
if (va == null) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
138
146
|
const s = m.findField(va.case);
|
|
139
147
|
if (s === undefined) {
|
|
140
148
|
return true;
|
|
@@ -165,61 +173,12 @@ export function compareMessages(fields, a, b) {
|
|
|
165
173
|
}
|
|
166
174
|
});
|
|
167
175
|
}
|
|
168
|
-
// clone a single field value - i.e. the element type of repeated fields, the value type of maps
|
|
169
|
-
function cloneSingularField(value, fieldInfo) {
|
|
170
|
-
if (value === undefined) {
|
|
171
|
-
return value;
|
|
172
|
-
}
|
|
173
|
-
if (fieldInfo.kind === "message") {
|
|
174
|
-
return cloneMessage(value, resolveMessageType(fieldInfo.T).fields);
|
|
175
|
-
}
|
|
176
|
-
if (fieldInfo.kind === "oneof") {
|
|
177
|
-
if (value.case === undefined) {
|
|
178
|
-
return undefined;
|
|
179
|
-
}
|
|
180
|
-
const selectedField = fieldInfo.findField(value.case);
|
|
181
|
-
if (!selectedField) {
|
|
182
|
-
throw new Error(`Invalid oneof case "${value.case}" for ${fieldInfo.name}`);
|
|
183
|
-
}
|
|
184
|
-
return {
|
|
185
|
-
case: value.case,
|
|
186
|
-
value: cloneSingularField(value.value, selectedField),
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
if (value instanceof Uint8Array) {
|
|
190
|
-
const c = new Uint8Array(value.byteLength);
|
|
191
|
-
c.set(value);
|
|
192
|
-
return c;
|
|
193
|
-
}
|
|
194
|
-
return value;
|
|
195
|
-
}
|
|
196
|
-
// TODO use isFieldSet() here to support future field presence
|
|
197
176
|
export function cloneMessage(message, fields) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const source = message[member.localName];
|
|
201
|
-
let copy;
|
|
202
|
-
if (member.repeated) {
|
|
203
|
-
copy = source.map((v) => cloneSingularField(v, member));
|
|
204
|
-
}
|
|
205
|
-
else if (member.kind == "map") {
|
|
206
|
-
copy = {};
|
|
207
|
-
for (const [key, v] of Object.entries(source)) {
|
|
208
|
-
copy[key] = cloneSingularField(v, member);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
else if (member.kind == "oneof") {
|
|
212
|
-
const f = member.findField(source.case);
|
|
213
|
-
copy =
|
|
214
|
-
f ?
|
|
215
|
-
{ case: source.case, value: cloneSingularField(source.value, member) }
|
|
216
|
-
: { case: undefined };
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
copy = cloneSingularField(source, member);
|
|
220
|
-
}
|
|
221
|
-
clone[member.localName] = copy;
|
|
177
|
+
if (message == null) {
|
|
178
|
+
return null;
|
|
222
179
|
}
|
|
180
|
+
const clone = Object.create(null);
|
|
181
|
+
applyPartialMessage(message, clone, fields, true);
|
|
223
182
|
return clone;
|
|
224
183
|
}
|
|
225
184
|
/**
|
|
@@ -227,67 +186,42 @@ export function cloneMessage(message, fields) {
|
|
|
227
186
|
*/
|
|
228
187
|
export function createCompleteMessage(fields) {
|
|
229
188
|
const message = {};
|
|
230
|
-
for (const field of fields.
|
|
231
|
-
const fieldKind = field
|
|
189
|
+
for (const field of fields.byMember()) {
|
|
190
|
+
const { localName, kind: fieldKind } = field;
|
|
191
|
+
throwSanitizeKey(localName);
|
|
232
192
|
switch (fieldKind) {
|
|
193
|
+
case "oneof":
|
|
194
|
+
message[localName] = Object.create(null);
|
|
195
|
+
message[localName].case = undefined;
|
|
196
|
+
break;
|
|
233
197
|
case "scalar":
|
|
234
198
|
if (field.repeated) {
|
|
235
|
-
message[
|
|
199
|
+
message[localName] = [];
|
|
236
200
|
}
|
|
237
201
|
else {
|
|
238
|
-
|
|
239
|
-
case ScalarType.DOUBLE:
|
|
240
|
-
case ScalarType.FLOAT:
|
|
241
|
-
message[field.localName] = 0;
|
|
242
|
-
break;
|
|
243
|
-
case ScalarType.INT64:
|
|
244
|
-
case ScalarType.UINT64:
|
|
245
|
-
case ScalarType.INT32:
|
|
246
|
-
case ScalarType.FIXED64:
|
|
247
|
-
case ScalarType.FIXED32:
|
|
248
|
-
case ScalarType.UINT32:
|
|
249
|
-
case ScalarType.SFIXED32:
|
|
250
|
-
case ScalarType.SFIXED64:
|
|
251
|
-
case ScalarType.SINT32:
|
|
252
|
-
case ScalarType.SINT64:
|
|
253
|
-
message[field.localName] = 0;
|
|
254
|
-
break;
|
|
255
|
-
case ScalarType.BOOL:
|
|
256
|
-
message[field.localName] = false;
|
|
257
|
-
break;
|
|
258
|
-
case ScalarType.STRING:
|
|
259
|
-
message[field.localName] = "";
|
|
260
|
-
break;
|
|
261
|
-
case ScalarType.BYTES:
|
|
262
|
-
message[field.localName] =
|
|
263
|
-
new Uint8Array();
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
202
|
+
message[localName] = scalarZeroValue(field.T, LongType.BIGINT);
|
|
266
203
|
}
|
|
267
204
|
break;
|
|
268
205
|
case "enum":
|
|
269
|
-
|
|
270
|
-
message[field.localName] = [];
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
message[field.localName] = 0;
|
|
274
|
-
}
|
|
206
|
+
message[localName] = field.repeated ? [] : enumZeroValue(field.T);
|
|
275
207
|
break;
|
|
276
208
|
case "message":
|
|
209
|
+
// oneofs are handled above
|
|
277
210
|
if (field.oneof) {
|
|
278
|
-
|
|
279
|
-
continue;
|
|
211
|
+
break;
|
|
280
212
|
}
|
|
281
|
-
const messageType = resolveMessageType(field.T);
|
|
282
213
|
if (field.repeated) {
|
|
283
|
-
message[
|
|
284
|
-
|
|
285
|
-
else {
|
|
286
|
-
message[field.localName] = createCompleteMessage(messageType.fields);
|
|
214
|
+
message[localName] = [];
|
|
215
|
+
break;
|
|
287
216
|
}
|
|
217
|
+
const messageType = resolveMessageType(field.T);
|
|
218
|
+
message[localName] =
|
|
219
|
+
!!messageType.fieldWrapper ?
|
|
220
|
+
messageType.fieldWrapper.unwrapField(null)
|
|
221
|
+
: createCompleteMessage(messageType.fields);
|
|
288
222
|
break;
|
|
289
223
|
case "map":
|
|
290
|
-
message[
|
|
224
|
+
message[localName] = Object.create(null);
|
|
291
225
|
break;
|
|
292
226
|
default:
|
|
293
227
|
field;
|
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,7 @@ export const safeIdentifier = (name) => {
|
|
|
246
248
|
return name;
|
|
247
249
|
};
|
|
248
250
|
export function checkSanitizeKey(key) {
|
|
249
|
-
return typeof key === "string" && key
|
|
251
|
+
return typeof key === "string" && !!key.length && !reservedObjectProperties.has(key);
|
|
250
252
|
}
|
|
251
253
|
export function throwSanitizeKey(key) {
|
|
252
254
|
if (typeof key !== "string") {
|
package/dist/partial.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
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;
|
|
4
|
-
export declare function applyPartialMap(sourceMap: Record<string, any> | undefined, targetMap: Record<string, any>, value: MapValueInfo): 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
|
@@ -4,7 +4,9 @@ import { createCompleteMessage } from "./message.js";
|
|
|
4
4
|
import { throwSanitizeKey } from "./names.js";
|
|
5
5
|
import { normalizeScalarValue } from "./scalar.js";
|
|
6
6
|
// applyPartialMessage applies a partial source message to a target message.
|
|
7
|
-
|
|
7
|
+
//
|
|
8
|
+
// if clone is set: values are deep-copied including Uint8Arrays.
|
|
9
|
+
export function applyPartialMessage(source, target, fields, clone = false) {
|
|
8
10
|
if (source == null || target == null) {
|
|
9
11
|
return;
|
|
10
12
|
}
|
|
@@ -62,7 +64,7 @@ export function applyPartialMessage(source, target, fields) {
|
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
else if (sourceField.kind === "scalar") {
|
|
65
|
-
dv.value = normalizeScalarValue(sourceField.T, sv);
|
|
67
|
+
dv.value = normalizeScalarValue(sourceField.T, sv, clone);
|
|
66
68
|
}
|
|
67
69
|
else {
|
|
68
70
|
dv.value = sv;
|
|
@@ -77,10 +79,10 @@ export function applyPartialMessage(source, target, fields) {
|
|
|
77
79
|
if (dst == null || !Array.isArray(dst)) {
|
|
78
80
|
dst = t[localName] = [];
|
|
79
81
|
}
|
|
80
|
-
dst.push(...sourceValue.map((v) => normalizeScalarValue(member.T, v)));
|
|
82
|
+
dst.push(...sourceValue.map((v) => normalizeScalarValue(member.T, v, clone)));
|
|
81
83
|
break;
|
|
82
84
|
}
|
|
83
|
-
t[localName] = normalizeScalarValue(member.T, sourceValue);
|
|
85
|
+
t[localName] = normalizeScalarValue(member.T, sourceValue, clone);
|
|
84
86
|
break;
|
|
85
87
|
case "enum":
|
|
86
88
|
t[localName] = normalizeEnumValue(member.T, sourceValue);
|
|
@@ -93,7 +95,7 @@ export function applyPartialMessage(source, target, fields) {
|
|
|
93
95
|
if (typeof tMap !== "object") {
|
|
94
96
|
tMap = t[localName] = Object.create(null);
|
|
95
97
|
}
|
|
96
|
-
applyPartialMap(sourceValue, tMap, member.V);
|
|
98
|
+
applyPartialMap(sourceValue, tMap, member.V, clone);
|
|
97
99
|
break;
|
|
98
100
|
case "message":
|
|
99
101
|
const mt = resolveMessageType(member.T);
|
|
@@ -137,7 +139,7 @@ export function applyPartialMessage(source, target, fields) {
|
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
// applyPartialMap applies a partial source map to a target map.
|
|
140
|
-
export function applyPartialMap(sourceMap, targetMap, value) {
|
|
142
|
+
export function applyPartialMap(sourceMap, targetMap, value, clone) {
|
|
141
143
|
if (sourceMap == null) {
|
|
142
144
|
return;
|
|
143
145
|
}
|
|
@@ -149,7 +151,7 @@ export function applyPartialMap(sourceMap, targetMap, value) {
|
|
|
149
151
|
for (const [k, v] of Object.entries(sourceMap)) {
|
|
150
152
|
throwSanitizeKey(k);
|
|
151
153
|
if (v !== undefined) {
|
|
152
|
-
targetMap[k] = normalizeScalarValue(value.T, v);
|
|
154
|
+
targetMap[k] = normalizeScalarValue(value.T, v, clone);
|
|
153
155
|
}
|
|
154
156
|
else {
|
|
155
157
|
delete targetMap[k];
|
|
@@ -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":
|
package/dist/scalar.d.ts
CHANGED
|
@@ -72,6 +72,7 @@ export declare function isScalarZeroValue(type: ScalarType, value: unknown): boo
|
|
|
72
72
|
* Zero or null is cast to the zero value.
|
|
73
73
|
* Bytes is cast to a Uint8Array.
|
|
74
74
|
* The BigInt long type is used.
|
|
75
|
+
* If clone is set, Uint8Array will always be copied to a new value.
|
|
75
76
|
*/
|
|
76
|
-
export declare function normalizeScalarValue<T>(type: ScalarType, value: T | null | undefined, longType?: LongType): T;
|
|
77
|
-
export declare function toU8Arr(input: ArrayLike<number
|
|
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;
|
package/dist/scalar.js
CHANGED
|
@@ -166,21 +166,22 @@ export function isScalarZeroValue(type, value) {
|
|
|
166
166
|
* Zero or null is cast to the zero value.
|
|
167
167
|
* Bytes is cast to a Uint8Array.
|
|
168
168
|
* The BigInt long type is used.
|
|
169
|
+
* If clone is set, Uint8Array will always be copied to a new value.
|
|
169
170
|
*/
|
|
170
|
-
export function normalizeScalarValue(type, value, longType = LongType.BIGINT) {
|
|
171
|
+
export function normalizeScalarValue(type, value, clone, longType = LongType.BIGINT) {
|
|
171
172
|
if (value == null) {
|
|
172
173
|
return scalarZeroValue(type, longType);
|
|
173
174
|
}
|
|
174
175
|
if (type === ScalarType.BYTES) {
|
|
175
|
-
return toU8Arr(value);
|
|
176
|
+
return toU8Arr(value, clone);
|
|
176
177
|
}
|
|
177
178
|
if (isScalarZeroValue(type, value)) {
|
|
178
179
|
return scalarZeroValue(type, longType);
|
|
179
180
|
}
|
|
180
|
-
// TODO: enforce correct type for other values as well.
|
|
181
181
|
return value;
|
|
182
182
|
}
|
|
183
183
|
// converts any ArrayLike<number> to Uint8Array if necessary.
|
|
184
|
-
|
|
185
|
-
|
|
184
|
+
// if clone is set, force clones the array to a copy.
|
|
185
|
+
export function toU8Arr(input, clone) {
|
|
186
|
+
return !clone && input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
186
187
|
}
|
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.2",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "git+ssh://git@github.com/aperturerobotics/protobuf-es-lite.git"
|
|
@@ -49,18 +49,19 @@
|
|
|
49
49
|
"scripts": {
|
|
50
50
|
"clean": "rimraf ./dist",
|
|
51
51
|
"build": "npm run clean && tsc --project tsconfig.json --outDir ./dist",
|
|
52
|
-
"release:version": "npm version patch -m \"release: v%s\" --no-git-tag-version",
|
|
53
|
-
"release:version:minor": "npm version minor -m \"release: v%s\" --no-git-tag-version",
|
|
54
|
-
"release:commit": "git reset && git add package.json && git commit -s -m \"release: v$npm_package_version\" && git tag v$npm_package_version",
|
|
55
|
-
"release:publish": "git push && git push --tags && npm run build && npm publish",
|
|
56
|
-
"release": "npm run release:version && npm run release:commit",
|
|
57
|
-
"release:minor": "npm run release:version:minor && npm run release:commit",
|
|
58
52
|
"typecheck": "tsc --noEmit --project tsconfig.json --outDir ./dist",
|
|
59
53
|
"gen": "npm run build && npm run gen:wkt && npm run gen:example",
|
|
60
54
|
"gen:wkt": "cd ./src && bash gen.bash",
|
|
61
55
|
"gen:example": "bash gen.bash ./example/example.proto",
|
|
62
56
|
"format": "prettier --write './src/**/(*.ts|*.tsx|*.html|*.css|*.scss)'",
|
|
63
|
-
"precommit": "lint-staged"
|
|
57
|
+
"precommit": "lint-staged",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"release:version": "npm version patch -m \"release: v%s\" --no-git-tag-version",
|
|
60
|
+
"release:version:minor": "npm version minor -m \"release: v%s\" --no-git-tag-version",
|
|
61
|
+
"release:commit": "git reset && git add package.json && git commit -s -m \"release: v$npm_package_version\" && git tag v$npm_package_version",
|
|
62
|
+
"release:publish": "git push && git push --tags && npm run build && npm publish",
|
|
63
|
+
"release": "npm run release:version && npm run release:commit",
|
|
64
|
+
"release:minor": "npm run release:version:minor && npm run release:commit"
|
|
64
65
|
},
|
|
65
66
|
"preferUnplugged": true,
|
|
66
67
|
"pre-commit": [
|
|
@@ -76,7 +77,8 @@
|
|
|
76
77
|
"pre-commit": "^1.2.2",
|
|
77
78
|
"prettier": "^3.2.5",
|
|
78
79
|
"rimraf": "^5.0.5",
|
|
79
|
-
"typescript": "^5.4.5"
|
|
80
|
+
"typescript": "^5.4.5",
|
|
81
|
+
"vitest": "^1.5.3"
|
|
80
82
|
},
|
|
81
83
|
"lint-staged": {
|
|
82
84
|
"package.json": "prettier --write",
|