ts-proto 1.151.1 → 1.152.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/integration/codegen.js +63 -0
- package/build/{generate-grpc-web.js → src/generate-grpc-web.js} +19 -21
- package/build/{generate-services.js → src/generate-services.js} +1 -1
- package/build/{main.js → src/main.js} +24 -13
- package/build/{types.js → src/types.js} +17 -17
- package/build/tests/case-test.js +52 -0
- package/build/tests/options-test.js +148 -0
- package/build/tests/types-test.js +56 -0
- package/build/tests/utils-test.js +65 -0
- package/package.json +4 -2
- /package/build/{case.js → src/case.js} +0 -0
- /package/build/{context.js → src/context.js} +0 -0
- /package/build/{encode.js → src/encode.js} +0 -0
- /package/build/{enums.js → src/enums.js} +0 -0
- /package/build/{generate-async-iterable.js → src/generate-async-iterable.js} +0 -0
- /package/build/{generate-generic-service-definition.js → src/generate-generic-service-definition.js} +0 -0
- /package/build/{generate-grpc-js.js → src/generate-grpc-js.js} +0 -0
- /package/build/{generate-nestjs.js → src/generate-nestjs.js} +0 -0
- /package/build/{generate-nice-grpc.js → src/generate-nice-grpc.js} +0 -0
- /package/build/{generate-struct-wrappers.js → src/generate-struct-wrappers.js} +0 -0
- /package/build/{generate-type-registry.js → src/generate-type-registry.js} +0 -0
- /package/build/{options.js → src/options.js} +0 -0
- /package/build/{plugin.js → src/plugin.js} +0 -0
- /package/build/{schema.js → src/schema.js} +0 -0
- /package/build/{sourceInfo.js → src/sourceInfo.js} +0 -0
- /package/build/{utils.js → src/utils.js} +0 -0
- /package/build/{visit.js → src/visit.js} +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ts_proto_descriptors_1 = require("ts-proto-descriptors");
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const main_1 = require("../src/main");
|
|
8
|
+
const types_1 = require("../src/types");
|
|
9
|
+
const utils_1 = require("../src/utils");
|
|
10
|
+
const options_1 = require("../src/options");
|
|
11
|
+
const generate_type_registry_1 = require("../src/generate-type-registry");
|
|
12
|
+
/**
|
|
13
|
+
* Generates output for our integration tests from their example proto files.
|
|
14
|
+
*
|
|
15
|
+
* We use snapshots of the protoc CodeGeneratorRequest's that are captured
|
|
16
|
+
* by running ./update_proto_bins.sh, just because various machines/CI/etc
|
|
17
|
+
* may not have the `protoc` compiler on their path.
|
|
18
|
+
*/
|
|
19
|
+
async function main() {
|
|
20
|
+
const dir = process.argv[2];
|
|
21
|
+
const file = process.argv[3];
|
|
22
|
+
const param = process.argv[4];
|
|
23
|
+
await generate(file, dir, param);
|
|
24
|
+
}
|
|
25
|
+
async function generate(binFile, baseDir, parameter) {
|
|
26
|
+
const stdin = await (0, util_1.promisify)(fs_1.readFile)(binFile);
|
|
27
|
+
const request = ts_proto_descriptors_1.CodeGeneratorRequest.decode(stdin);
|
|
28
|
+
request.parameter = parameter;
|
|
29
|
+
const options = (0, options_1.optionsFromParameter)(parameter || "");
|
|
30
|
+
const typeMap = (0, types_1.createTypeMap)(request, options);
|
|
31
|
+
for (let file of request.protoFile) {
|
|
32
|
+
// Make a different utils per file to track per-file usage
|
|
33
|
+
if (options.M[file.name]) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const utils = (0, main_1.makeUtils)(options);
|
|
37
|
+
const ctx = { options, typeMap, utils };
|
|
38
|
+
const [path, code] = (0, main_1.generateFile)(ctx, file);
|
|
39
|
+
const filePath = `${baseDir}/${path}`;
|
|
40
|
+
const dirPath = (0, path_1.parse)(filePath).dir;
|
|
41
|
+
await (0, util_1.promisify)(fs_1.mkdir)(dirPath, { recursive: true }).catch(() => { });
|
|
42
|
+
await (0, util_1.promisify)(fs_1.writeFile)(filePath, code.toString({ ...(0, options_1.getTsPoetOpts)(options), path }));
|
|
43
|
+
}
|
|
44
|
+
if (options.outputTypeRegistry) {
|
|
45
|
+
const utils = (0, main_1.makeUtils)(options);
|
|
46
|
+
const ctx = { options, typeMap, utils };
|
|
47
|
+
const path = "typeRegistry.ts";
|
|
48
|
+
const code = (0, generate_type_registry_1.generateTypeRegistry)(ctx);
|
|
49
|
+
const filePath = `${baseDir}/${path}`;
|
|
50
|
+
await (0, util_1.promisify)(fs_1.writeFile)(filePath, code.toString({ ...(0, options_1.getTsPoetOpts)(options), path }));
|
|
51
|
+
}
|
|
52
|
+
if (options.outputIndex) {
|
|
53
|
+
for (const [path, code] of (0, utils_1.generateIndexFiles)(request.protoFile, options)) {
|
|
54
|
+
const filePath = `${baseDir}/${path}`;
|
|
55
|
+
const dirPath = (0, path_1.parse)(filePath).dir;
|
|
56
|
+
await (0, util_1.promisify)(fs_1.mkdir)(dirPath, { recursive: true }).catch(() => { });
|
|
57
|
+
await (0, util_1.promisify)(fs_1.writeFile)(filePath, code.toString({ ...(0, options_1.getTsPoetOpts)(options), path }));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
main().then(() => {
|
|
62
|
+
console.log(`${process.argv[3]}: Done`);
|
|
63
|
+
});
|
|
@@ -227,17 +227,16 @@ function createPromiseUnaryMethod(ctx) {
|
|
|
227
227
|
${useAbortSignal ? "abortSignal?: AbortSignal," : ""}
|
|
228
228
|
): Promise<any> {
|
|
229
229
|
const request = { ..._request, ...methodDesc.requestType };
|
|
230
|
-
const maybeCombinedMetadata =
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
: metadata || this.options.metadata;
|
|
230
|
+
const maybeCombinedMetadata = metadata && this.options.metadata
|
|
231
|
+
? new ${BrowserHeaders}({ ...this.options?.metadata.headersMap, ...metadata?.headersMap })
|
|
232
|
+
: metadata ?? this.options.metadata;
|
|
234
233
|
return new Promise((resolve, reject) => {
|
|
235
234
|
${useAbortSignal ? `const client =` : ""} ${grpc}.unary(methodDesc, {
|
|
236
235
|
request,
|
|
237
236
|
host: this.host,
|
|
238
|
-
metadata: maybeCombinedMetadata,
|
|
239
|
-
transport: this.options.transport,
|
|
240
|
-
debug: this.options.debug,
|
|
237
|
+
metadata: maybeCombinedMetadata ?? {},
|
|
238
|
+
...(this.options.transport !== undefined ? {transport: this.options.transport} : {}),
|
|
239
|
+
debug: this.options.debug ?? false,
|
|
241
240
|
onEnd: function (response) {
|
|
242
241
|
if (response.status === grpc.Code.OK) {
|
|
243
242
|
resolve(response.message!.toObject());
|
|
@@ -271,17 +270,16 @@ function createObservableUnaryMethod(ctx) {
|
|
|
271
270
|
${useAbortSignal ? "abortSignal?: AbortSignal," : ""}
|
|
272
271
|
): ${(0, types_1.observableType)(ctx)}<any> {
|
|
273
272
|
const request = { ..._request, ...methodDesc.requestType };
|
|
274
|
-
const maybeCombinedMetadata =
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
: metadata || this.options.metadata;
|
|
273
|
+
const maybeCombinedMetadata = metadata && this.options.metadata
|
|
274
|
+
? new ${BrowserHeaders}({ ...this.options?.metadata.headersMap, ...metadata?.headersMap })
|
|
275
|
+
: metadata ?? this.options.metadata;
|
|
278
276
|
return new Observable(observer => {
|
|
279
277
|
${useAbortSignal ? `const client =` : ""} ${grpc}.unary(methodDesc, {
|
|
280
278
|
request,
|
|
281
279
|
host: this.host,
|
|
282
|
-
metadata: maybeCombinedMetadata,
|
|
283
|
-
transport: this.options.transport,
|
|
284
|
-
debug: this.options.debug,
|
|
280
|
+
metadata: maybeCombinedMetadata ?? {},
|
|
281
|
+
...(this.options.transport !== undefined ? {transport: this.options.transport} : {}),
|
|
282
|
+
debug: this.options.debug ?? false,
|
|
285
283
|
onEnd: (next) => {
|
|
286
284
|
if (next.status !== 0) {
|
|
287
285
|
const err = new ${ctx.utils.GrpcWebError}(next.statusMessage, next.status, next.trailers);
|
|
@@ -317,21 +315,21 @@ function createInvokeMethod(ctx) {
|
|
|
317
315
|
metadata: grpc.Metadata | undefined,
|
|
318
316
|
${useAbortSignal ? "abortSignal?: AbortSignal," : ""}
|
|
319
317
|
): ${(0, types_1.observableType)(ctx)}<any> {
|
|
320
|
-
const upStreamCodes = this.options.upStreamRetryCodes
|
|
318
|
+
const upStreamCodes = this.options.upStreamRetryCodes ?? [];
|
|
321
319
|
const DEFAULT_TIMEOUT_TIME: number = 3_000;
|
|
322
320
|
const request = { ..._request, ...methodDesc.requestType };
|
|
323
|
-
const
|
|
324
|
-
metadata && this.options.metadata
|
|
321
|
+
const transport = this.options.streamingTransport ?? this.options.transport;
|
|
322
|
+
const maybeCombinedMetadata = metadata && this.options.metadata
|
|
325
323
|
? new ${BrowserHeaders}({ ...this.options?.metadata.headersMap, ...metadata?.headersMap })
|
|
326
|
-
: metadata
|
|
324
|
+
: metadata ?? this.options.metadata;
|
|
327
325
|
return new Observable(observer => {
|
|
328
326
|
const upStream = (() => {
|
|
329
327
|
const client = ${grpc}.invoke(methodDesc, {
|
|
330
328
|
host: this.host,
|
|
331
329
|
request,
|
|
332
|
-
transport
|
|
333
|
-
metadata: maybeCombinedMetadata,
|
|
334
|
-
debug: this.options.debug,
|
|
330
|
+
...(transport !== undefined ? {transport} : {}),
|
|
331
|
+
metadata: maybeCombinedMetadata ?? {},
|
|
332
|
+
debug: this.options.debug ?? false,
|
|
335
333
|
onMessage: (next) => observer.next(next),
|
|
336
334
|
onEnd: (code: ${grpc}.Code, message: string, trailers: ${grpc}.Metadata) => {
|
|
337
335
|
if (code === 0) {
|
|
@@ -206,7 +206,7 @@ function generateBatchingRpcMethod(ctx, batchMethod) {
|
|
|
206
206
|
// If the return type is a map, lookup each key in the result
|
|
207
207
|
lambda.push((0, ts_poet_1.code) `
|
|
208
208
|
return this.${methodDesc.formattedName}(ctx, request).then(res => {
|
|
209
|
-
return ${inputFieldName}.map(key => res.${outputFieldName}[key])
|
|
209
|
+
return ${inputFieldName}.map(key => res.${outputFieldName}[key] ?? ${ctx.utils.fail}())
|
|
210
210
|
});
|
|
211
211
|
`);
|
|
212
212
|
}
|
|
@@ -279,6 +279,7 @@ function makeUtils(options) {
|
|
|
279
279
|
...makeNiceGrpcServerStreamingMethodResult(),
|
|
280
280
|
...makeGrpcWebErrorClass(bytes),
|
|
281
281
|
...makeExtensionClass(options),
|
|
282
|
+
...makeAssertionUtils(),
|
|
282
283
|
};
|
|
283
284
|
}
|
|
284
285
|
exports.makeUtils = makeUtils;
|
|
@@ -365,10 +366,10 @@ function makeLongUtils(options, bytes) {
|
|
|
365
366
|
}
|
|
366
367
|
function makeByteUtils() {
|
|
367
368
|
const globalThis = (0, ts_poet_1.conditionalOutput)("tsProtoGlobalThis", (0, ts_poet_1.code) `
|
|
368
|
-
declare
|
|
369
|
-
declare
|
|
370
|
-
declare
|
|
371
|
-
|
|
369
|
+
declare const self: any | undefined;
|
|
370
|
+
declare const window: any | undefined;
|
|
371
|
+
declare const global: any | undefined;
|
|
372
|
+
const tsProtoGlobalThis: any = (() => {
|
|
372
373
|
if (typeof globalThis !== "undefined") return globalThis;
|
|
373
374
|
if (typeof self !== "undefined") return self;
|
|
374
375
|
if (typeof window !== "undefined") return window;
|
|
@@ -589,6 +590,14 @@ function makeExtensionClass(options) {
|
|
|
589
590
|
`);
|
|
590
591
|
return { Extension };
|
|
591
592
|
}
|
|
593
|
+
function makeAssertionUtils() {
|
|
594
|
+
const fail = (0, ts_poet_1.conditionalOutput)("fail", (0, ts_poet_1.code) `
|
|
595
|
+
function fail(message?: string): never {
|
|
596
|
+
throw new Error(message ?? "Failed");
|
|
597
|
+
}
|
|
598
|
+
`);
|
|
599
|
+
return { fail };
|
|
600
|
+
}
|
|
592
601
|
// Create the interface with properties
|
|
593
602
|
function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fullTypeName) {
|
|
594
603
|
var _a;
|
|
@@ -615,12 +624,15 @@ function generateInterfaceDeclaration(ctx, fullName, messageDesc, sourceInfo, fu
|
|
|
615
624
|
const info = sourceInfo.lookup(sourceInfo_1.Fields.message.field, index);
|
|
616
625
|
(0, utils_1.maybeAddComment)(info, chunks, (_a = fieldDesc.options) === null || _a === void 0 ? void 0 : _a.deprecated);
|
|
617
626
|
const name = (0, case_1.maybeSnakeToCamel)(fieldDesc.name, options);
|
|
618
|
-
const
|
|
619
|
-
const
|
|
620
|
-
|
|
627
|
+
const isOptional = (0, types_1.isOptionalProperty)(fieldDesc, messageDesc.options, options);
|
|
628
|
+
const type = (0, types_1.toTypeName)(ctx, messageDesc, fieldDesc, isOptional);
|
|
629
|
+
if (isOptional && !type.toString().includes("undefined")) {
|
|
630
|
+
console.warn(name, type);
|
|
631
|
+
}
|
|
632
|
+
chunks.push((0, ts_poet_1.code) `${maybeReadonly(options)}${name}${isOptional ? "?" : ""}: ${type}, `);
|
|
621
633
|
});
|
|
622
634
|
if (ctx.options.unknownFields) {
|
|
623
|
-
chunks.push((0, ts_poet_1.code) `_unknownFields?: {[key: number]: Uint8Array[]},`);
|
|
635
|
+
chunks.push((0, ts_poet_1.code) `_unknownFields?: {[key: number]: Uint8Array[]} | undefined,`);
|
|
624
636
|
}
|
|
625
637
|
chunks.push((0, ts_poet_1.code) `}`);
|
|
626
638
|
return (0, ts_poet_1.joinCode)(chunks, { on: "\n" });
|
|
@@ -635,7 +647,7 @@ function generateOneofProperty(ctx, messageDesc, oneofIndex, sourceInfo) {
|
|
|
635
647
|
return (0, ts_poet_1.code) `{ ${mbReadonly}$case: '${fieldName}', ${mbReadonly}${fieldName}: ${typeName} }`;
|
|
636
648
|
}), { on: " | " });
|
|
637
649
|
const name = (0, case_1.maybeSnakeToCamel)(messageDesc.oneofDecl[oneofIndex].name, options);
|
|
638
|
-
return (0, ts_poet_1.code) `${mbReadonly}${name}?: ${unionType},`;
|
|
650
|
+
return (0, ts_poet_1.code) `${mbReadonly}${name}?: ${unionType} | undefined,`;
|
|
639
651
|
/*
|
|
640
652
|
// Ideally we'd put the comments for each oneof field next to the anonymous
|
|
641
653
|
// type we've created in the type union above, but ts-poet currently lacks
|
|
@@ -1135,8 +1147,7 @@ function generateEncode(ctx, fullName, messageDesc) {
|
|
|
1135
1147
|
});
|
|
1136
1148
|
if (options.unknownFields) {
|
|
1137
1149
|
chunks.push((0, ts_poet_1.code) `if (message._unknownFields !== undefined) {
|
|
1138
|
-
for (const key
|
|
1139
|
-
const values = message._unknownFields[key];
|
|
1150
|
+
for (const [key, values] of Object.entries(message._unknownFields)) {
|
|
1140
1151
|
const tag = parseInt(key, 10);
|
|
1141
1152
|
for (const value of values) {
|
|
1142
1153
|
writer.uint32(tag);
|
|
@@ -1330,7 +1341,7 @@ function generateExtension(ctx, message, extension) {
|
|
|
1330
1341
|
chunks.push((0, ts_poet_1.code) `const values: ${type} = [];`);
|
|
1331
1342
|
// start loop over all buffers
|
|
1332
1343
|
chunks.push((0, ts_poet_1.code) `
|
|
1333
|
-
for (
|
|
1344
|
+
for (const buffer of input) {
|
|
1334
1345
|
const reader = ${Reader}.create(buffer);
|
|
1335
1346
|
`);
|
|
1336
1347
|
if ((0, types_1.packedType)(extension.type) === undefined) {
|
|
@@ -1360,7 +1371,7 @@ function generateExtension(ctx, message, extension) {
|
|
|
1360
1371
|
else {
|
|
1361
1372
|
// pick the last entry, since it overrides all previous entries if not repeated
|
|
1362
1373
|
chunks.push((0, ts_poet_1.code) `
|
|
1363
|
-
const reader = ${Reader}.create(input[input.length -1]);
|
|
1374
|
+
const reader = ${Reader}.create(input[input.length -1] ?? ${ctx.utils.fail}());
|
|
1364
1375
|
return ${readSnippet};
|
|
1365
1376
|
},
|
|
1366
1377
|
`);
|
|
@@ -531,19 +531,15 @@ function longTypeName(ctx) {
|
|
|
531
531
|
}
|
|
532
532
|
/** Maps `.some_proto_namespace.Message` to a TypeName. */
|
|
533
533
|
function messageToTypeName(ctx, protoType, typeOptions = {}) {
|
|
534
|
+
var _a;
|
|
534
535
|
const { options, typeMap } = ctx;
|
|
535
536
|
// Watch for the wrapper types `.google.protobuf.*Value`. If we're mapping
|
|
536
537
|
// them to basic built-in types, we union the type with undefined to
|
|
537
538
|
// indicate the value is optional. Exceptions:
|
|
538
539
|
// - If the field is repeated, values cannot be undefined.
|
|
539
|
-
// - If useOptionals='messages' or useOptionals='all', all non-scalar types
|
|
540
|
-
// are already optional properties, so there's no need for that union.
|
|
541
540
|
let valueType = valueTypeName(ctx, protoType);
|
|
542
541
|
if (!typeOptions.keepValueType && valueType) {
|
|
543
|
-
if (
|
|
544
|
-
options.useOptionals === true ||
|
|
545
|
-
options.useOptionals === "messages" ||
|
|
546
|
-
options.useOptionals === "all") {
|
|
542
|
+
if ((_a = typeOptions.repeated) !== null && _a !== void 0 ? _a : false) {
|
|
547
543
|
return valueType;
|
|
548
544
|
}
|
|
549
545
|
return (0, ts_poet_1.code) `${valueType} | undefined`;
|
|
@@ -575,26 +571,32 @@ function getEnumMethod(ctx, enumProtoType, methodSuffix) {
|
|
|
575
571
|
}
|
|
576
572
|
exports.getEnumMethod = getEnumMethod;
|
|
577
573
|
/** Return the TypeName for any field (primitive/message/etc.) as exposed in the interface. */
|
|
578
|
-
function toTypeName(ctx, messageDesc, field) {
|
|
574
|
+
function toTypeName(ctx, messageDesc, field, ensureOptional = false) {
|
|
575
|
+
function finalize(type, isOptional) {
|
|
576
|
+
if (isOptional) {
|
|
577
|
+
return (0, ts_poet_1.code) `${type} | undefined`;
|
|
578
|
+
}
|
|
579
|
+
return type;
|
|
580
|
+
}
|
|
579
581
|
let type = basicTypeName(ctx, field, { keepValueType: false });
|
|
580
582
|
if (isRepeated(field)) {
|
|
581
583
|
const mapType = messageDesc ? detectMapType(ctx, messageDesc, field) : false;
|
|
582
584
|
if (mapType) {
|
|
583
585
|
const { keyType, valueType } = mapType;
|
|
584
586
|
if (ctx.options.useMapType) {
|
|
585
|
-
return (0, ts_poet_1.code) `Map<${keyType}, ${valueType}
|
|
587
|
+
return finalize((0, ts_poet_1.code) `Map<${keyType}, ${valueType}>`, ensureOptional);
|
|
586
588
|
}
|
|
587
|
-
return (0, ts_poet_1.code) `{ [key: ${keyType} ]: ${valueType} }
|
|
589
|
+
return finalize((0, ts_poet_1.code) `{ [key: ${keyType} ]: ${valueType} }`, ensureOptional);
|
|
588
590
|
}
|
|
589
591
|
if (ctx.options.useReadonlyTypes) {
|
|
590
|
-
return (0, ts_poet_1.code) `readonly ${type}[]
|
|
592
|
+
return finalize((0, ts_poet_1.code) `readonly ${type}[]`, ensureOptional);
|
|
591
593
|
}
|
|
592
|
-
return (0, ts_poet_1.code) `${type}[]
|
|
594
|
+
return finalize((0, ts_poet_1.code) `${type}[]`, ensureOptional);
|
|
593
595
|
}
|
|
594
596
|
if (isValueType(ctx, field)) {
|
|
595
597
|
// google.protobuf.*Value types are already unioned with `undefined`
|
|
596
598
|
// in messageToTypeName, so no need to consider them for that here.
|
|
597
|
-
return type;
|
|
599
|
+
return finalize(type, false);
|
|
598
600
|
}
|
|
599
601
|
// By default (useOptionals='none', oneof=properties), non-scalar fields
|
|
600
602
|
// outside oneofs and all fields within a oneof clause need to be unioned
|
|
@@ -608,14 +610,12 @@ function toTypeName(ctx, messageDesc, field) {
|
|
|
608
610
|
// clause, spelling each option out inside a large type union. No need for
|
|
609
611
|
// union with `undefined` here, either.
|
|
610
612
|
const { options } = ctx;
|
|
611
|
-
|
|
613
|
+
return finalize(type, (!isWithinOneOf(field) &&
|
|
612
614
|
isMessage(field) &&
|
|
613
615
|
(options.useOptionals === false || options.useOptionals === "none")) ||
|
|
614
616
|
(isWithinOneOf(field) && options.oneof === options_1.OneofOption.PROPERTIES) ||
|
|
615
|
-
(isWithinOneOf(field) && field.proto3Optional)
|
|
616
|
-
|
|
617
|
-
}
|
|
618
|
-
return type;
|
|
617
|
+
(isWithinOneOf(field) && field.proto3Optional) ||
|
|
618
|
+
ensureOptional);
|
|
619
619
|
}
|
|
620
620
|
exports.toTypeName = toTypeName;
|
|
621
621
|
function detectMapType(ctx, messageDesc, fieldDesc) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const case_1 = require("../src/case");
|
|
4
|
+
const options_1 = require("../src/options");
|
|
5
|
+
const utils_1 = require("../src/utils");
|
|
6
|
+
const keys = (0, options_1.optionsFromParameter)("snakeToCamel=keys");
|
|
7
|
+
describe("case", () => {
|
|
8
|
+
it("converts snake to camel by default", () => {
|
|
9
|
+
expect((0, case_1.maybeSnakeToCamel)("foo_bar", (0, options_1.optionsFromParameter)(undefined))).toEqual("fooBar");
|
|
10
|
+
});
|
|
11
|
+
it("leaves as-is if snakeToCamel is false", () => {
|
|
12
|
+
expect((0, case_1.maybeSnakeToCamel)("foo_bar", (0, options_1.optionsFromParameter)("snakeToCamel=false"))).toEqual("foo_bar");
|
|
13
|
+
});
|
|
14
|
+
it("de-upper cases", () => {
|
|
15
|
+
expect((0, case_1.maybeSnakeToCamel)("FOO_BAR", keys)).toEqual("fooBar");
|
|
16
|
+
});
|
|
17
|
+
it("leaves existing mixed cases", () => {
|
|
18
|
+
expect((0, case_1.maybeSnakeToCamel)("clientI_d", keys)).toEqual("clientID");
|
|
19
|
+
expect((0, case_1.maybeSnakeToCamel)("menu_calendarI_d", keys)).toEqual("menuCalendarID");
|
|
20
|
+
expect((0, case_1.maybeSnakeToCamel)("display_nameI18n", keys)).toEqual("displayNameI18n");
|
|
21
|
+
});
|
|
22
|
+
it("leaves the first character as it was", () => {
|
|
23
|
+
expect((0, case_1.maybeSnakeToCamel)("Foo_Bar", keys)).toEqual("FooBar");
|
|
24
|
+
});
|
|
25
|
+
it("does nothing is already camel", () => {
|
|
26
|
+
expect((0, case_1.maybeSnakeToCamel)("FooBar", keys)).toEqual("FooBar");
|
|
27
|
+
});
|
|
28
|
+
// deal with original protoc which converts
|
|
29
|
+
// _uuid -> Uuid
|
|
30
|
+
// __uuid -> Uuid
|
|
31
|
+
// _uuid_foo -> UuidFoo
|
|
32
|
+
it("converts snake to camel with first underscore", () => {
|
|
33
|
+
expect((0, case_1.maybeSnakeToCamel)("_uuid", { snakeToCamel: ["keys"] })).toEqual("Uuid");
|
|
34
|
+
});
|
|
35
|
+
it("converts snake to camel with first double underscore", () => {
|
|
36
|
+
expect((0, case_1.maybeSnakeToCamel)("__uuid", { snakeToCamel: ["keys"] })).toEqual("Uuid");
|
|
37
|
+
});
|
|
38
|
+
it("converts snake to camel with first underscore and camelize other", () => {
|
|
39
|
+
expect((0, case_1.maybeSnakeToCamel)("_uuid_foo", { snakeToCamel: ["keys"] })).toEqual("UuidFoo");
|
|
40
|
+
});
|
|
41
|
+
it("converts string to camel case respecting word separation, getAPIValue === getApiValue", () => {
|
|
42
|
+
expect((0, case_1.camelCaseGrpc)("GetAPIValue")).toEqual("getApiValue");
|
|
43
|
+
});
|
|
44
|
+
describe("getFieldJsonName", () => {
|
|
45
|
+
it("keeps snake case when jsonName is probably not set", () => {
|
|
46
|
+
expect((0, utils_1.getFieldJsonName)({ name: "foo_bar", jsonName: "fooBar" }, { snakeToCamel: [] })).toBe("foo_bar");
|
|
47
|
+
});
|
|
48
|
+
it("uses jsonName when it is set", () => {
|
|
49
|
+
expect((0, utils_1.getFieldJsonName)({ name: "foo_bar", jsonName: "foo" }, { snakeToCamel: [] })).toBe("foo");
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const options_1 = require("../src/options");
|
|
4
|
+
describe("options", () => {
|
|
5
|
+
it("can set outputJsonMethods with nestJs=true", () => {
|
|
6
|
+
expect((0, options_1.optionsFromParameter)("nestJs=true,outputJsonMethods=true")).toMatchInlineSnapshot(`
|
|
7
|
+
{
|
|
8
|
+
"M": {},
|
|
9
|
+
"addGrpcMetadata": false,
|
|
10
|
+
"addNestjsRestParameter": false,
|
|
11
|
+
"constEnums": false,
|
|
12
|
+
"context": false,
|
|
13
|
+
"emitImportedFiles": true,
|
|
14
|
+
"enumsAsLiterals": false,
|
|
15
|
+
"env": "both",
|
|
16
|
+
"esModuleInterop": false,
|
|
17
|
+
"exportCommonSymbols": true,
|
|
18
|
+
"fileSuffix": "",
|
|
19
|
+
"forceLong": "number",
|
|
20
|
+
"importSuffix": "",
|
|
21
|
+
"initializeFieldsAsUndefined": false,
|
|
22
|
+
"lowerCaseServiceMethods": true,
|
|
23
|
+
"metadataType": undefined,
|
|
24
|
+
"nestJs": true,
|
|
25
|
+
"oneof": "properties",
|
|
26
|
+
"onlyTypes": false,
|
|
27
|
+
"outputClientImpl": false,
|
|
28
|
+
"outputEncodeMethods": false,
|
|
29
|
+
"outputExtensions": false,
|
|
30
|
+
"outputIndex": false,
|
|
31
|
+
"outputJsonMethods": true,
|
|
32
|
+
"outputPartialMethods": false,
|
|
33
|
+
"outputSchema": false,
|
|
34
|
+
"outputServices": [
|
|
35
|
+
"default",
|
|
36
|
+
],
|
|
37
|
+
"outputTypeAnnotations": false,
|
|
38
|
+
"outputTypeRegistry": false,
|
|
39
|
+
"removeEnumPrefix": false,
|
|
40
|
+
"returnObservable": false,
|
|
41
|
+
"snakeToCamel": [
|
|
42
|
+
"json",
|
|
43
|
+
"keys",
|
|
44
|
+
],
|
|
45
|
+
"stringEnums": false,
|
|
46
|
+
"unknownFields": false,
|
|
47
|
+
"unrecognizedEnum": true,
|
|
48
|
+
"useAbortSignal": false,
|
|
49
|
+
"useAsyncIterable": false,
|
|
50
|
+
"useDate": "timestamp",
|
|
51
|
+
"useExactTypes": true,
|
|
52
|
+
"useJsonWireFormat": false,
|
|
53
|
+
"useMapType": false,
|
|
54
|
+
"useMongoObjectId": false,
|
|
55
|
+
"useNumericEnumForJson": false,
|
|
56
|
+
"useOptionals": "none",
|
|
57
|
+
"usePrototypeForDefaults": false,
|
|
58
|
+
"useReadonlyTypes": false,
|
|
59
|
+
"useSnakeTypeName": true,
|
|
60
|
+
}
|
|
61
|
+
`);
|
|
62
|
+
});
|
|
63
|
+
it("can set outputJsonMethods with nestJs=true", () => {
|
|
64
|
+
const options = (0, options_1.optionsFromParameter)("outputClientImpl=grpc-web,addGrpcMetadata=false");
|
|
65
|
+
expect(options).toMatchObject({
|
|
66
|
+
outputClientImpl: "grpc-web",
|
|
67
|
+
addGrpcMetadata: false,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
it("can set fileSuffix", () => {
|
|
71
|
+
const options = (0, options_1.optionsFromParameter)("fileSuffix=.pb");
|
|
72
|
+
expect(options).toMatchObject({
|
|
73
|
+
fileSuffix: ".pb",
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
it("can set outputServices to false", () => {
|
|
77
|
+
const options = (0, options_1.optionsFromParameter)("outputServices=false");
|
|
78
|
+
expect(options).toMatchObject({
|
|
79
|
+
outputServices: [options_1.ServiceOption.NONE],
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
it("can set outputServices to grpc", () => {
|
|
83
|
+
const options = (0, options_1.optionsFromParameter)("outputServices=grpc-js");
|
|
84
|
+
expect(options).toMatchObject({
|
|
85
|
+
outputServices: [options_1.ServiceOption.GRPC],
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
it("can set useOptionals to boolean", () => {
|
|
89
|
+
const options = (0, options_1.optionsFromParameter)("useOptionals=true");
|
|
90
|
+
expect(options).toMatchObject({
|
|
91
|
+
useOptionals: true,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
it("can set useOptionals to string", () => {
|
|
95
|
+
const options = (0, options_1.optionsFromParameter)("useOptionals=messages");
|
|
96
|
+
expect(options).toMatchObject({
|
|
97
|
+
useOptionals: "messages",
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it("can set snakeToCamel as string", () => {
|
|
101
|
+
const options = (0, options_1.optionsFromParameter)("snakeToCamel=keys");
|
|
102
|
+
expect(options).toMatchObject({ snakeToCamel: ["keys"] });
|
|
103
|
+
});
|
|
104
|
+
it("can set snakeToCamel as two values", () => {
|
|
105
|
+
const options = (0, options_1.optionsFromParameter)("snakeToCamel=keys_json");
|
|
106
|
+
expect(options).toMatchObject({ snakeToCamel: ["keys", "json"] });
|
|
107
|
+
});
|
|
108
|
+
it("can set multiple values as an array", () => {
|
|
109
|
+
const options = (0, options_1.optionsFromParameter)("foo=one,foo=two");
|
|
110
|
+
expect(options).toMatchObject({ foo: ["one", "two"] });
|
|
111
|
+
});
|
|
112
|
+
it("´output*=false implies onlyTypes", () => {
|
|
113
|
+
const options = (0, options_1.optionsFromParameter)("outputJsonMethods=false,outputEncodeMethods=false,outputClientImpl=false");
|
|
114
|
+
expect(options).toMatchObject({
|
|
115
|
+
onlyTypes: true,
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
it("onlyTypes implies output*=false", () => {
|
|
119
|
+
const options = (0, options_1.optionsFromParameter)("onlyTypes=true");
|
|
120
|
+
expect(options).toMatchObject({
|
|
121
|
+
outputJsonMethods: false,
|
|
122
|
+
outputEncodeMethods: false,
|
|
123
|
+
outputClientImpl: false,
|
|
124
|
+
nestJs: false,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
it("useJsonWireFormat requires onlyTypes", () => {
|
|
128
|
+
const options = (0, options_1.optionsFromParameter)("useJsonWireFormat=true");
|
|
129
|
+
expect(options).toMatchObject({
|
|
130
|
+
useJsonWireFormat: false,
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
it("useSnakeTypeName", () => {
|
|
134
|
+
const options = (0, options_1.optionsFromParameter)("useSnakeTypeName=false");
|
|
135
|
+
expect(options).toMatchObject({
|
|
136
|
+
useSnakeTypeName: false,
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
it("useJsonWireFormat implies useDate=string and stringEnums=true", () => {
|
|
140
|
+
const options = (0, options_1.optionsFromParameter)("useJsonWireFormat=true,onlyTypes=true");
|
|
141
|
+
expect(options).toMatchObject({
|
|
142
|
+
useJsonWireFormat: true,
|
|
143
|
+
onlyTypes: true,
|
|
144
|
+
stringEnums: true,
|
|
145
|
+
useDate: options_1.DateOption.STRING,
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const options_1 = require("../src/options");
|
|
4
|
+
const types_1 = require("../src/types");
|
|
5
|
+
const ts_poet_1 = require("ts-poet");
|
|
6
|
+
const fakeProto = undefined;
|
|
7
|
+
describe("types", () => {
|
|
8
|
+
describe("messageToTypeName", () => {
|
|
9
|
+
const testCases = [
|
|
10
|
+
{
|
|
11
|
+
descr: "top-level messages",
|
|
12
|
+
typeMap: new Map([[".namespace.Message", ["namespace", "Message", fakeProto]]]),
|
|
13
|
+
protoType: ".namespace.Message",
|
|
14
|
+
expected: (0, ts_poet_1.code) `${(0, ts_poet_1.imp)("Message@./namespace")}`,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
descr: "nested messages",
|
|
18
|
+
typeMap: new Map([[".namespace.Message.Inner", ["namespace", "Message_Inner", fakeProto]]]),
|
|
19
|
+
protoType: ".namespace.Message.Inner",
|
|
20
|
+
expected: (0, ts_poet_1.code) `${(0, ts_poet_1.imp)("Message_Inner@./namespace")}`,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
descr: "nested messages: .js import suffix",
|
|
24
|
+
typeMap: new Map([[".namespace.Message.Inner", ["namespace", "Message_Inner", fakeProto]]]),
|
|
25
|
+
protoType: ".namespace.Message.Inner",
|
|
26
|
+
options: { ...(0, options_1.defaultOptions)(), importSuffix: ".js" },
|
|
27
|
+
expected: (0, ts_poet_1.code) `${(0, ts_poet_1.imp)("Message_Inner@./namespace.js")}`,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
descr: "value types",
|
|
31
|
+
typeMap: new Map(),
|
|
32
|
+
protoType: ".google.protobuf.StringValue",
|
|
33
|
+
expected: (0, ts_poet_1.code) `string | undefined`,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
descr: "value types (useOptionals=true)",
|
|
37
|
+
typeMap: new Map(),
|
|
38
|
+
protoType: ".google.protobuf.StringValue",
|
|
39
|
+
options: { ...(0, options_1.defaultOptions)(), useOptionals: true },
|
|
40
|
+
expected: (0, ts_poet_1.code) `string | undefined`,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
descr: 'value types (useOptionals="all")',
|
|
44
|
+
typeMap: new Map(),
|
|
45
|
+
protoType: ".google.protobuf.StringValue",
|
|
46
|
+
options: { ...(0, options_1.defaultOptions)(), useOptionals: "all" },
|
|
47
|
+
expected: (0, ts_poet_1.code) `string | undefined`,
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
testCases.forEach((t) => it(t.descr, async () => {
|
|
51
|
+
const ctx = { options: (0, options_1.defaultOptions)(), utils: undefined, ...t };
|
|
52
|
+
const got = (0, types_1.messageToTypeName)(ctx, t.protoType);
|
|
53
|
+
expect(got.toString()).toEqual(t.expected.toString());
|
|
54
|
+
}));
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("../src/utils");
|
|
4
|
+
const ts_poet_1 = require("ts-poet");
|
|
5
|
+
describe("utils", () => {
|
|
6
|
+
describe("maybeAddComment", () => {
|
|
7
|
+
it("handles single-line impl comments", () => {
|
|
8
|
+
// Foo
|
|
9
|
+
const chunks = [];
|
|
10
|
+
(0, utils_1.maybeAddComment)({ leadingComments: " Foo\n" }, chunks);
|
|
11
|
+
expect((0, ts_poet_1.joinCode)(chunks).toString()).toMatchInlineSnapshot(`
|
|
12
|
+
"/** Foo */
|
|
13
|
+
"
|
|
14
|
+
`);
|
|
15
|
+
});
|
|
16
|
+
it("handles single-dot star comments", () => {
|
|
17
|
+
// /* Foo */
|
|
18
|
+
const chunks = [];
|
|
19
|
+
(0, utils_1.maybeAddComment)({ leadingComments: " Foo " }, chunks);
|
|
20
|
+
expect((0, ts_poet_1.joinCode)(chunks).toString()).toMatchInlineSnapshot(`
|
|
21
|
+
"/** Foo */
|
|
22
|
+
"
|
|
23
|
+
`);
|
|
24
|
+
});
|
|
25
|
+
it("handles single-line double-dot star comments", () => {
|
|
26
|
+
// /** Foo */
|
|
27
|
+
const chunks = [];
|
|
28
|
+
(0, utils_1.maybeAddComment)({ leadingComments: " * Foo " }, chunks);
|
|
29
|
+
expect((0, ts_poet_1.joinCode)(chunks).toString()).toMatchInlineSnapshot(`
|
|
30
|
+
"/** Foo */
|
|
31
|
+
"
|
|
32
|
+
`);
|
|
33
|
+
});
|
|
34
|
+
it("handles double-line double-dot star comments", () => {
|
|
35
|
+
// /**
|
|
36
|
+
// * Foo
|
|
37
|
+
// *
|
|
38
|
+
// * bar.
|
|
39
|
+
// */
|
|
40
|
+
const chunks = [];
|
|
41
|
+
(0, utils_1.maybeAddComment)({ leadingComments: "*\n Foo\n \n bar.\n" }, chunks);
|
|
42
|
+
expect((0, ts_poet_1.joinCode)(chunks).toString()).toMatchInlineSnapshot(`
|
|
43
|
+
"/**
|
|
44
|
+
* Foo
|
|
45
|
+
*
|
|
46
|
+
* bar.
|
|
47
|
+
*/
|
|
48
|
+
"
|
|
49
|
+
`);
|
|
50
|
+
});
|
|
51
|
+
it("handles double-line impl comments", () => {
|
|
52
|
+
// // Foo
|
|
53
|
+
// // Bar
|
|
54
|
+
const chunks = [];
|
|
55
|
+
(0, utils_1.maybeAddComment)({ leadingComments: " Foo\n Bar\n" }, chunks);
|
|
56
|
+
expect((0, ts_poet_1.joinCode)(chunks).toString()).toMatchInlineSnapshot(`
|
|
57
|
+
"/**
|
|
58
|
+
* Foo
|
|
59
|
+
* Bar
|
|
60
|
+
*/
|
|
61
|
+
"
|
|
62
|
+
`);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-proto",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.152.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "build/plugin.js",
|
|
6
6
|
"repository": "github:stephenh/ts-proto",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"proto2pbjs": "docker compose run --rm protoc pbjs.sh",
|
|
17
17
|
"bin2ts": "docker compose run --rm protoc codegen.sh",
|
|
18
18
|
"test": "yarn jest -c jest.config.js --maxWorkers=2",
|
|
19
|
+
"tsc:check": "./tsc-check.sh tsconfig.json integration/tsconfig.json integration/tsconfig.proto.json protos/tsconfig.json",
|
|
19
20
|
"format": "prettier --write {src,tests}/**/*.ts integration/*.ts",
|
|
20
21
|
"format:check": "prettier --list-different {src,tests}/**/*.ts",
|
|
21
22
|
"setup:docker": "docker compose build",
|
|
@@ -42,8 +43,9 @@
|
|
|
42
43
|
"@semantic-release/github": "^9.0.2",
|
|
43
44
|
"@semantic-release/npm": "^10.0.3",
|
|
44
45
|
"@semantic-release/release-notes-generator": "^11.0.2",
|
|
46
|
+
"@tsconfig/strictest": "^2.0.1",
|
|
45
47
|
"@types/jest": "^29.5.2",
|
|
46
|
-
"@types/node": "^
|
|
48
|
+
"@types/node": "^16.18.38",
|
|
47
49
|
"chokidar": "^3.5.3",
|
|
48
50
|
"jest": "^29.5.0",
|
|
49
51
|
"jest-ts-webcompat-resolver": "^1.0.0",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/build/{generate-generic-service-definition.js → src/generate-generic-service-definition.js}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|