From 8499c7b20f02334c2ac13598b678b130249173ac Mon Sep 17 00:00:00 2001 From: tenkirin <60653216+tenkirin@users.noreply.github.com> Date: Sat, 1 Mar 2025 12:38:33 +0900 Subject: [PATCH 1/4] feat(proto-loader-gen-types): add options for specifying file extensions --- .../bin/proto-loader-gen-types.ts | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index bdd7d789..4dbc80de 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -47,6 +47,8 @@ type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { outputTemplate: string; inputBranded: boolean; outputBranded: boolean; + targetFileExtension?: string; + importFileExtension?: string; } class TextFormatter { @@ -105,8 +107,8 @@ function getImportPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service): st return stripLeadingPeriod(to.fullName).replace(/\./g, '/'); } -function getPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { - return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.ts'; +function getPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service, extension: string = '.ts') { + return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + extension; } function getPathToRoot(from: Protobuf.NamespaceBase) { @@ -153,7 +155,7 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv throw new Error('Invalid object passed to getImportLine'); } } - return `import type { ${importedTypes} } from '${filePath}';` + return `import type { ${importedTypes} } from '${filePath}${options.importFileExtension ?? ''}';` } function getChildMessagesAndEnums(namespace: Protobuf.NamespaceBase): (Protobuf.Type | Protobuf.Enum)[] { @@ -787,21 +789,21 @@ function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: G if (nested instanceof Protobuf.Type) { generateMessageInterfaces(fileFormatter, nested, options); if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + console.log(`Writing ${options.outDir}/${getPath(nested, options.targetFileExtension)} from file ${nested.filename}`); } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options.targetFileExtension)}`, fileFormatter.getFullText())); } else if (nested instanceof Protobuf.Enum) { generateEnumInterface(fileFormatter, nested, options); if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + console.log(`Writing ${options.outDir}/${getPath(nested, options.targetFileExtension)} from file ${nested.filename}`); } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options.targetFileExtension)}`, fileFormatter.getFullText())); } else if (nested instanceof Protobuf.Service) { generateServiceInterfaces(fileFormatter, nested, options); if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + console.log(`Writing ${options.outDir}/${getPath(nested, options.targetFileExtension)} from file ${nested.filename}`); } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options.targetFileExtension)}`, fileFormatter.getFullText())); } else if (isNamespaceBase(nested)) { filePromises.push(...generateFilesForNamespace(nested, options)); } @@ -877,6 +879,8 @@ async function runScript() { .option('outputTemplate', { string: true, default: `${templateStr}__Output` }) .option('inputBranded', boolDefaultFalseOption) .option('outputBranded', boolDefaultFalseOption) + .option('targetFileExtension', { string: true, default: '.ts' }) + .option('importFileExtension', { string: true }) .coerce('longs', value => { switch (value) { case 'String': return String; @@ -916,6 +920,8 @@ async function runScript() { outputTemplate: 'Template for mapping output or "restricted" type names', inputBranded: 'Output property for branded type for "permissive" types with fullName of the Message as its value', outputBranded: 'Output property for branded type for "restricted" types with fullName of the Message as its value', + targetFileExtension: 'File extension for generated files. Defaults to .ts', + importFileExtension: 'File extension for import specifiers in generated code. Defaults to none (omitted)' }).demandOption(['outDir']) .demand(1) .usage('$0 [options] filenames...') From b43225d6a647914f4bbb30ad28cfd66a229aa6df Mon Sep 17 00:00:00 2001 From: tenkirin <60653216+tenkirin@users.noreply.github.com> Date: Sat, 1 Mar 2025 12:56:32 +0900 Subject: [PATCH 2/4] docs(proto-loader-gen-types): update option description of `proto-loader-gen-types` in README.md --- packages/proto-loader/README.md | 75 ++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 3ee67272..4c8d3ce6 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -61,44 +61,53 @@ The `proto-loader-gen-types` script distributed with this package can be used to proto-loader-gen-types.js [options] filenames... Options: - --help Show help [boolean] - --version Show version number [boolean] - --keepCase Preserve the case of field names + --help Show help [boolean] + --version Show version number [boolean] + --keepCase Preserve the case of field names [boolean] [default: false] - --longs The type that should be used to output 64 bit integer - values. Can be String, Number[string] [default: "Long"] - --enums The type that should be used to output enum fields. Can - be String [string] [default: "number"] - --bytes The type that should be used to output bytes fields. - Can be String, Array [string] [default: "Buffer"] - --defaults Output default values for omitted fields + --longs The type that should be used to output 64 bit + integer values. Can be String, Number + [string] [default: "Long"] + --enums The type that should be used to output enum fields. + Can be String [string] [default: "number"] + --bytes The type that should be used to output bytes + fields. Can be String, Array + [string] [default: "Buffer"] + --defaults Output default values for omitted fields [boolean] [default: false] - --arrays Output default values for omitted repeated fields even - if --defaults is not set [boolean] [default: false] - --objects Output default values for omitted message fields even - if --defaults is not set [boolean] [default: false] - --oneofs Output virtual oneof fields set to the present field's - name [boolean] [default: false] - --json Represent Infinity and NaN as strings in float fields. - Also decode google.protobuf.Any automatically + --arrays Output default values for omitted repeated fields + even if --defaults is not set [boolean] [default: false] - --includeComments Generate doc comments from comments in the original - files [boolean] [default: false] - -I, --includeDirs Directories to search for included files [array] - -O, --outDir Directory in which to output files [string] [required] - --grpcLib The gRPC implementation library that these types will - be used with. If not provided, some types will not be - generated [string] - --inputTemplate Template for mapping input or "permissive" type names - [string] [default: "%s"] - --outputTemplate Template for mapping output or "restricted" type names - [string] [default: "%s__Output"] - --inputBranded Output property for branded type for "permissive" - types with fullName of the Message as its value + --objects Output default values for omitted message fields + even if --defaults is not set [boolean] [default: false] - --outputBranded Output property for branded type for "restricted" - types with fullName of the Message as its value + --oneofs Output virtual oneof fields set to the present + field's name [boolean] [default: false] + --json Represent Infinity and NaN as strings in float + fields. Also decode google.protobuf.Any + automatically [boolean] [default: false] + --includeComments Generate doc comments from comments in the original + files [boolean] [default: false] + -I, --includeDirs Directories to search for included files [array] + -O, --outDir Directory in which to output files + [string] [required] + --grpcLib The gRPC implementation library that these types + will be used with. If not provided, some types will + not be generated [string] + --inputTemplate Template for mapping input or "permissive" type + names [string] [default: "%s"] + --outputTemplate Template for mapping output or "restricted" type + names [string] [default: "%s__Output"] + --inputBranded Output property for branded type for "permissive" + types with fullName of the Message as its value [boolean] [default: false] + --outputBranded Output property for branded type for "restricted" + types with fullName of the Message as its value + [boolean] [default: false] + --targetFileExtension File extension for generated files. Defaults to .ts + [string] [default: ".ts"] + --importFileExtension File extension for import specifiers in generated + code. Defaults to none (omitted) [string] ``` ### Example Usage From c5b96a905438a05abc76dd026989bd81e6e83ff4 Mon Sep 17 00:00:00 2001 From: tenkirin <60653216+tenkirin@users.noreply.github.com> Date: Tue, 4 Mar 2025 07:21:07 +0900 Subject: [PATCH 3/4] refactor(proto-loader-gen-types): refactor for more consistent code style --- .../bin/proto-loader-gen-types.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 4dbc80de..0addb643 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -107,8 +107,8 @@ function getImportPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service): st return stripLeadingPeriod(to.fullName).replace(/\./g, '/'); } -function getPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service, extension: string = '.ts') { - return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + extension; +function getPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service, options: GeneratorOptions) { + return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + options.targetFileExtension; } function getPathToRoot(from: Protobuf.NamespaceBase) { @@ -155,7 +155,7 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv throw new Error('Invalid object passed to getImportLine'); } } - return `import type { ${importedTypes} } from '${filePath}${options.importFileExtension ?? ''}';` + return `import type { ${importedTypes} } from '${filePath}${options.importFileExtension}';` } function getChildMessagesAndEnums(namespace: Protobuf.NamespaceBase): (Protobuf.Type | Protobuf.Enum)[] { @@ -789,21 +789,21 @@ function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: G if (nested instanceof Protobuf.Type) { generateMessageInterfaces(fileFormatter, nested, options); if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested, options.targetFileExtension)} from file ${nested.filename}`); + console.log(`Writing ${options.outDir}/${getPath(nested, options)} from file ${nested.filename}`); } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options.targetFileExtension)}`, fileFormatter.getFullText())); + filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options)}`, fileFormatter.getFullText())); } else if (nested instanceof Protobuf.Enum) { generateEnumInterface(fileFormatter, nested, options); if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested, options.targetFileExtension)} from file ${nested.filename}`); + console.log(`Writing ${options.outDir}/${getPath(nested, options)} from file ${nested.filename}`); } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options.targetFileExtension)}`, fileFormatter.getFullText())); + filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options)}`, fileFormatter.getFullText())); } else if (nested instanceof Protobuf.Service) { generateServiceInterfaces(fileFormatter, nested, options); if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested, options.targetFileExtension)} from file ${nested.filename}`); + console.log(`Writing ${options.outDir}/${getPath(nested, options)} from file ${nested.filename}`); } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options.targetFileExtension)}`, fileFormatter.getFullText())); + filePromises.push(writeFile(`${options.outDir}/${getPath(nested, options)}`, fileFormatter.getFullText())); } else if (isNamespaceBase(nested)) { filePromises.push(...generateFilesForNamespace(nested, options)); } @@ -880,7 +880,7 @@ async function runScript() { .option('inputBranded', boolDefaultFalseOption) .option('outputBranded', boolDefaultFalseOption) .option('targetFileExtension', { string: true, default: '.ts' }) - .option('importFileExtension', { string: true }) + .option('importFileExtension', { string: true, default: '' }) .coerce('longs', value => { switch (value) { case 'String': return String; From 68bfa3b5e7d80446880bf7c8acdfbff1e1e4539a Mon Sep 17 00:00:00 2001 From: tenkirin <60653216+tenkirin@users.noreply.github.com> Date: Wed, 5 Mar 2025 07:21:07 +0900 Subject: [PATCH 4/4] chore(proto-loader-gen-types): update option descriptions for consistency --- packages/proto-loader/README.md | 4 ++-- packages/proto-loader/bin/proto-loader-gen-types.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 4c8d3ce6..935c100d 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -104,10 +104,10 @@ Options: --outputBranded Output property for branded type for "restricted" types with fullName of the Message as its value [boolean] [default: false] - --targetFileExtension File extension for generated files. Defaults to .ts + --targetFileExtension File extension for generated files. [string] [default: ".ts"] --importFileExtension File extension for import specifiers in generated - code. Defaults to none (omitted) [string] + code. [string] [default: ""] ``` ### Example Usage diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 0addb643..af01ecfc 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -920,8 +920,8 @@ async function runScript() { outputTemplate: 'Template for mapping output or "restricted" type names', inputBranded: 'Output property for branded type for "permissive" types with fullName of the Message as its value', outputBranded: 'Output property for branded type for "restricted" types with fullName of the Message as its value', - targetFileExtension: 'File extension for generated files. Defaults to .ts', - importFileExtension: 'File extension for import specifiers in generated code. Defaults to none (omitted)' + targetFileExtension: 'File extension for generated files.', + importFileExtension: 'File extension for import specifiers in generated code.' }).demandOption(['outDir']) .demand(1) .usage('$0 [options] filenames...')