@grpc/proto-loader
Advanced tools
Comparing version 0.6.0-pre1 to 0.6.0-pre10
@@ -23,6 +23,6 @@ #!/usr/bin/env node | ||
const path = require("path"); | ||
const mkdirp = require("mkdirp"); | ||
const Protobuf = require("protobufjs"); | ||
const yargs = require("yargs"); | ||
const camelCase = require("lodash.camelcase"); | ||
const util_1 = require("../src/util"); | ||
class TextFormatter { | ||
@@ -51,2 +51,14 @@ constructor() { | ||
} | ||
// GENERATOR UTILITY FUNCTIONS | ||
function compareName(x, y) { | ||
if (x.name < y.name) { | ||
return -1; | ||
} | ||
else if (x.name > y.name) { | ||
return 1; | ||
} | ||
else { | ||
return 0; | ||
} | ||
} | ||
function isNamespaceBase(obj) { | ||
@@ -62,5 +74,5 @@ return Array.isArray(obj.nestedArray); | ||
function getPath(to) { | ||
return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.d.ts'; | ||
return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.ts'; | ||
} | ||
function getRelativeImportPath(from, to) { | ||
function getPathToRoot(from) { | ||
const depth = stripLeadingPeriod(from.fullName).split('.').length - 1; | ||
@@ -71,4 +83,7 @@ let path = ''; | ||
} | ||
return path + getImportPath(to); | ||
return path; | ||
} | ||
function getRelativeImportPath(from, to) { | ||
return getPathToRoot(from) + getImportPath(to); | ||
} | ||
function getTypeInterfaceName(type) { | ||
@@ -80,7 +95,54 @@ return type.fullName.replace(/\./g, '_'); | ||
const typeInterfaceName = getTypeInterfaceName(dependency); | ||
const importedTypes = dependency instanceof Protobuf.Type ? `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output` : `${dependency.name} as ${typeInterfaceName}`; | ||
let importedTypes; | ||
if (dependency instanceof Protobuf.Type) { | ||
importedTypes = `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output`; | ||
} | ||
else if (dependency instanceof Protobuf.Enum) { | ||
importedTypes = `${dependency.name} as ${typeInterfaceName}`; | ||
} | ||
else if (dependency instanceof Protobuf.Service) { | ||
importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client`; | ||
} | ||
else { | ||
throw new Error('Invalid object passed to getImportLine'); | ||
} | ||
return `import { ${importedTypes} } from '${filePath}';`; | ||
} | ||
function generatePermissiveMessageInterface(formatter, messageType) { | ||
formatter.writeLine(`export interface ${messageType.name} {`); | ||
function getChildMessagesAndEnums(namespace) { | ||
const messageList = []; | ||
for (const nested of namespace.nestedArray) { | ||
if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { | ||
messageList.push(nested); | ||
} | ||
if (isNamespaceBase(nested)) { | ||
messageList.push(...getChildMessagesAndEnums(nested)); | ||
} | ||
} | ||
return messageList; | ||
} | ||
function formatComment(formatter, comment) { | ||
if (!comment) { | ||
return; | ||
} | ||
formatter.writeLine('/**'); | ||
for (const line of comment.split('\n')) { | ||
formatter.writeLine(` * ${line.replace(/\*\//g, '* /')}`); | ||
} | ||
formatter.writeLine(' */'); | ||
} | ||
// GENERATOR FUNCTIONS | ||
function generatePermissiveMessageInterface(formatter, messageType, options, nameOverride) { | ||
if (options.includeComments) { | ||
formatComment(formatter, messageType.comment); | ||
} | ||
if (messageType.fullName === '.google.protobuf.Any') { | ||
/* This describes the behavior of the Protobuf.js Any wrapper fromObject | ||
* replacement function */ | ||
formatter.writeLine('export type Any = AnyExtension | {'); | ||
formatter.writeLine(' type_url: string;'); | ||
formatter.writeLine(' value: Buffer | Uint8Array | string;'); | ||
formatter.writeLine('}'); | ||
return; | ||
} | ||
formatter.writeLine(`export interface ${nameOverride !== null && nameOverride !== void 0 ? nameOverride : messageType.name} {`); | ||
formatter.indent(); | ||
@@ -93,2 +155,4 @@ for (const field of messageType.fieldsArray) { | ||
case 'float': | ||
type = 'number | string'; | ||
break; | ||
case 'int32': | ||
@@ -115,3 +179,3 @@ case 'uint32': | ||
case 'bytes': | ||
type = 'Buffer | UInt8Array | String'; | ||
type = 'Buffer | Uint8Array | string'; | ||
break; | ||
@@ -130,7 +194,13 @@ default: | ||
} | ||
formatter.writeLine(`${field.name}?: (${type})${repeatedString};`); | ||
if (options.includeComments) { | ||
formatComment(formatter, field.comment); | ||
} | ||
formatter.writeLine(`'${field.name}'?: (${type})${repeatedString};`); | ||
} | ||
for (const oneof of messageType.oneofsArray) { | ||
const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); | ||
formatter.writeLine(`${oneof.name}?: ${typeString};`); | ||
if (options.includeComments) { | ||
formatComment(formatter, oneof.comment); | ||
} | ||
formatter.writeLine(`'${oneof.name}'?: ${typeString};`); | ||
} | ||
@@ -140,4 +210,26 @@ formatter.unindent(); | ||
} | ||
function generateRestrictedMessageInterface(formatter, messageType, options) { | ||
formatter.writeLine(`export interface ${messageType.name}__Output {`); | ||
function generateRestrictedMessageInterface(formatter, messageType, options, nameOverride) { | ||
if (options.includeComments) { | ||
formatComment(formatter, messageType.comment); | ||
} | ||
if (messageType.fullName === '.google.protobuf.Any' && options.json) { | ||
/* This describes the behavior of the Protobuf.js Any wrapper toObject | ||
* replacement function */ | ||
formatter.writeLine('export type Any__Output = AnyExtension | {'); | ||
formatter.writeLine(' type_url: string;'); | ||
let type; | ||
if (options.bytes === Array) { | ||
type = 'Uint8Array'; | ||
} | ||
else if (options.bytes === String) { | ||
type = 'string'; | ||
} | ||
else { | ||
type = 'Buffer'; | ||
} | ||
formatter.writeLine(` value: ${type};`); | ||
formatter.writeLine('}'); | ||
return; | ||
} | ||
formatter.writeLine(`export interface ${nameOverride !== null && nameOverride !== void 0 ? nameOverride : messageType.name}__Output {`); | ||
formatter.indent(); | ||
@@ -151,2 +243,9 @@ for (const field of messageType.fieldsArray) { | ||
case 'float': | ||
if (options.json) { | ||
type = 'number | string'; | ||
} | ||
else { | ||
type = 'number'; | ||
} | ||
break; | ||
case 'int32': | ||
@@ -185,3 +284,3 @@ case 'uint32': | ||
else if (options.bytes === String) { | ||
type = 'String'; | ||
type = 'string'; | ||
} | ||
@@ -214,3 +313,6 @@ else { | ||
const optionalString = fieldGuaranteed ? '' : '?'; | ||
formatter.writeLine(`${field.name}${optionalString}: (${type})${repeatedString};`); | ||
if (options.includeComments) { | ||
formatComment(formatter, field.comment); | ||
} | ||
formatter.writeLine(`'${field.name}'${optionalString}: (${type})${repeatedString};`); | ||
} | ||
@@ -220,3 +322,6 @@ if (options.oneofs) { | ||
const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); | ||
formatter.writeLine(`${oneof.name}: ${typeString};`); | ||
if (options.includeComments) { | ||
formatComment(formatter, oneof.comment); | ||
} | ||
formatter.writeLine(`'${oneof.name}': ${typeString};`); | ||
} | ||
@@ -230,4 +335,8 @@ } | ||
let seenDeps = new Set(); | ||
const childTypes = getChildMessagesAndEnums(messageType); | ||
formatter.writeLine(`// Original file: ${messageType.filename}`); | ||
formatter.writeLine(''); | ||
messageType.fieldsArray.sort((fieldA, fieldB) => fieldA.id - fieldB.id); | ||
for (const field of messageType.fieldsArray) { | ||
if (field.resolvedType) { | ||
if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { | ||
const dependency = field.resolvedType; | ||
@@ -244,14 +353,54 @@ if (seenDeps.has(dependency.fullName)) { | ||
} | ||
for (const childType of childTypes) { | ||
if (childType instanceof Protobuf.Type) { | ||
for (const field of childType.fieldsArray) { | ||
if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { | ||
const dependency = field.resolvedType; | ||
if (seenDeps.has(dependency.fullName)) { | ||
continue; | ||
} | ||
seenDeps.add(dependency.fullName); | ||
formatter.writeLine(getImportLine(dependency, messageType)); | ||
} | ||
if (field.type.indexOf('64') >= 0) { | ||
usesLong = true; | ||
} | ||
} | ||
} | ||
} | ||
if (usesLong) { | ||
formatter.writeLine("import { Long } from '@grpc/proto-loader';"); | ||
} | ||
if (messageType.fullName === '.google.protobuf.Any') { | ||
formatter.writeLine("import { AnyExtension } from '@grpc/proto-loader';"); | ||
} | ||
formatter.writeLine(''); | ||
generatePermissiveMessageInterface(formatter, messageType); | ||
for (const childType of childTypes.sort(compareName)) { | ||
const nameOverride = getTypeInterfaceName(childType); | ||
if (childType instanceof Protobuf.Type) { | ||
generatePermissiveMessageInterface(formatter, childType, options, nameOverride); | ||
formatter.writeLine(''); | ||
generateRestrictedMessageInterface(formatter, childType, options, nameOverride); | ||
} | ||
else { | ||
generateEnumInterface(formatter, childType, options, nameOverride); | ||
} | ||
formatter.writeLine(''); | ||
} | ||
generatePermissiveMessageInterface(formatter, messageType, options); | ||
formatter.writeLine(''); | ||
generateRestrictedMessageInterface(formatter, messageType, options); | ||
} | ||
function generateEnumInterface(formatter, enumType) { | ||
formatter.writeLine(`export enum ${enumType.name} {`); | ||
function generateEnumInterface(formatter, enumType, options, nameOverride) { | ||
formatter.writeLine(`// Original file: ${enumType.filename}`); | ||
formatter.writeLine(''); | ||
if (options.includeComments) { | ||
formatComment(formatter, enumType.comment); | ||
} | ||
formatter.writeLine(`export enum ${nameOverride !== null && nameOverride !== void 0 ? nameOverride : enumType.name} {`); | ||
formatter.indent(); | ||
for (const key of Object.keys(enumType.values)) { | ||
if (options.includeComments) { | ||
formatComment(formatter, enumType.comments[key]); | ||
} | ||
formatter.writeLine(`${key} = ${enumType.values[key]},`); | ||
@@ -262,37 +411,16 @@ } | ||
} | ||
function generateMessageAndEnumImports(formatter, namespace) { | ||
for (const nested of namespace.nestedArray) { | ||
if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { | ||
formatter.writeLine(getImportLine(nested)); | ||
} | ||
if (isNamespaceBase(nested)) { | ||
generateMessageAndEnumImports(formatter, nested); | ||
} | ||
function generateServiceClientInterface(formatter, serviceType, options) { | ||
if (options.includeComments) { | ||
formatComment(formatter, serviceType.comment); | ||
} | ||
} | ||
function generateMessageAndEnumExports(formatter, namespace, nameOverride) { | ||
formatter.writeLine(`export namespace ${nameOverride !== null && nameOverride !== void 0 ? nameOverride : namespace.name} {`); | ||
formatter.writeLine(`export interface ${serviceType.name}Client extends grpc.Client {`); | ||
formatter.indent(); | ||
for (const nested of namespace.nestedArray) { | ||
if (nested instanceof Protobuf.Enum || nested instanceof Protobuf.Type) { | ||
formatter.writeLine(`export type ${nested.name} = ${getTypeInterfaceName(nested)};`); | ||
if (nested instanceof Protobuf.Type) { | ||
formatter.writeLine(`export type ${nested.name}__Output = ${getTypeInterfaceName(nested)}__Output;`); | ||
} | ||
} | ||
else if (isNamespaceBase(nested)) { | ||
generateMessageAndEnumExports(formatter, nested); | ||
} | ||
} | ||
formatter.unindent(); | ||
formatter.writeLine('}'); | ||
} | ||
function generateServiceClientInterface(formatter, serviceType) { | ||
formatter.writeLine(`interface ${serviceType.name}Client extends grpc.Client {`); | ||
formatter.indent(); | ||
for (const methodName of Object.keys(serviceType.methods)) { | ||
for (const methodName of Object.keys(serviceType.methods).sort()) { | ||
const method = serviceType.methods[methodName]; | ||
for (const name of [methodName, camelCase(methodName)]) { | ||
const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType.fullName); | ||
const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType.fullName) + '__Output'; | ||
if (options.includeComments) { | ||
formatComment(formatter, method.comment); | ||
} | ||
const requestType = getTypeInterfaceName(method.resolvedRequestType); | ||
const responseType = getTypeInterfaceName(method.resolvedResponseType) + '__Output'; | ||
const callbackType = `(error?: grpc.ServiceError, result?: ${responseType}) => void`; | ||
@@ -337,42 +465,15 @@ if (method.requestStream) { | ||
} | ||
function generateAllServiceClientInterfaces(formatter, namespace) { | ||
for (const nested of namespace.nestedArray) { | ||
if (nested instanceof Protobuf.Service) { | ||
generateServiceClientInterface(formatter, nested); | ||
} | ||
else if (isNamespaceBase(nested)) { | ||
generateAllServiceClientInterfaces(formatter, nested); | ||
} | ||
function generateServiceHandlerInterface(formatter, serviceType, options) { | ||
if (options.includeComments) { | ||
formatComment(formatter, serviceType.comment); | ||
} | ||
} | ||
function generateSingleLoadedDefinitionType(formatter, nested) { | ||
if (nested instanceof Protobuf.Service) { | ||
formatter.writeLine(`${nested.name}: SubtypeConstructor<typeof grpc.Client, ${nested.name}Client> & { service: ServiceDefinition }`); | ||
} | ||
else if (nested instanceof Protobuf.Enum) { | ||
formatter.writeLine(`${nested.name}: EnumTypeDefinition`); | ||
} | ||
else if (nested instanceof Protobuf.Type) { | ||
formatter.writeLine(`${nested.name}: MessageTypeDefinition`); | ||
} | ||
else if (isNamespaceBase(nested)) { | ||
generateLoadedDefinitionTypes(formatter, nested); | ||
} | ||
} | ||
function generateLoadedDefinitionTypes(formatter, namespace) { | ||
formatter.writeLine(`${namespace.name}: {`); | ||
formatter.writeLine(`export interface ${serviceType.name}Handlers {`); | ||
formatter.indent(); | ||
for (const nested of namespace.nestedArray) { | ||
generateSingleLoadedDefinitionType(formatter, nested); | ||
} | ||
formatter.unindent(); | ||
formatter.writeLine('}'); | ||
} | ||
function generateServiceHandlerInterface(formatter, serviceType) { | ||
formatter.writeLine(`export interface ${serviceType.name} {`); | ||
formatter.indent(); | ||
for (const methodName of Object.keys(serviceType.methods)) { | ||
for (const methodName of Object.keys(serviceType.methods).sort()) { | ||
const method = serviceType.methods[methodName]; | ||
const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType.fullName) + '__Output'; | ||
const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType.fullName); | ||
if (options.includeComments) { | ||
formatComment(formatter, method.comment); | ||
} | ||
const requestType = getTypeInterfaceName(method.resolvedRequestType); | ||
const responseType = getTypeInterfaceName(method.resolvedResponseType) + '__Output'; | ||
if (method.requestStream) { | ||
@@ -385,3 +486,3 @@ if (method.responseStream) { | ||
// Client streaming | ||
formatter.writeLine(`${methodName}(call: grpc.ServerReadableStream<${requestType}>, callback: grpc.SendUnaryData<${responseType}>): void;`); | ||
formatter.writeLine(`${methodName}(call: grpc.ServerReadableStream<${requestType}>, callback: grpc.sendUnaryData<${responseType}>): void;`); | ||
} | ||
@@ -392,7 +493,7 @@ } | ||
// Server streaming | ||
formatter.writeLine(`${methodName}(call: grpc.ServerWriteableStream<${requestType}, ${responseType}>): void;`); | ||
formatter.writeLine(`${methodName}(call: grpc.ServerWritableStream<${requestType}, ${responseType}>): void;`); | ||
} | ||
else { | ||
// Unary | ||
formatter.writeLine(`${methodName}(call: grpc.ServerUnaryCall<${requestType}>, callback: grpc.SendUnaryData<${responseType}>): void;`); | ||
formatter.writeLine(`${methodName}(call: grpc.ServerUnaryCall<${requestType}, ${responseType}>, callback: grpc.sendUnaryData<${responseType}>): void;`); | ||
} | ||
@@ -405,29 +506,65 @@ } | ||
} | ||
function generateAllServiceHandlerInterfaces(formatter, namespace, nameOverride) { | ||
formatter.writeLine(`export namespace ${nameOverride !== null && nameOverride !== void 0 ? nameOverride : namespace.name} {`); | ||
formatter.indent(); | ||
for (const nested of namespace.nestedArray) { | ||
function generateServiceInterfaces(formatter, serviceType, options) { | ||
formatter.writeLine(`// Original file: ${serviceType.filename}`); | ||
formatter.writeLine(''); | ||
const grpcImportPath = options.grpcLib.startsWith('.') ? getPathToRoot(serviceType) + options.grpcLib : options.grpcLib; | ||
formatter.writeLine(`import * as grpc from '${grpcImportPath}'`); | ||
const dependencies = new Set(); | ||
for (const method of serviceType.methodsArray) { | ||
dependencies.add(method.resolvedRequestType); | ||
dependencies.add(method.resolvedResponseType); | ||
} | ||
for (const dep of Array.from(dependencies.values()).sort(compareName)) { | ||
formatter.writeLine(getImportLine(dep, serviceType)); | ||
} | ||
formatter.writeLine(''); | ||
generateServiceClientInterface(formatter, serviceType, options); | ||
formatter.writeLine(''); | ||
generateServiceHandlerInterface(formatter, serviceType, options); | ||
} | ||
function generateServiceImports(formatter, namespace, options) { | ||
for (const nested of namespace.nestedArray.sort(compareName)) { | ||
if (nested instanceof Protobuf.Service) { | ||
generateServiceHandlerInterface(formatter, nested); | ||
formatter.writeLine(getImportLine(nested)); | ||
} | ||
else if (isNamespaceBase(nested)) { | ||
generateAllServiceHandlerInterfaces(formatter, nested); | ||
else if (isNamespaceBase(nested) && !(nested instanceof Protobuf.Type) && !(nested instanceof Protobuf.Enum)) { | ||
generateServiceImports(formatter, nested, options); | ||
} | ||
} | ||
} | ||
function generateSingleLoadedDefinitionType(formatter, nested, options) { | ||
if (nested instanceof Protobuf.Service) { | ||
if (options.includeComments) { | ||
formatComment(formatter, nested.comment); | ||
} | ||
formatter.writeLine(`${nested.name}: SubtypeConstructor<typeof grpc.Client, ${getTypeInterfaceName(nested)}Client> & { service: ServiceDefinition }`); | ||
} | ||
else if (nested instanceof Protobuf.Enum) { | ||
formatter.writeLine(`${nested.name}: EnumTypeDefinition`); | ||
} | ||
else if (nested instanceof Protobuf.Type) { | ||
formatter.writeLine(`${nested.name}: MessageTypeDefinition`); | ||
} | ||
else if (isNamespaceBase(nested)) { | ||
generateLoadedDefinitionTypes(formatter, nested, options); | ||
} | ||
} | ||
function generateLoadedDefinitionTypes(formatter, namespace, options) { | ||
formatter.writeLine(`${namespace.name}: {`); | ||
formatter.indent(); | ||
for (const nested of namespace.nestedArray.sort(compareName)) { | ||
generateSingleLoadedDefinitionType(formatter, nested, options); | ||
} | ||
formatter.unindent(); | ||
formatter.writeLine('}'); | ||
} | ||
function generateMasterFile(formatter, root, options) { | ||
function generateRootFile(formatter, root, options) { | ||
formatter.writeLine(`import * as grpc from '${options.grpcLib}';`); | ||
formatter.writeLine("import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); | ||
formatter.writeLine(''); | ||
generateMessageAndEnumImports(formatter, root); | ||
generateServiceImports(formatter, root, options); | ||
formatter.writeLine(''); | ||
generateMessageAndEnumExports(formatter, root, 'messages'); | ||
formatter.writeLine(''); | ||
generateAllServiceClientInterfaces(formatter, root); | ||
formatter.writeLine(''); | ||
formatter.writeLine('type ConstructorArguments<Constructor> = Constructor extends new (...args: infer Args) => any ? Args: never;'); | ||
formatter.writeLine('type SubtypeConstructor<Constructor, Subtype> = {'); | ||
formatter.writeLine(' new(args: ConstructorArguments<Constructor>): Subtype;'); | ||
formatter.writeLine(' new(...args: ConstructorArguments<Constructor>): Subtype;'); | ||
formatter.writeLine('}'); | ||
@@ -438,3 +575,3 @@ formatter.writeLine(''); | ||
for (const nested of root.nestedArray) { | ||
generateSingleLoadedDefinitionType(formatter, nested); | ||
generateSingleLoadedDefinitionType(formatter, nested, options); | ||
} | ||
@@ -444,6 +581,6 @@ formatter.unindent(); | ||
formatter.writeLine(''); | ||
generateAllServiceHandlerInterfaces(formatter, root, 'ServiceHandlers'); | ||
} | ||
function writeFile(filename, contents) { | ||
return mkdirp(path.dirname(filename)).then(() => fs.promises.writeFile(filename, contents)); | ||
async function writeFile(filename, contents) { | ||
await fs.promises.mkdir(path.dirname(filename), { recursive: true }); | ||
return fs.promises.writeFile(filename, contents); | ||
} | ||
@@ -456,11 +593,22 @@ function generateFilesForNamespace(namespace, options) { | ||
generateMessageInterfaces(fileFormatter, nested, options); | ||
console.log(`Writing ${options.outDir}/${getPath(nested)}`); | ||
if (options.verbose) { | ||
console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); | ||
} | ||
filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); | ||
} | ||
else if (nested instanceof Protobuf.Enum) { | ||
generateEnumInterface(fileFormatter, nested); | ||
console.log(`Writing ${options.outDir}/${getPath(nested)}`); | ||
generateEnumInterface(fileFormatter, nested, options); | ||
if (options.verbose) { | ||
console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); | ||
} | ||
filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); | ||
} | ||
if (isNamespaceBase(nested)) { | ||
else if (nested instanceof Protobuf.Service) { | ||
generateServiceInterfaces(fileFormatter, nested, options); | ||
if (options.verbose) { | ||
console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); | ||
} | ||
filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); | ||
} | ||
else if (isNamespaceBase(nested)) { | ||
filePromises.push(...generateFilesForNamespace(nested, options)); | ||
@@ -474,4 +622,6 @@ } | ||
const masterFileFormatter = new TextFormatter(); | ||
generateMasterFile(masterFileFormatter, root, options); | ||
console.log(`Writing ${options.outDir}/${masterFileName}`); | ||
generateRootFile(masterFileFormatter, root, options); | ||
if (options.verbose) { | ||
console.log(`Writing ${options.outDir}/${masterFileName}`); | ||
} | ||
filePromises.push(writeFile(`${options.outDir}/${masterFileName}`, masterFileFormatter.getFullText())); | ||
@@ -481,37 +631,7 @@ filePromises.push(...generateFilesForNamespace(root, options)); | ||
} | ||
function addIncludePathResolver(root, includePaths) { | ||
const originalResolvePath = root.resolvePath; | ||
root.resolvePath = (origin, target) => { | ||
if (path.isAbsolute(target)) { | ||
return target; | ||
} | ||
for (const directory of includePaths) { | ||
const fullPath = path.join(directory, target); | ||
try { | ||
fs.accessSync(fullPath, fs.constants.R_OK); | ||
return fullPath; | ||
} | ||
catch (err) { | ||
continue; | ||
} | ||
} | ||
process.emitWarning(`${target} not found in any of the include paths ${includePaths}`); | ||
return originalResolvePath(origin, target); | ||
}; | ||
} | ||
async function writeAllFiles(protoFiles, options) { | ||
await mkdirp(options.outDir); | ||
await fs.promises.mkdir(options.outDir, { recursive: true }); | ||
for (const filename of protoFiles) { | ||
console.log(`Processing ${filename}`); | ||
const root = new Protobuf.Root(); | ||
options = options || {}; | ||
if (!!options.includeDirs) { | ||
if (!Array.isArray(options.includeDirs)) { | ||
throw new Error('The includeDirs option must be an array'); | ||
} | ||
addIncludePathResolver(root, options.includeDirs); | ||
} | ||
const loadedRoot = await root.load(filename, options); | ||
root.resolveAll(); | ||
writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.d.ts'), options); | ||
const loadedRoot = await util_1.loadProtosWithOptions(filename, options); | ||
writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.ts'), options); | ||
} | ||
@@ -524,3 +644,3 @@ } | ||
.array('includeDirs') | ||
.boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs']) | ||
.boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'generateComments']) | ||
// .choices('longs', ['String', 'Number']) | ||
@@ -558,8 +678,9 @@ // .choices('enums', ['String']) | ||
includeDirs: 'I', | ||
outDir: 'O' | ||
outDir: 'O', | ||
verbose: 'v' | ||
}).describe({ | ||
keepCase: 'Preserve the case of field names', | ||
longs: 'The type that should be used to output 64 bit integer values', | ||
enums: 'The type that should be used to output enum fields', | ||
bytes: 'The type that should be used to output bytes fields', | ||
longs: 'The type that should be used to output 64 bit integer values. Can be String, Number', | ||
enums: 'The type that should be used to output enum fields. Can be String', | ||
bytes: 'The type that should be used to output bytes fields. Can be String, Array', | ||
defaults: 'Output default values for omitted fields', | ||
@@ -569,2 +690,3 @@ arrays: 'Output default values for omitted repeated fields even if --defaults is not set', | ||
oneofs: 'Output virtual oneof fields set to the present field\'s name', | ||
json: 'Represent Infinity and NaN as strings in float fields. Also decode google.protobuf.Any automatically', | ||
includeDirs: 'Directories to search for included files', | ||
@@ -578,5 +700,10 @@ outDir: 'Directory in which to output files', | ||
.argv; | ||
console.log(argv); | ||
writeAllFiles(argv._, argv).then(() => { | ||
console.log('Success'); | ||
if (argv.verbose) { | ||
console.log('Parsed arguments:', argv); | ||
} | ||
util_1.addCommonProtos(); | ||
writeAllFiles(argv._, Object.assign(Object.assign({}, argv), { alternateCommentMode: true })).then(() => { | ||
if (argv.verbose) { | ||
console.log('Success'); | ||
} | ||
}, (error) => { | ||
@@ -583,0 +710,0 @@ throw error; |
@@ -0,5 +1,52 @@ | ||
/** | ||
* @license | ||
* Copyright 2018 gRPC authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
/// <reference types="node" /> | ||
import * as Protobuf from 'protobufjs'; | ||
import * as descriptor from 'protobufjs/ext/descriptor'; | ||
import { Options } from './util'; | ||
export { Long } from 'long'; | ||
/** | ||
* This type exists for use with code generated by the proto-loader-gen-types | ||
* tool. This type should be used with another interface, e.g. | ||
* MessageType & AnyExtension for an object that is converted to or from a | ||
* google.protobuf.Any message. | ||
* For example, when processing an Any message: | ||
* | ||
* ```ts | ||
* if (isAnyExtension(message)) { | ||
* switch (message['@type']) { | ||
* case TYPE1_URL: | ||
* handleType1(message as AnyExtension & Type1); | ||
* break; | ||
* case TYPE2_URL: | ||
* handleType2(message as AnyExtension & Type2); | ||
* break; | ||
* // ... | ||
* } | ||
* } | ||
* ``` | ||
*/ | ||
export interface AnyExtension { | ||
/** | ||
* The fully qualified name of the message type that this object represents, | ||
* possibly including a URL prefix. | ||
*/ | ||
'@type': string; | ||
} | ||
export declare function isAnyExtension(obj: object): obj is AnyExtension; | ||
declare module 'protobufjs' { | ||
@@ -52,5 +99,3 @@ interface Type { | ||
} | ||
export declare type Options = Protobuf.IParseOptions & Protobuf.IConversionOptions & { | ||
includeDirs?: string[]; | ||
}; | ||
export { Options }; | ||
/** | ||
@@ -78,2 +123,4 @@ * Load a .proto file with the specified options. | ||
* name | ||
* @param options.json Represent Infinity and NaN as strings in float fields, | ||
* and automatically decode google.protobuf.Any values. | ||
* @param options.includeDirs Paths to search for imported `.proto` files. | ||
@@ -80,0 +127,0 @@ */ |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
@@ -20,7 +19,11 @@ * @license | ||
*/ | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const camelCase = require("lodash.camelcase"); | ||
const Protobuf = require("protobufjs"); | ||
const descriptor = require("protobufjs/ext/descriptor"); | ||
const camelCase = require("lodash.camelcase"); | ||
const util_1 = require("./util"); | ||
function isAnyExtension(obj) { | ||
return ('@type' in obj) && (typeof obj['@type'] === 'string'); | ||
} | ||
exports.isAnyExtension = isAnyExtension; | ||
const descriptorOptions = { | ||
@@ -150,22 +153,2 @@ longs: String, | ||
} | ||
function addIncludePathResolver(root, includePaths) { | ||
const originalResolvePath = root.resolvePath; | ||
root.resolvePath = (origin, target) => { | ||
if (path.isAbsolute(target)) { | ||
return target; | ||
} | ||
for (const directory of includePaths) { | ||
const fullPath = path.join(directory, target); | ||
try { | ||
fs.accessSync(fullPath, fs.constants.R_OK); | ||
return fullPath; | ||
} | ||
catch (err) { | ||
continue; | ||
} | ||
} | ||
process.emitWarning(`${target} not found in any of the include paths ${includePaths}`); | ||
return originalResolvePath(origin, target); | ||
}; | ||
} | ||
/** | ||
@@ -193,16 +176,9 @@ * Load a .proto file with the specified options. | ||
* name | ||
* @param options.json Represent Infinity and NaN as strings in float fields, | ||
* and automatically decode google.protobuf.Any values. | ||
* @param options.includeDirs Paths to search for imported `.proto` files. | ||
*/ | ||
function load(filename, options) { | ||
const root = new Protobuf.Root(); | ||
options = options || {}; | ||
if (!!options.includeDirs) { | ||
if (!Array.isArray(options.includeDirs)) { | ||
return Promise.reject(new Error('The includeDirs option must be an array')); | ||
} | ||
addIncludePathResolver(root, options.includeDirs); | ||
} | ||
return root.load(filename, options).then(loadedRoot => { | ||
loadedRoot.resolveAll(); | ||
return createPackageDefinition(root, options); | ||
return util_1.loadProtosWithOptions(filename, options).then(loadedRoot => { | ||
return createPackageDefinition(loadedRoot, options); | ||
}); | ||
@@ -212,27 +188,7 @@ } | ||
function loadSync(filename, options) { | ||
const root = new Protobuf.Root(); | ||
options = options || {}; | ||
if (!!options.includeDirs) { | ||
if (!Array.isArray(options.includeDirs)) { | ||
throw new Error('The includeDirs option must be an array'); | ||
} | ||
addIncludePathResolver(root, options.includeDirs); | ||
} | ||
const loadedRoot = root.loadSync(filename, options); | ||
loadedRoot.resolveAll(); | ||
return createPackageDefinition(root, options); | ||
const loadedRoot = util_1.loadProtosWithOptionsSync(filename, options); | ||
return createPackageDefinition(loadedRoot, options); | ||
} | ||
exports.loadSync = loadSync; | ||
// Load Google's well-known proto files that aren't exposed by Protobuf.js. | ||
{ | ||
// Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp, | ||
// and wrappers. compiler/plugin is excluded in Protobuf.js and here. | ||
const wellKnownProtos = ['api', 'descriptor', 'source_context', 'type']; | ||
const sourceDir = path.join(path.dirname(require.resolve('protobufjs')), 'google', 'protobuf'); | ||
for (const proto of wellKnownProtos) { | ||
const file = path.join(sourceDir, `${proto}.proto`); | ||
const descriptor = Protobuf.loadSync(file).toJSON(); | ||
Protobuf.common(proto, descriptor.nested.google.nested); | ||
} | ||
} | ||
util_1.addCommonProtos(); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@grpc/proto-loader", | ||
"version": "0.6.0-pre1", | ||
"version": "0.6.0-pre10", | ||
"author": "Google Inc.", | ||
@@ -49,4 +49,3 @@ "contributors": [ | ||
"long": "^4.0.0", | ||
"mkdirp": "^1.0.4", | ||
"protobufjs": "^6.8.6", | ||
"protobufjs": "^6.9.0", | ||
"yargs": "^15.3.1" | ||
@@ -53,0 +52,0 @@ }, |
@@ -41,2 +41,3 @@ # gRPC Protobuf Loader | ||
| `oneofs` | `true` or `false` | Set virtual oneof properties to the present field's name. Defaults to `false`. | ||
| `json` | `true` or `false` | Represent `Infinity` and `NaN` as strings in `float` fields, and automatically decode `google.protobuf.Any` values. Defaults to `false` | ||
| `includeDirs` | An array of strings | A list of search paths for imported `.proto` files. | ||
@@ -43,0 +44,0 @@ |
61403
5
9
1120
55
- Removedmkdirp@^1.0.4
- Removedmkdirp@1.0.4(transitive)
Updatedprotobufjs@^6.9.0