Comparing version
@@ -0,1 +1,5 @@ | ||
v2.1.0 - January 6, 2018 | ||
* 827f314 Update: support node ranges (fixes #89) (#190) (Teddy Katz) | ||
v2.0.2 - November 25, 2017 | ||
@@ -2,0 +6,0 @@ |
@@ -93,2 +93,7 @@ /* | ||
// A regex character class that contains all whitespace except linebreak characters (\r, \n, \u2028, \u2029) | ||
var WHITESPACE = '[ \\f\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]'; | ||
var STAR_MATCHER = '(' + WHITESPACE + '*(?:\\*' + WHITESPACE + '?)?)(.+|[\r\n\u2028\u2029])'; | ||
function unwrapComment(doc) { | ||
@@ -99,50 +104,35 @@ // JSDoc comment is following form | ||
// */ | ||
// remove /**, */ and * | ||
var BEFORE_STAR = 0, | ||
STAR = 1, | ||
AFTER_STAR = 2, | ||
index, | ||
len, | ||
mode, | ||
result, | ||
ch; | ||
doc = doc.replace(/^\/\*\*?/, '').replace(/\*\/$/, ''); | ||
index = 0; | ||
len = doc.length; | ||
mode = BEFORE_STAR; | ||
result = ''; | ||
return doc. | ||
// remove /** | ||
replace(/^\/\*\*?/, ''). | ||
// remove */ | ||
replace(/\*\/$/, ''). | ||
// remove ' * ' at the beginning of a line | ||
replace(new RegExp(STAR_MATCHER, 'g'), '$2'). | ||
// remove trailing whitespace | ||
replace(/\s*$/, ''); | ||
} | ||
while (index < len) { | ||
ch = doc.charCodeAt(index); | ||
switch (mode) { | ||
case BEFORE_STAR: | ||
if (esutils.code.isLineTerminator(ch)) { | ||
result += String.fromCharCode(ch); | ||
} else if (ch === 0x2A /* '*' */) { | ||
mode = STAR; | ||
} else if (!esutils.code.isWhiteSpace(ch)) { | ||
result += String.fromCharCode(ch); | ||
mode = AFTER_STAR; | ||
} | ||
break; | ||
/** | ||
* Converts an index in an "unwrapped" JSDoc comment to the corresponding index in the original "wrapped" version | ||
* @param {string} originalSource The original wrapped comment | ||
* @param {number} unwrappedIndex The index of a character in the unwrapped string | ||
* @returns {number} The index of the corresponding character in the original wrapped string | ||
*/ | ||
function convertUnwrappedCommentIndex(originalSource, unwrappedIndex) { | ||
var replacedSource = originalSource.replace(/^\/\*\*?/, ''); | ||
var numSkippedChars = 0; | ||
var matcher = new RegExp(STAR_MATCHER, 'g'); | ||
var match; | ||
case STAR: | ||
if (!esutils.code.isWhiteSpace(ch)) { | ||
result += String.fromCharCode(ch); | ||
} | ||
mode = esutils.code.isLineTerminator(ch) ? BEFORE_STAR : AFTER_STAR; | ||
break; | ||
while ((match = matcher.exec(replacedSource))) { | ||
numSkippedChars += match[1].length; | ||
case AFTER_STAR: | ||
result += String.fromCharCode(ch); | ||
if (esutils.code.isLineTerminator(ch)) { | ||
mode = BEFORE_STAR; | ||
} | ||
break; | ||
if (match.index + match[0].length > unwrappedIndex + numSkippedChars) { | ||
return unwrappedIndex + numSkippedChars + originalSource.length - replacedSource.length; | ||
} | ||
index += 1; | ||
} | ||
return result.replace(/\s+$/, ''); | ||
return originalSource.replace(/\*\/$/, '').replace(/\s*$/, '').length; | ||
} | ||
@@ -158,2 +148,3 @@ | ||
source, | ||
originalSource, | ||
recoverable, | ||
@@ -209,4 +200,4 @@ sloppy, | ||
// therefore, scanning type expression with balancing braces. | ||
function parseType(title, last) { | ||
var ch, brace, type, direct = false; | ||
function parseType(title, last, addRange) { | ||
var ch, brace, type, startIndex, direct = false; | ||
@@ -251,2 +242,5 @@ | ||
} | ||
if (type === '') { | ||
startIndex = index; | ||
} | ||
type += advance(); | ||
@@ -262,6 +256,6 @@ } | ||
if (isAllowedOptional(title)) { | ||
return typed.parseParamType(type); | ||
return typed.parseParamType(type, {startIndex: convertIndex(startIndex), range: addRange}); | ||
} | ||
return typed.parseType(type); | ||
return typed.parseType(type, {startIndex: convertIndex(startIndex), range: addRange}); | ||
} | ||
@@ -411,2 +405,9 @@ | ||
function convertIndex(rangeIndex) { | ||
if (source === originalSource) { | ||
return rangeIndex; | ||
} | ||
return convertUnwrappedCommentIndex(originalSource, rangeIndex); | ||
} | ||
function TagParser(options, title) { | ||
@@ -422,2 +423,3 @@ this._options = options; | ||
} | ||
this._first = index - title.length - 1; | ||
this._last = 0; | ||
@@ -453,3 +455,3 @@ // space to save special information for title parsers. | ||
try { | ||
this._tag.type = parseType(this._title, this._last); | ||
this._tag.type = parseType(this._title, this._last, this._options.range); | ||
if (!this._tag.type) { | ||
@@ -471,3 +473,3 @@ if (!isParamTitle(this._title) && !isReturnTitle(this._title)) { | ||
try { | ||
this._tag.type = parseType(this._title, this._last); | ||
this._tag.type = parseType(this._title, this._last, this._options.range); | ||
} catch (e) { | ||
@@ -764,2 +766,6 @@ //For optional types, lets drop the thrown error when we hit the end of the file | ||
if (this._options.range) { | ||
this._tag.range = [this._first, source.slice(0, this._last).replace(/\s*$/, '').length].map(convertIndex); | ||
} | ||
if (hasOwnProperty(Rules, this._title)) { | ||
@@ -845,2 +851,4 @@ sequences = Rules[this._title]; | ||
originalSource = comment; | ||
// array of relevant tags | ||
@@ -847,0 +855,0 @@ if (options.tags) { |
162
lib/typed.js
@@ -22,3 +22,5 @@ /* | ||
esutils, | ||
utility; | ||
utility, | ||
rangeOffset, | ||
addRange; | ||
@@ -98,2 +100,9 @@ esutils = require('esutils'); | ||
function maybeAddRange(node, range) { | ||
if (addRange) { | ||
node.range = [range[0] + rangeOffset, range[1] + rangeOffset]; | ||
} | ||
return node; | ||
} | ||
function advance() { | ||
@@ -513,3 +522,3 @@ var ch = source.charAt(index); | ||
function parseUnionType() { | ||
var elements; | ||
var elements, startIndex = index - 1; | ||
consume(Token.LPAREN, 'UnionType should start with ('); | ||
@@ -527,6 +536,6 @@ elements = []; | ||
consume(Token.RPAREN, 'UnionType should end with )'); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.UnionType, | ||
elements: elements | ||
}; | ||
}, [startIndex, previous]); | ||
} | ||
@@ -542,3 +551,3 @@ | ||
function parseArrayType() { | ||
var elements; | ||
var elements, startIndex = index - 1, restStartIndex; | ||
consume(Token.LBRACK, 'ArrayType should start with ['); | ||
@@ -548,7 +557,8 @@ elements = []; | ||
if (token === Token.REST) { | ||
restStartIndex = index - 3; | ||
consume(Token.REST); | ||
elements.push({ | ||
elements.push(maybeAddRange({ | ||
type: Syntax.RestType, | ||
expression: parseTypeExpression() | ||
}); | ||
}, [restStartIndex, previous])); | ||
break; | ||
@@ -563,6 +573,6 @@ } else { | ||
expect(Token.RBRACK); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.ArrayType, | ||
elements: elements | ||
}; | ||
}, [startIndex, previous]); | ||
} | ||
@@ -595,3 +605,3 @@ | ||
function parseFieldType() { | ||
var key; | ||
var key, rangeStart = previous; | ||
@@ -601,13 +611,13 @@ key = parseFieldName(); | ||
consume(Token.COLON); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.FieldType, | ||
key: key, | ||
value: parseTypeExpression() | ||
}; | ||
}, [rangeStart, previous]); | ||
} | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.FieldType, | ||
key: key, | ||
value: null | ||
}; | ||
}, [rangeStart, previous]); | ||
} | ||
@@ -622,3 +632,3 @@ | ||
function parseRecordType() { | ||
var fields; | ||
var fields, rangeStart = index - 1, rangeEnd; | ||
@@ -637,7 +647,8 @@ consume(Token.LBRACE, 'RecordType should start with {'); | ||
} | ||
rangeEnd = index; | ||
expect(Token.RBRACE); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.RecordType, | ||
fields: fields | ||
}; | ||
}, [rangeStart, rangeEnd]); | ||
} | ||
@@ -653,3 +664,3 @@ | ||
function parseNameExpression() { | ||
var name = value; | ||
var name = value, rangeStart = index - name.length; | ||
expect(Token.NAME); | ||
@@ -666,6 +677,6 @@ | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.NameExpression, | ||
name: name | ||
}; | ||
}, [rangeStart, previous]); | ||
} | ||
@@ -695,3 +706,3 @@ | ||
function parseTypeName() { | ||
var expr, applications; | ||
var expr, applications, startIndex = index - value.length; | ||
@@ -703,7 +714,7 @@ expr = parseNameExpression(); | ||
expect(Token.GT); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.TypeApplication, | ||
expression: expr, | ||
applications: applications | ||
}; | ||
}, [startIndex, previous]); | ||
} | ||
@@ -755,3 +766,3 @@ return expr; | ||
function parseParametersType() { | ||
var params = [], optionalSequence = false, expr, rest = false; | ||
var params = [], optionalSequence = false, expr, rest = false, startIndex, restStartIndex = index - 3, nameStartIndex; | ||
@@ -765,18 +776,21 @@ while (token !== Token.RPAREN) { | ||
startIndex = previous; | ||
expr = parseTypeExpression(); | ||
if (expr.type === Syntax.NameExpression && token === Token.COLON) { | ||
nameStartIndex = previous - expr.name.length; | ||
// Identifier ':' TypeExpression | ||
consume(Token.COLON); | ||
expr = { | ||
expr = maybeAddRange({ | ||
type: Syntax.ParameterType, | ||
name: expr.name, | ||
expression: parseTypeExpression() | ||
}; | ||
}, [nameStartIndex, previous]); | ||
} | ||
if (token === Token.EQUAL) { | ||
consume(Token.EQUAL); | ||
expr = { | ||
expr = maybeAddRange({ | ||
type: Syntax.OptionalType, | ||
expression: expr | ||
}; | ||
}, [startIndex, previous]); | ||
optionalSequence = true; | ||
@@ -789,6 +803,6 @@ } else { | ||
if (rest) { | ||
expr = { | ||
expr = maybeAddRange({ | ||
type: Syntax.RestType, | ||
expression: expr | ||
}; | ||
}, [restStartIndex, previous]); | ||
} | ||
@@ -811,3 +825,3 @@ params.push(expr); | ||
function parseFunctionType() { | ||
var isNew, thisBinding, params, result, fnType; | ||
var isNew, thisBinding, params, result, fnType, startIndex = index - value.length; | ||
utility.assert(token === Token.NAME && value === 'function', 'FunctionType should start with \'function\''); | ||
@@ -849,7 +863,7 @@ consume(Token.NAME); | ||
fnType = { | ||
fnType = maybeAddRange({ | ||
type: Syntax.FunctionType, | ||
params: params, | ||
result: result | ||
}; | ||
}, [startIndex, previous]); | ||
if (thisBinding) { | ||
@@ -875,9 +889,9 @@ // avoid adding null 'new' and 'this' properties | ||
function parseBasicTypeExpression() { | ||
var context; | ||
var context, startIndex; | ||
switch (token) { | ||
case Token.STAR: | ||
consume(Token.STAR); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.AllLiteral | ||
}; | ||
}, [previous - 1, previous]); | ||
@@ -894,7 +908,9 @@ case Token.LPAREN: | ||
case Token.NAME: | ||
startIndex = index - value.length; | ||
if (value === 'null') { | ||
consume(Token.NAME); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.NullLiteral | ||
}; | ||
}, [startIndex, previous]); | ||
} | ||
@@ -904,5 +920,5 @@ | ||
consume(Token.NAME); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.UndefinedLiteral | ||
}; | ||
}, [startIndex, previous]); | ||
} | ||
@@ -912,6 +928,6 @@ | ||
consume(Token.NAME); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.BooleanLiteralType, | ||
value: value === 'true' | ||
}; | ||
}, [startIndex, previous]); | ||
} | ||
@@ -932,13 +948,13 @@ | ||
next(); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.StringLiteralType, | ||
value: value | ||
}; | ||
}, [previous - value.length - 2, previous]); | ||
case Token.NUMBER: | ||
next(); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.NumericLiteralType, | ||
value: value | ||
}; | ||
}, [previous - String(value).length, previous]); | ||
@@ -959,5 +975,6 @@ default: | ||
function parseTypeExpression() { | ||
var expr; | ||
var expr, rangeStart; | ||
if (token === Token.QUESTION) { | ||
rangeStart = index - 1; | ||
consume(Token.QUESTION); | ||
@@ -967,20 +984,21 @@ if (token === Token.COMMA || token === Token.EQUAL || token === Token.RBRACE || | ||
token === Token.RBRACK || token === Token.GT) { | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.NullableLiteral | ||
}; | ||
}, [rangeStart, previous]); | ||
} | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.NullableType, | ||
expression: parseBasicTypeExpression(), | ||
prefix: true | ||
}; | ||
} | ||
if (token === Token.BANG) { | ||
}, [rangeStart, previous]); | ||
} else if (token === Token.BANG) { | ||
rangeStart = index - 1; | ||
consume(Token.BANG); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.NonNullableType, | ||
expression: parseBasicTypeExpression(), | ||
prefix: true | ||
}; | ||
}, [rangeStart, previous]); | ||
} else { | ||
rangeStart = previous; | ||
} | ||
@@ -991,7 +1009,7 @@ | ||
consume(Token.BANG); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.NonNullableType, | ||
expression: expr, | ||
prefix: false | ||
}; | ||
}, [rangeStart, previous]); | ||
} | ||
@@ -1001,7 +1019,7 @@ | ||
consume(Token.QUESTION); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.NullableType, | ||
expression: expr, | ||
prefix: false | ||
}; | ||
}, [rangeStart, previous]); | ||
} | ||
@@ -1012,10 +1030,10 @@ | ||
expect(Token.RBRACK, 'expected an array-style type declaration (' + value + '[])'); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.TypeApplication, | ||
expression: { | ||
expression: maybeAddRange({ | ||
type: Syntax.NameExpression, | ||
name: 'Array' | ||
}, | ||
}, [rangeStart, previous]), | ||
applications: [expr] | ||
}; | ||
}, [rangeStart, previous]); | ||
} | ||
@@ -1053,6 +1071,6 @@ | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.UnionType, | ||
elements: elements | ||
}; | ||
}, [0, index]); | ||
} | ||
@@ -1065,6 +1083,6 @@ | ||
consume(Token.REST); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.RestType, | ||
expression: parseTop() | ||
}; | ||
}, [0, index]); | ||
} | ||
@@ -1075,6 +1093,6 @@ | ||
consume(Token.EQUAL); | ||
return { | ||
return maybeAddRange({ | ||
type: Syntax.OptionalType, | ||
expression: expr | ||
}; | ||
}, [0, index]); | ||
} | ||
@@ -1092,2 +1110,4 @@ | ||
previous = 0; | ||
addRange = opt && opt.range; | ||
rangeOffset = opt && opt.startIndex || 0; | ||
@@ -1118,2 +1138,4 @@ next(); | ||
previous = 0; | ||
addRange = opt && opt.range; | ||
rangeOffset = opt && opt.startIndex || 0; | ||
@@ -1120,0 +1142,0 @@ next(); |
@@ -6,3 +6,3 @@ { | ||
"main": "lib/doctrine.js", | ||
"version": "2.0.2", | ||
"version": "2.1.0", | ||
"engines": { | ||
@@ -9,0 +9,0 @@ "node": ">=0.10.0" |
@@ -38,2 +38,3 @@ [![NPM version][npm-image]][npm-url] | ||
* `lineNumbers` - set to `true` to add `lineNumber` to each node, specifying the line on which the node is found in the source. Default: `false`. | ||
* `range` - set to `true` to add `range` to each node, specifying the start and end index of the node in the original comment. Default: `false`. | ||
@@ -40,0 +41,0 @@ Here's a simple example: |
105957
3.34%1941
1.2%166
0.61%