diff --git a/package.json b/package.json index b7d5035a7..3b4ebe791 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ }, "dependencies": { "@types/object-hash": "^1.3.0", + "case-anything": "^2.1.10", "dataloader": "^1.4.0", "object-hash": "^1.3.1", "protobufjs": "^6.11.3", diff --git a/protos/build.sh b/protos/build.sh index e03103bfb..fd1cfa1d5 100755 --- a/protos/build.sh +++ b/protos/build.sh @@ -12,5 +12,3 @@ protoc \ ./node_modules/.bin/tsc -p tsconfig.json - - diff --git a/src/case.ts b/src/case.ts index 4757aedd2..b5816ce31 100644 --- a/src/case.ts +++ b/src/case.ts @@ -1,3 +1,5 @@ +import { camelCase as camelCaseAnything } from "case-anything"; + import { Options } from "./options"; /** Converts `key` to TS/JS camel-case idiom, unless overridden not to. */ @@ -32,3 +34,13 @@ export function capitalize(s: string): string { export function camelCase(s: string): string { return s.substring(0, 1).toLowerCase() + s.substring(1); } + +export function camelCaseGrpc(s: string): string { + /* This function uses the exact same semantics found inside the grpc + * nodejs library. Camel case splitting must be done by word i.e + * GetAPIValue must become getApiValue (notice the API becomes Api). + * This needs to be followed otherwise it will not succeed in the grpc nodejs module. + */ + + return camelCaseAnything(s); +} diff --git a/src/utils.ts b/src/utils.ts index 11ebe1920..e869019c3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -9,7 +9,7 @@ import { import ReadStream = NodeJS.ReadStream; import { SourceDescription } from "./sourceInfo"; import { Options, ServiceOption } from "./options"; -import { camelCase, snakeToCamel } from "./case"; +import { camelCaseGrpc, snakeToCamel } from "./case"; export function protoFilesToGenerate(request: CodeGeneratorRequest): FileDescriptorProto[] { return request.protoFile.filter((f) => request.fileToGenerate.includes(f.name)); @@ -167,7 +167,7 @@ export class FormattedMethodDescriptor implements MethodDescriptorProto { let result = methodName; if (options.lowerCaseServiceMethods || options.outputServices.includes(ServiceOption.GRPC)) { - result = camelCase(result); + result = camelCaseGrpc(result); } return result; diff --git a/tests/case-test.ts b/tests/case-test.ts index 07303072c..2d16c9b2b 100644 --- a/tests/case-test.ts +++ b/tests/case-test.ts @@ -1,4 +1,4 @@ -import { maybeSnakeToCamel } from "../src/case"; +import { maybeSnakeToCamel, camelCaseGrpc } from "../src/case"; import { Options, optionsFromParameter } from "../src/options"; import { getFieldJsonName } from "../src/utils"; @@ -47,6 +47,10 @@ describe("case", () => { expect(maybeSnakeToCamel("_uuid_foo", { snakeToCamel: ["keys"] })).toEqual("UuidFoo"); }); + it("converts string to camel case respecting word separation, getAPIValue === getApiValue", () => { + expect(camelCaseGrpc("GetAPIValue")).toEqual("getApiValue"); + }); + describe("getFieldJsonName", () => { it("keeps snake case when jsonName is probably not set", () => { expect(getFieldJsonName({ name: "foo_bar", jsonName: "fooBar" }, { snakeToCamel: [] })).toBe("foo_bar"); diff --git a/yarn.lock b/yarn.lock index f443ace6e..fdb5b285d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2799,6 +2799,13 @@ __metadata: languageName: node linkType: hard +"case-anything@npm:^2.1.10": + version: 2.1.10 + resolution: "case-anything@npm:2.1.10" + checksum: eff2769d7da178115be8ac2617ccbb850664ffd36f0a897e000d9dd5a64300141128f6a8fe024bd98ec63cc9173a72c1426bbcaac328c8a44109ce15f7c14a5e + languageName: node + linkType: hard + "caseless@npm:~0.12.0": version: 0.12.0 resolution: "caseless@npm:0.12.0" @@ -8957,6 +8964,7 @@ __metadata: "@types/jest": ^26.0.22 "@types/node": ^14.14.37 "@types/object-hash": ^1.3.0 + case-anything: ^2.1.10 chokidar: ^3.5.2 dataloader: ^1.4.0 jest: ^28.1.2