diff --git a/lib/Project.js b/lib/Project.js index b0c4cf5..0736aed 100644 --- a/lib/Project.js +++ b/lib/Project.js @@ -128,10 +128,11 @@ Project.prototype.setOutDir = function (outDir) { * @param {string} protoFile The proto file to compile, all imports will be followed. * @param {string} templateName The Soy template name to use when compiling. * @param {string=} opt_suffix Optional suffix for generated files. + * @param {boolean=} opt_skipImports If true, dont' follow imports. * @return {Project} */ -Project.prototype.addJob = function (protoFile, templateName, opt_suffix) { - this.addProto(protoFile, true) +Project.prototype.addJob = function (protoFile, templateName, opt_suffix, opt_skipImports) { + this.addProto(protoFile, !opt_skipImports) this._compileJobs.push({ proto: this._resolve(protoFile), template: templateName, diff --git a/lib/Token.js b/lib/Token.js index 65f3b78..f7fcd2a 100644 --- a/lib/Token.js +++ b/lib/Token.js @@ -37,7 +37,9 @@ Token.Type = { END_BLOCK: 9, START_OPTION: 10, END_OPTION: 11, - NUMBER: 12 + NUMBER: 12, + START_PAREN: 13, + END_PAREN: 14 } @@ -59,6 +61,8 @@ Token.toErrorString = function (value) { case Token.Type.END_BLOCK: return '} (close block)' case Token.Type.START_OPTION: return '[ (open option)' case Token.Type.END_OPTION: return '] (close option)' + case Token.Type.START_PAREN: return '( (open parenthesis)' + case Token.Type.END_PAREN: return ') (close parenthesis)' case Token.Type.NUMBER: return 'number' default: return 'Token Value=' + value diff --git a/lib/descriptors/ProtoDescriptor.js b/lib/descriptors/ProtoDescriptor.js index 41cd178..4534253 100644 --- a/lib/descriptors/ProtoDescriptor.js +++ b/lib/descriptors/ProtoDescriptor.js @@ -98,7 +98,7 @@ ProtoDescriptor.prototype.getOptionKeys = function () { ProtoDescriptor.prototype.addImportName = function (fileName) { - this._importNames.push(path.resolve(path.dirname(this._filePath), fileName)) + this._importNames.push(path.resolve(fileName)) return this } diff --git a/lib/parser.js b/lib/parser.js index 9ae46cc..67dd4e2 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -73,9 +73,21 @@ module.exports = function parser(identifier, string) { expect(Token.Type.TERMINATOR) } - // Parses a file level option: option optionName = "optionValue"; + // Parses a file level option: + // option optionName = "optionValue"; + // option (optionName) = "optionValue"; function parseOption(parent) { + var hasParens = false + if (peek().type == Token.Type.START_PAREN) { + expect(Token.Type.START_PAREN) + hasParens = true + } + var key = expect(Token.Type.WORD) + if (hasParens) { + expect(Token.Type.END_PAREN) + } + var equals = expect(Token.Type.OPERATOR) var value = expect(Token.Type.STRING) expect(Token.Type.TERMINATOR) @@ -185,10 +197,23 @@ module.exports = function parser(identifier, string) { }) } - // Parses field options: [ name1 = value1, name2 = value2 ] + // Parses field options: [ name1 = value1, name2 = value2, (name3) = value3 ] function parseFieldOptions(parent) { parseBlock(function (token) { + var hasParens = false + var nameToken = token + if (token.type == Token.Type.START_PAREN) { + token = expect(Token.Type.WORD) + hasParens = true + } else if (token.type != Token.Type.WORD) { + throw new ParseError(identifier, token, 'expected ' + Token.toErrorString(Token.Type.WORD) + '.') + } + var name = token.content + if (hasParens) { + expect(Token.Type.END_PAREN) + } + expect(Token.Type.OPERATOR) var value = expect([Token.Type.WORD, Token.Type.STRING, Token.Type.NUMBER]).content parent.addOption(name, value) diff --git a/lib/tokenize.js b/lib/tokenize.js index 5d0fef5..48791dd 100644 --- a/lib/tokenize.js +++ b/lib/tokenize.js @@ -38,6 +38,8 @@ module.exports = function tokenize(string, fileName) { else if (lookingAt('}')) consumeChar(Token.Type.END_BLOCK) else if (lookingAt('[')) consumeChar(Token.Type.START_OPTION) else if (lookingAt(']')) consumeChar(Token.Type.END_OPTION) + else if (lookingAt('(')) consumeChar(Token.Type.START_PAREN) + else if (lookingAt(')')) consumeChar(Token.Type.END_PAREN) else if (lookingAtNumberFirstCharacter()) consumeNumber() else if (lookingAtWordFirstCharacter()) consumeWord() else if (lookingAtRe(/\s/)) nextChar() diff --git a/package.json b/package.json index cc306c8..8b2c4b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pbnj", - "version": "0.1.2", + "version": "0.2.0", "keywords": ["protocol", "buffer", "proto", "protobuf", "parser", "codegen"], "description": "JavaScript protocol buffer schema parser and template based code generator", "homepage": "https://github.com/dpup/pbnj", @@ -24,7 +24,7 @@ } ], "main": "lib/pbnj.js", "scripts": { - "test": "nodeunit ./tests/" + "test": "nodeunit ./tests/ && tests/protoc_test.sh" }, "dependencies": { "mkdirp": "0.3.5", diff --git a/tests/parsing_test.js b/tests/parsing_test.js index dac2b88..79ac3c9 100644 --- a/tests/parsing_test.js +++ b/tests/parsing_test.js @@ -21,7 +21,7 @@ exports.testKitchenSinkParsing = function (test) { // Test imports. test.equal(proto.getImportNames().length, 1) - test.equal(proto.getImportNames()[0], path.join(process.cwd(), 'some-other-file.proto')) + test.equal(proto.getImportNames()[0], path.join(process.cwd(), 'tests/protos/options.proto')) // Test proto level options. test.equal(proto.getOptionKeys().length, 2) diff --git a/tests/protoc_test.sh b/tests/protoc_test.sh new file mode 100755 index 0000000..8271e2c --- /dev/null +++ b/tests/protoc_test.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +cd `dirname $0`/.. +mkdir tmp_protoc_test +protoc tests/protos/*.proto --proto_path=.:/usr/local/include --cpp_out=tmp_protoc_test +RESULT=$? +rm -fR tmp_protoc_test +exit $RESULT diff --git a/tests/protos/kitchen-sink.proto b/tests/protos/kitchen-sink.proto index bafd5a1..be471cc 100644 --- a/tests/protos/kitchen-sink.proto +++ b/tests/protos/kitchen-sink.proto @@ -6,10 +6,10 @@ package some_package; -import "some-other-file.proto"; +import "tests/protos/options.proto"; -option file_level_option = "string value"; -option another_option = "Just \"testing\" that strings parse."; +option (file_level_option) = "string value"; +option (another_option) = "Just \"testing\" that strings parse."; message ThisIsTheKitchenSink { @@ -25,8 +25,8 @@ message ThisIsTheKitchenSink { message AnotherMessage { - option message_level_option = "XYZ"; - required int64 id = 1000 [option=1, something_else="foobar"]; + option (message_level_option) = "XYZ"; + required int64 id = 1000 [(option)=1, (something_else)="foobar"]; optional string x = 1; optional string y = 2; optional string z = 3; message MessagesWithinMessages { diff --git a/tests/protos/options.proto b/tests/protos/options.proto new file mode 100644 index 0000000..78988a5 --- /dev/null +++ b/tests/protos/options.proto @@ -0,0 +1,17 @@ +// Copyright 2015. A Medium Corporation. + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.FieldOptions { + optional int32 option = 20150103; + optional string something_else = 20150104; +} + +extend google.protobuf.MessageOptions { + optional string message_level_option = 20150102; +} + +extend google.protobuf.FileOptions { + optional string file_level_option = 20150101; + optional string another_option = 20150105; +} diff --git a/tests/protos/person.proto b/tests/protos/person.proto index 4612c74..5cbd209 100644 --- a/tests/protos/person.proto +++ b/tests/protos/person.proto @@ -2,7 +2,7 @@ * Proto definition for a Person */ -import "common.proto"; +import "tests/protos/common.proto"; package examples; diff --git a/tests/protos/vehicle.proto b/tests/protos/vehicle.proto index 0db0ac6..5835d8b 100644 --- a/tests/protos/vehicle.proto +++ b/tests/protos/vehicle.proto @@ -1,7 +1,7 @@ // Proto definition for a Car -import "common.proto"; -import "person.proto"; +import "tests/protos/common.proto"; +import "tests/protos/person.proto"; package examples;