UNPKG

pbjs2typescript

Version:

Typescript definition generator for Protocol Buffer definitions

209 lines (174 loc) 4.99 kB
"use strict"; /* eslint-disable no-console */ // Import in commondjs style const dust = require("dustjs-linkedin"); const fs = require("fs"); const _ = require("lodash"); const protobuf = require("protobufjs"); initializeDustJS(); // Load dust templates loadDustTemplate("module"); loadDustTemplate("object"); /** * @param {string} filePath path of *.json file or *.proto file * @param {(err, out: string) => void} callback */ module.exports = function (filePath, options, callback) { // Load the json file let model; try { model = protobuf.loadSync(filePath); model.resolveAll(); } catch (e) { callback(e, null); return; } // convert from new json(pbjs6) to old json(pbjs5) format // convertNamespace(model); const globalContext = { options, // context helper in context of Field classFieldType, // context helper in context of Field interfaceFieldType, // context helper in context of ReflectionObject isType, // context helper in context of ReflectionObject isEnum, // context helper in context of Enum enumValues, }; const context = dust.makeBase(globalContext).push(model); // Render the model dust.render("module", context, function (err, out) { callback(err, out); }); }; // --------------------------- functions ----------------------- function loadDustTemplate(name) { const template = fs.readFileSync(__dirname + "/../templates/" + name + ".dust", "UTF8"); const compiledTemplate = dust.compile(template, name); dust.loadSource(compiledTemplate); } function initializeDustJS() { // Keep line breaks // dust.optimizers.format = function (ctx, node) { // return node; // }; dust.config.whitespace = true; // strip first character if dot (.) dust.filters.toModuleName = function (value) { if (!value) { return ""; } return (value[0] === ".") ? value.slice(1) : value; }; // Create view filters dust.filters.firstLetterInUpperCase = function (value) { return value.charAt(0).toUpperCase() + value.slice(1); }; dust.filters.firstLetterInLowerCase = function (value) { return value.charAt(0).toLowerCase() + value.slice(1); }; dust.filters.camelCase = function (value) { return value.replace(/(_[a-zA-Z])/g, function (match) { return match[1].toUpperCase(); }); }; } function convertBasicType(typeName, options) { switch (typeName.toLowerCase()) { case "string": return "string"; case "bool": return "boolean"; case "bytes": return options.bytes; case "double": case "float": case "int32": case "int64": case "uint32": case "uint64": case "sint32": case "sint64": case "fixed32": case "fixed64": case "sfixed32": case "sfixed64": return "number"; // message or enum default: return ""; } } // helper /** * context helper: true if current context is Type * context: ReflectionObject */ function isType(chunk, context, bodies, params) { const reflectionObject = context.current(); return reflectionObject instanceof protobuf.Type; } /** * context helper: true if current context is Enum * context: ReflectionObject */ function isEnum(chunk, context, bodies, params) { const reflectionObject = context.current(); return reflectionObject instanceof protobuf.Enum; } /** * context helper: get value array of Enum (convert "values" object to array) * context: ReflectionObject * @returns {{ name: string, value: number }[]} */ function enumValues(chunk, context, bodies, params) { const values = context.get("values"); const valueArray = _.map(values, (value, key) => ({ name: key, value })); return valueArray; } /** * context helper: get field type name of interface * context: Field */ function classFieldType(chunk, context, bodies, params) { const type = context.get("type"); const options = context.get("options"); const result = convertBasicType(type, options); // if result is empty, it's Type or Enum return chunk.write(result || type); } /** * context helper: get field type name of interface * context: Field */ function interfaceFieldType(chunk, context, bodies, params) { const type = context.get("type"); const options = context.get("options"); const result = convertBasicType(type, options); if (result) { return chunk.write(result); } const resolvedType = context.get("resolvedType"); if (!resolvedType) { return chunk; } // filter enum type if (resolvedType instanceof protobuf.Enum) { return chunk.write(type); } // By default, it's a message "interface" identifier return chunk.write(messageNameToInterfaceName(type)); } /** e.g. Protocols.Message -> Protocols.IMessage */ function messageNameToInterfaceName(value) { const lastDotIndex = value.lastIndexOf("."); if (lastDotIndex === -1) { return "I" + value; } const result = value.slice(0, lastDotIndex) + ".I" + value.slice(lastDotIndex + 1); return result; }