var onimport = function (i, result) { result.push('import "' + i + '";', '') return result } var onfield = function (f, result) { var prefix = f.repeated ? 'repeated' : f.required ? 'required' : 'optional' if (f.type === 'map') prefix = 'map<' + f.map.from + ',' + f.map.to + '>' if (f.oneof) prefix = '' var opts = Object.keys(f.options || {}).map(function (key) { return key + ' = ' + f.options[key] }).join(',') if (opts) opts = ' [' + opts + ']' result.push((prefix ? prefix + ' ' : '') + (f.map === 'map' ? '' : f.type + ' ') + f.name + ' = ' + f.tag + opts + ';') return result } var onmessage = function (m, result) { result.push('message ' + m.name + ' {') if (!m.options) m.options = {} onoption(m.options, result) if (!m.enums) m.enums = [] m.enums.forEach(function (e) { result.push(onenum(e, [])) }) if (!m.messages) m.messages = [] m.messages.forEach(function (m) { result.push(onmessage(m, [])) }) var oneofs = {} if (!m.fields) m.fields = [] m.fields.forEach(function (f) { if (f.oneof) { if (!oneofs[f.oneof]) oneofs[f.oneof] = [] oneofs[f.oneof].push(onfield(f, [])) } else { result.push(onfield(f, [])) } }) Object.keys(oneofs).forEach(function (n) { oneofs[n].unshift('oneof ' + n + ' {') oneofs[n].push('}') result.push(oneofs[n]) }) result.push('}', '') return result } var onenum = function (e, result) { result.push('enum ' + e.name + ' {') if (!e.options) e.options = {} var options = onoption(e.options, []) if (options.length > 1) { result.push(options.slice(0, -1)) } Object.keys(e.values).map(function (v) { var val = onenumvalue(e.values[v]) result.push([v + ' = ' + val + ';']) }) result.push('}', '') return result } var onenumvalue = function (v, result) { var opts = Object.keys(v.options || {}).map(function (key) { return key + ' = ' + v.options[key] }).join(',') if (opts) opts = ' [' + opts + ']' var val = v.value + opts return val } var onoption = function (o, result) { var keys = Object.keys(o) keys.forEach(function (option) { var v = o[option] if (~option.indexOf('.')) option = '(' + option + ')' var type = typeof v if (type === 'object') { v = onoptionMap(v, []) if (v.length) result.push('option ' + option + ' = {', v, '};') } else { if (type === 'string' && option !== 'optimize_for') v = '"' + v + '"' result.push('option ' + option + ' = ' + v + ';') } }) if (keys.length > 0) { result.push('') } return result } var onoptionMap = function (o, result) { var keys = Object.keys(o) keys.forEach(function (k) { var v = o[k] var type = typeof v if (type === 'object') { if (Array.isArray(v)) { v.forEach(function (v) { v = onoptionMap(v, []) if (v.length) result.push(k + ' {', v, '}') }) } else { v = onoptionMap(v, []) if (v.length) result.push(k + ' {', v, '}') } } else { if (type === 'string') v = '"' + v + '"' result.push(k + ': ' + v) } }) return result } var onservices = function (s, result) { result.push('service ' + s.name + ' {') if (!s.options) s.options = {} onoption(s.options, result) if (!s.methods) s.methods = [] s.methods.forEach(function (m) { result.push(onrpc(m, [])) }) result.push('}', '') return result } var onrpc = function (rpc, result) { var def = 'rpc ' + rpc.name + '(' if (rpc.client_streaming) def += 'stream ' def += rpc.input_type + ') returns (' if (rpc.server_streaming) def += 'stream ' def += rpc.output_type + ')' if (!rpc.options) rpc.options = {} var options = onoption(rpc.options, []) if (options.length > 1) { result.push(def + ' {', options.slice(0, -1), '}') } else { result.push(def + ';') } return result } var indent = function (lvl) { return function (line) { if (Array.isArray(line)) return line.map(indent(lvl + ' ')).join('\n') return lvl + line } } module.exports = function (schema) { var result = [] result.push('syntax = "proto' + schema.syntax + '";', '') if (schema.package) result.push('package ' + schema.package + ';', '') if (schema.imports) { schema.imports.forEach(function (i) { onimport(i, result) }) } if (!schema.options) schema.options = {} onoption(schema.options, result) if (!schema.enums) schema.enums = [] schema.enums.forEach(function (e) { onenum(e, result) }) if (!schema.messages) schema.messages = [] schema.messages.forEach(function (m) { onmessage(m, result) }) if (schema.services) { schema.services.forEach(function (s) { onservices(s, result) }) } return result.map(indent('')).join('\n') }