Skip to content

Commit ec6a133

Browse files
committed
Fixed: parser should not confuse previous trailing line comments with comments for the next declaration, see #762
1 parent fb3f9c7 commit ec6a133

File tree

5 files changed

+42
-60
lines changed

5 files changed

+42
-60
lines changed

index.d.ts

+3-27
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,6 @@ export function common(name: string, json: { [k: string]: any }): void;
1010

1111
export namespace common {
1212

13-
/** Any */
14-
// let google/protobuf/any.proto: INamespace;
15-
16-
/** Duration */
17-
// let google/protobuf/duration.proto: INamespace;
18-
19-
/** Empty */
20-
// let google/protobuf/empty.proto: INamespace;
21-
22-
/** Struct, Value, NullValue and ListValue */
23-
// let google/protobuf/struct.proto: INamespace;
24-
25-
/** Timestamp */
26-
// let google/protobuf/timestamp.proto: INamespace;
27-
28-
/** Wrappers */
29-
// let google/protobuf/wrappers.proto: INamespace;
30-
3113
/**
3214
* Gets the root definition of the specified common proto file.
3315
*
@@ -1349,12 +1331,6 @@ export interface IService extends INamespace {
13491331
methods: { [k: string]: IMethod };
13501332
}
13511333

1352-
/**
1353-
* Gets the current line number.
1354-
* @returns Line number
1355-
*/
1356-
type TokenizerHandleLine = () => number;
1357-
13581334
/**
13591335
* Gets the next token and advances.
13601336
* @returns Next token or `null` on eof
@@ -1392,9 +1368,6 @@ type TokenizerHandleCmnt = (line?: number) => string;
13921368
/** Handle object returned from {@link tokenize}. */
13931369
export interface ITokenizerHandle {
13941370

1395-
/** Gets the current line number */
1396-
line: TokenizerHandleLine;
1397-
13981371
/** Gets the next token and advances (`null` on eof) */
13991372
next: TokenizerHandleNext;
14001373

@@ -1409,6 +1382,9 @@ export interface ITokenizerHandle {
14091382

14101383
/** Gets the comment on the previous line or the line comment on the specified line, if any */
14111384
cmnt: TokenizerHandleCmnt;
1385+
1386+
/** Current line number */
1387+
line: number;
14121388
}
14131389

14141390
/**

src/parse.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ function parse(source, root, options) {
9595
var filename = parse.filename;
9696
if (!insideTryCatch)
9797
parse.filename = null;
98-
return Error("illegal " + (name || "token") + " '" + token + "' (" + (filename ? filename + ", " : "") + "line " + tn.line() + ")");
98+
return Error("illegal " + (name || "token") + " '" + token + "' (" + (filename ? filename + ", " : "") + "line " + tn.line + ")");
9999
}
100100

101101
function readString() {
@@ -279,7 +279,7 @@ function parse(source, root, options) {
279279
}
280280

281281
function ifBlock(obj, fnIf, fnElse) {
282-
var trailingLine = tn.line();
282+
var trailingLine = tn.line;
283283
if (obj) {
284284
obj.comment = cmnt(); // try block-type comment
285285
obj.filename = parse.filename;

src/tokenize.js

+30-28
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,6 @@ function unescape(str) {
3838

3939
tokenize.unescape = unescape;
4040

41-
/**
42-
* Gets the current line number.
43-
* @typedef TokenizerHandleLine
44-
* @type {function}
45-
* @returns {number} Line number
46-
*/
47-
4841
/**
4942
* Gets the next token and advances.
5043
* @typedef TokenizerHandleNext
@@ -88,12 +81,12 @@ tokenize.unescape = unescape;
8881
/**
8982
* Handle object returned from {@link tokenize}.
9083
* @interface ITokenizerHandle
91-
* @property {TokenizerHandleLine} line Gets the current line number
9284
* @property {TokenizerHandleNext} next Gets the next token and advances (`null` on eof)
9385
* @property {TokenizerHandlePeek} peek Peeks for the next token (`null` on eof)
9486
* @property {TokenizerHandlePush} push Pushes a token back to the stack
9587
* @property {TokenizerHandleSkip} skip Skips a token, returns its presence and advances or, if non-optional and not present, throws
9688
* @property {TokenizerHandleCmnt} cmnt Gets the comment on the previous line or the line comment on the specified line, if any
89+
* @property {number} line Current line number
9790
*/
9891

9992
/**
@@ -110,7 +103,8 @@ function tokenize(source) {
110103
line = 1,
111104
commentType = null,
112105
commentText = null,
113-
commentLine = 0;
106+
commentLine = 0,
107+
commentLineEmpty = false;
114108

115109
var stack = [];
116110

@@ -164,6 +158,15 @@ function tokenize(source) {
164158
function setComment(start, end) {
165159
commentType = source.charAt(start++);
166160
commentLine = line;
161+
commentLineEmpty = false;
162+
var offset = start - 3, // "///" or "/**"
163+
c;
164+
do {
165+
if (--offset < 0 || (c = source.charAt(offset)) === "\n") {
166+
commentLineEmpty = true;
167+
break;
168+
}
169+
} while (c === " " || c === "\t");
167170
var lines = source
168171
.substring(start, end)
169172
.split(setCommentSplitRe);
@@ -188,7 +191,7 @@ function tokenize(source) {
188191
prev,
189192
curr,
190193
start,
191-
isComment;
194+
isDoc;
192195
do {
193196
if (offset === length)
194197
return null;
@@ -203,17 +206,17 @@ function tokenize(source) {
203206
if (++offset === length)
204207
throw illegal("comment");
205208
if (charAt(offset) === "/") { // Line
206-
isComment = charAt(start = offset + 1) === "/";
209+
isDoc = charAt(start = offset + 1) === "/";
207210
while (charAt(++offset) !== "\n")
208211
if (offset === length)
209212
return null;
210213
++offset;
211-
if (isComment)
214+
if (isDoc) /// Comment
212215
setComment(start, offset - 1);
213216
++line;
214217
repeat = true;
215218
} else if ((curr = charAt(offset)) === "*") { /* Block */
216-
isComment = charAt(start = offset + 1) === "*";
219+
isDoc = charAt(start = offset + 1) === "*";
217220
do {
218221
if (curr === "\n")
219222
++line;
@@ -223,7 +226,7 @@ function tokenize(source) {
223226
curr = charAt(offset);
224227
} while (prev !== "*" || curr !== "/");
225228
++offset;
226-
if (isComment)
229+
if (isDoc) /** Comment */
227230
setComment(start, offset - 2);
228231
repeat = true;
229232
} else
@@ -292,33 +295,32 @@ function tokenize(source) {
292295

293296
/**
294297
* Gets a comment.
295-
* @param {number} [trailingLine] Trailing line number if applicable
298+
* @param {number} [trailingLine] Line number if looking for a trailing comment
296299
* @returns {?string} Comment text
297300
* @inner
298301
*/
299302
function cmnt(trailingLine) {
300-
var ret;
301-
if (trailingLine === undefined)
302-
ret = commentLine === line - 1 && commentText || null;
303-
else {
304-
if (!commentText)
303+
var ret = null;
304+
if (trailingLine === undefined) {
305+
if (commentLine === line - 1 && (commentType === "*" || commentLineEmpty))
306+
ret = commentText;
307+
} else {
308+
if (commentLine !== trailingLine || commentLineEmpty || commentType !== "/")
305309
peek();
306-
ret = commentLine === trailingLine && commentType === "/" && commentText || null;
310+
if (commentLine === trailingLine && !commentLineEmpty && commentType === "/")
311+
ret = commentText;
307312
}
308-
commentType = commentText = null;
309-
commentLine = 0;
310313
return ret;
311314
}
312315

313-
return {
316+
return Object.defineProperty({
314317
next: next,
315318
peek: peek,
316319
push: push,
317320
skip: skip,
318-
line: function() {
319-
return line;
320-
},
321321
cmnt: cmnt
322-
};
322+
}, "line", {
323+
get: function() { return line; }
324+
});
323325
/* eslint-enable callback-return */
324326
}

tests/data/comments.proto

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ syntax = "proto3";
1010
a
1111
** comment.
1212
*/
13-
message Test1 {
13+
message Test1 { /// not a valid comment
1414

1515
/**
1616
* Field with a comment.
@@ -44,5 +44,8 @@ enum Test3 {
4444
// Value with no comment.
4545
TWO = 2;
4646

47+
/// Preferred value with a comment.
4748
THREE = 3; /// Value with a comment.
49+
50+
FOUR = 4; /// Other value with a comment.
4851
}

tests/docs_comments.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var tape = require("tape");
33
var protobuf = require("..");
44

55
tape.test("proto comments", function(test) {
6-
test.plan(9);
6+
test.plan(10);
77
protobuf.load("tests/data/comments.proto", function(err, root) {
88
if (err)
99
throw test.fail(err.message);
@@ -18,7 +18,8 @@ tape.test("proto comments", function(test) {
1818

1919
test.equal(root.lookup("Test3").comments.ONE, "Value with a comment.", "should parse blocks for enum values");
2020
test.equal(root.lookup("Test3").comments.TWO, null, "should not parse lines for enum values");
21-
test.equal(root.lookup("Test3").comments.THREE, "Value with a comment.", "should parse triple-slash lines for enum values");
21+
test.equal(root.lookup("Test3").comments.THREE, "Preferred value with a comment.", "should parse lines for enum values and prefer on top over trailing");
22+
test.equal(root.lookup("Test3").comments.FOUR, "Other value with a comment.", "should not confuse previous trailing comments with comments for the next field");
2223

2324
test.end();
2425
});

0 commit comments

Comments
 (0)