[Pkg-javascript-commits] [node-doctrine] 01/05: New upstream version 2.1.0
Julien Puydt
julien.puydt at laposte.net
Wed Jan 10 16:21:20 UTC 2018
This is an automated email from the git hooks/post-receive script.
jpuydt-guest pushed a commit to branch master
in repository node-doctrine.
commit b5ed464171c04c4f19579fa2e221abc9ccb38d3a
Author: Julien Puydt <julien.puydt at laposte.net>
Date: Wed Jan 10 13:43:12 2018 +0100
New upstream version 2.1.0
---
CHANGELOG.md | 4 +
README.md | 1 +
lib/doctrine.js | 106 +++++-----
lib/typed.js | 162 ++++++++------
package-lock.json | 2 +-
package.json | 2 +-
test/parse.js | 622 +++++++++++++++++++++++++++++++++++-------------------
7 files changed, 562 insertions(+), 337 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5caec3..57140d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+v2.1.0 - January 6, 2018
+
+* 827f314 Update: support node ranges (fixes #89) (#190) (Teddy Katz)
+
v2.0.2 - November 25, 2017
* 5049ee3 Fix: Remove redundant LICENSE/README names from files (#203) (Kevin Partington)
diff --git a/README.md b/README.md
index dcfe776..26fad18 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@ The primary method is `parse()`, which accepts two arguments: the JSDoc comment
* `recoverable` - set to `true` to keep parsing even when syntax errors occur. Default: `false`.
* `sloppy` - set to `true` to allow optional parameters to be specified in brackets (`@param {string} [foo]`). Default: `false`.
* `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`.
Here's a simple example:
diff --git a/lib/doctrine.js b/lib/doctrine.js
index bdaa0e0..1665afe 100644
--- a/lib/doctrine.js
+++ b/lib/doctrine.js
@@ -90,59 +90,49 @@
title === 'public' || title === 'private' || title === 'protected';
}
+ // 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) {
// 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 = '';
-
- 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;
- case STAR:
- if (!esutils.code.isWhiteSpace(ch)) {
- result += String.fromCharCode(ch);
- }
- mode = esutils.code.isLineTerminator(ch) ? BEFORE_STAR : AFTER_STAR;
- break;
+ 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*$/, '');
+ }
- case AFTER_STAR:
- result += String.fromCharCode(ch);
- if (esutils.code.isLineTerminator(ch)) {
- mode = BEFORE_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;
+
+ while ((match = matcher.exec(replacedSource))) {
+ numSkippedChars += match[1].length;
+
+ 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;
}
// JSDoc Tag Parser
@@ -153,6 +143,7 @@
lineNumber,
length,
source,
+ originalSource,
recoverable,
sloppy,
strict;
@@ -203,8 +194,8 @@
// { { ok: string } }
//
// 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;
// search '{'
@@ -244,6 +235,9 @@
} else if (ch === 0x7B /* '{' */) {
brace += 1;
}
+ if (type === '') {
+ startIndex = index;
+ }
type += advance();
}
}
@@ -254,10 +248,10 @@
}
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});
}
function scanIdentifier(last) {
@@ -402,6 +396,13 @@
return true;
}
+ function convertIndex(rangeIndex) {
+ if (source === originalSource) {
+ return rangeIndex;
+ }
+ return convertUnwrappedCommentIndex(originalSource, rangeIndex);
+ }
+
function TagParser(options, title) {
this._options = options;
this._title = title.toLowerCase();
@@ -412,6 +413,7 @@
if (this._options.lineNumbers) {
this._tag.lineNumber = lineNumber;
}
+ this._first = index - title.length - 1;
this._last = 0;
// space to save special information for title parsers.
this._extra = { };
@@ -442,7 +444,7 @@
// type required titles
if (isTypeParameterRequired(this._title)) {
try {
- this._tag.type = parseType(this._title, this._last);
+ this._tag.type = parseType(this._title, this._last, this._options.range);
if (!this._tag.type) {
if (!isParamTitle(this._title) && !isReturnTitle(this._title)) {
if (!this.addError('Missing or invalid tag type')) {
@@ -459,7 +461,7 @@
} else if (isAllowedType(this._title)) {
// optional types
try {
- this._tag.type = parseType(this._title, this._last);
+ this._tag.type = parseType(this._title, this._last, this._options.range);
} catch (e) {
//For optional types, lets drop the thrown error when we hit the end of the file
}
@@ -751,6 +753,10 @@
// Seek to content last index.
this._last = seekContent(this._title);
+ if (this._options.range) {
+ this._tag.range = [this._first, source.slice(0, this._last).replace(/\s*$/, '').length].map(convertIndex);
+ }
+
if (hasOwnProperty(Rules, this._title)) {
sequences = Rules[this._title];
} else {
@@ -831,6 +837,8 @@
source = comment;
}
+ originalSource = comment;
+
// array of relevant tags
if (options.tags) {
if (Array.isArray(options.tags)) {
diff --git a/lib/typed.js b/lib/typed.js
index e5b14f7..bdd3c39 100644
--- a/lib/typed.js
+++ b/lib/typed.js
@@ -19,7 +19,9 @@
token,
value,
esutils,
- utility;
+ utility,
+ rangeOffset,
+ addRange;
esutils = require('esutils');
utility = require('./utility');
@@ -94,6 +96,13 @@
return new Context(previous, index, token, value);
};
+ function maybeAddRange(node, range) {
+ if (addRange) {
+ node.range = [range[0] + rangeOffset, range[1] + rangeOffset];
+ }
+ return node;
+ }
+
function advance() {
var ch = source.charAt(index);
index += 1;
@@ -508,7 +517,7 @@
// TypeExpression
// | TypeExpression '|' NonemptyTypeUnionList
function parseUnionType() {
- var elements;
+ var elements, startIndex = index - 1;
consume(Token.LPAREN, 'UnionType should start with (');
elements = [];
if (token !== Token.RPAREN) {
@@ -521,10 +530,10 @@
}
}
consume(Token.RPAREN, 'UnionType should end with )');
- return {
+ return maybeAddRange({
type: Syntax.UnionType,
elements: elements
- };
+ }, [startIndex, previous]);
}
// ArrayType := '[' ElementTypeList ']'
@@ -535,16 +544,17 @@
// | '...' TypeExpression
// | TypeExpression ',' ElementTypeList
function parseArrayType() {
- var elements;
+ var elements, startIndex = index - 1, restStartIndex;
consume(Token.LBRACK, 'ArrayType should start with [');
elements = [];
while (token !== Token.RBRACK) {
if (token === Token.REST) {
+ restStartIndex = index - 3;
consume(Token.REST);
- elements.push({
+ elements.push(maybeAddRange({
type: Syntax.RestType,
expression: parseTypeExpression()
- });
+ }, [restStartIndex, previous]));
break;
} else {
elements.push(parseTypeExpression());
@@ -554,10 +564,10 @@
}
}
expect(Token.RBRACK);
- return {
+ return maybeAddRange({
type: Syntax.ArrayType,
elements: elements
- };
+ }, [startIndex, previous]);
}
function parseFieldName() {
@@ -585,22 +595,22 @@
// | NumberLiteral
// | ReservedIdentifier
function parseFieldType() {
- var key;
+ var key, rangeStart = previous;
key = parseFieldName();
if (token === Token.COLON) {
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]);
}
// RecordType := '{' FieldTypeList '}'
@@ -610,7 +620,7 @@
// | FieldType
// | FieldType ',' FieldTypeList
function parseRecordType() {
- var fields;
+ var fields, rangeStart = index - 1, rangeEnd;
consume(Token.LBRACE, 'RecordType should start with {');
fields = [];
@@ -624,11 +634,12 @@
}
}
}
+ rangeEnd = index;
expect(Token.RBRACE);
- return {
+ return maybeAddRange({
type: Syntax.RecordType,
fields: fields
- };
+ }, [rangeStart, rangeEnd]);
}
// NameExpression :=
@@ -639,7 +650,7 @@
// Identifier is the same as Token.NAME, including any dots, something like
// namespace.module.MyClass
function parseNameExpression() {
- var name = value;
+ var name = value, rangeStart = index - name.length;
expect(Token.NAME);
if (token === Token.COLON && (
@@ -651,10 +662,10 @@
expect(Token.NAME);
}
- return {
+ return maybeAddRange({
type: Syntax.NameExpression,
name: name
- };
+ }, [rangeStart, previous]);
}
// TypeExpressionList :=
@@ -679,18 +690,18 @@
// '.<' TypeExpressionList '>'
// | '<' TypeExpressionList '>' // this is extension of doctrine
function parseTypeName() {
- var expr, applications;
+ var expr, applications, startIndex = index - value.length;
expr = parseNameExpression();
if (token === Token.DOT_LT || token === Token.LT) {
next();
applications = parseTypeExpressionList();
expect(Token.GT);
- return {
+ return maybeAddRange({
type: Syntax.TypeApplication,
expression: expr,
applications: applications
- };
+ }, [startIndex, previous]);
}
return expr;
}
@@ -737,7 +748,7 @@
//
// Identifier is "new" or "this"
function parseParametersType() {
- var params = [], optionalSequence = false, expr, rest = false;
+ var params = [], optionalSequence = false, expr, rest = false, startIndex, restStartIndex = index - 3, nameStartIndex;
while (token !== Token.RPAREN) {
if (token === Token.REST) {
@@ -746,22 +757,25 @@
rest = true;
}
+ 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;
} else {
if (optionalSequence) {
@@ -769,10 +783,10 @@
}
}
if (rest) {
- expr = {
+ expr = maybeAddRange({
type: Syntax.RestType,
expression: expr
- };
+ }, [restStartIndex, previous]);
}
params.push(expr);
if (token !== Token.RPAREN) {
@@ -790,7 +804,7 @@
// | TypeParameters '(' 'this' ':' TypeName ')' ResultType
// | TypeParameters '(' 'this' ':' TypeName ',' ParametersType ')' ResultType
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\'');
consume(Token.NAME);
@@ -827,11 +841,11 @@
result = parseResultType();
}
- fnType = {
+ fnType = maybeAddRange({
type: Syntax.FunctionType,
params: params,
result: result
- };
+ }, [startIndex, previous]);
if (thisBinding) {
// avoid adding null 'new' and 'this' properties
fnType['this'] = thisBinding;
@@ -852,13 +866,13 @@
// | RecordType
// | ArrayType
function parseBasicTypeExpression() {
- var context;
+ var context, startIndex;
switch (token) {
case Token.STAR:
consume(Token.STAR);
- return {
+ return maybeAddRange({
type: Syntax.AllLiteral
- };
+ }, [previous - 1, previous]);
case Token.LPAREN:
return parseUnionType();
@@ -870,26 +884,28 @@
return parseRecordType();
case Token.NAME:
+ startIndex = index - value.length;
+
if (value === 'null') {
consume(Token.NAME);
- return {
+ return maybeAddRange({
type: Syntax.NullLiteral
- };
+ }, [startIndex, previous]);
}
if (value === 'undefined') {
consume(Token.NAME);
- return {
+ return maybeAddRange({
type: Syntax.UndefinedLiteral
- };
+ }, [startIndex, previous]);
}
if (value === 'true' || value === 'false') {
consume(Token.NAME);
- return {
+ return maybeAddRange({
type: Syntax.BooleanLiteralType,
value: value === 'true'
- };
+ }, [startIndex, previous]);
}
context = Context.save();
@@ -905,17 +921,17 @@
case Token.STRING:
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]);
default:
utility.throwError('unexpected token');
@@ -931,63 +947,65 @@
// | '?'
// | BasicTypeExpression '[]'
function parseTypeExpression() {
- var expr;
+ var expr, rangeStart;
if (token === Token.QUESTION) {
+ rangeStart = index - 1;
consume(Token.QUESTION);
if (token === Token.COMMA || token === Token.EQUAL || token === Token.RBRACE ||
token === Token.RPAREN || token === Token.PIPE || token === Token.EOF ||
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;
}
expr = parseBasicTypeExpression();
if (token === Token.BANG) {
consume(Token.BANG);
- return {
+ return maybeAddRange({
type: Syntax.NonNullableType,
expression: expr,
prefix: false
- };
+ }, [rangeStart, previous]);
}
if (token === Token.QUESTION) {
consume(Token.QUESTION);
- return {
+ return maybeAddRange({
type: Syntax.NullableType,
expression: expr,
prefix: false
- };
+ }, [rangeStart, previous]);
}
if (token === Token.LBRACK) {
consume(Token.LBRACK);
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]);
}
return expr;
@@ -1020,10 +1038,10 @@
consume(Token.PIPE);
}
- return {
+ return maybeAddRange({
type: Syntax.UnionType,
elements: elements
- };
+ }, [0, index]);
}
function parseTopParamType() {
@@ -1031,19 +1049,19 @@
if (token === Token.REST) {
consume(Token.REST);
- return {
+ return maybeAddRange({
type: Syntax.RestType,
expression: parseTop()
- };
+ }, [0, index]);
}
expr = parseTop();
if (token === Token.EQUAL) {
consume(Token.EQUAL);
- return {
+ return maybeAddRange({
type: Syntax.OptionalType,
expression: expr
- };
+ }, [0, index]);
}
return expr;
@@ -1056,6 +1074,8 @@
length = source.length;
index = 0;
previous = 0;
+ addRange = opt && opt.range;
+ rangeOffset = opt && opt.startIndex || 0;
next();
expr = parseTop();
@@ -1081,6 +1101,8 @@
length = source.length;
index = 0;
previous = 0;
+ addRange = opt && opt.range;
+ rangeOffset = opt && opt.startIndex || 0;
next();
expr = parseTopParamType();
diff --git a/package-lock.json b/package-lock.json
index 197d707..9e20b5a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "doctrine",
- "version": "2.0.2",
+ "version": "2.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index d309199..92667d3 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"description": "JSDoc parser",
"homepage": "https://github.com/eslint/doctrine",
"main": "lib/doctrine.js",
- "version": "2.0.2",
+ "version": "2.1.0",
"engines": {
"node": ">=0.10.0"
},
diff --git a/test/parse.js b/test/parse.js
index 51886db..224efd6 100644
--- a/test/parse.js
+++ b/test/parse.js
@@ -1387,125 +1387,149 @@ describe('parse', function () {
describe('parseType', function () {
it('union type closure-compiler extended', function () {
- var type = doctrine.parseType("string|number");
+ var type = doctrine.parseType("string|number", {range: true});
type.should.eql({
type: 'UnionType',
elements: [{
type: 'NameExpression',
- name: 'string'
+ name: 'string',
+ range: [0, 6]
}, {
type: 'NameExpression',
- name: 'number'
- }]
+ name: 'number',
+ range: [7, 13]
+ }],
+ range: [0, 13]
});
});
it('empty union type', function () {
- var type = doctrine.parseType("()");
+ var type = doctrine.parseType("()", {range: true});
type.should.eql({
type: 'UnionType',
- elements: []
+ elements: [],
+ range: [0, 2]
});
});
it('comma last array type', function () {
- var type = doctrine.parseType("[string,]");
+ var type = doctrine.parseType("[string,]", {range: true});
type.should.eql({
type: 'ArrayType',
elements: [{
type: 'NameExpression',
- name: 'string'
- }]
+ name: 'string',
+ range: [1, 7]
+ }],
+ range: [0, 9]
});
});
it('array type of all literal', function () {
- var type = doctrine.parseType("[*]");
+ var type = doctrine.parseType("[*]", {range: true});
type.should.eql({
type: 'ArrayType',
elements: [{
- type: 'AllLiteral'
- }]
+ type: 'AllLiteral',
+ range: [1, 2]
+ }],
+ range: [0, 3]
});
});
it('array type of nullable literal', function () {
- var type = doctrine.parseType("[?]");
+ var type = doctrine.parseType("[?]", {range: true});
type.should.eql({
type: 'ArrayType',
elements: [{
- type: 'NullableLiteral'
- }]
+ type: 'NullableLiteral',
+ range: [1, 2]
+ }],
+ range: [0, 3]
});
});
it('comma last record type', function () {
- var type = doctrine.parseType("{,}");
+ var type = doctrine.parseType("{,}", {range: true});
type.should.eql({
type: 'RecordType',
- fields: []
+ fields: [],
+ range: [0, 3]
});
});
it('type application', function () {
- var type = doctrine.parseType("Array.<String>");
+ var type = doctrine.parseType("Array.<String>", {range: true});
type.should.eql({
type: 'TypeApplication',
expression: {
type: 'NameExpression',
- name: 'Array'
+ name: 'Array',
+ range: [0, 5]
},
applications: [{
type: 'NameExpression',
- name: 'String'
- }]
+ name: 'String',
+ range: [7, 13]
+ }],
+ range: [0, 14]
});
});
it('type application with NullableLiteral', function () {
- var type = doctrine.parseType("Array<?>");
+ var type = doctrine.parseType("Array<?>", {range: true});
type.should.eql({
type: 'TypeApplication',
expression: {
type: 'NameExpression',
- name: 'Array'
+ name: 'Array',
+ range: [0, 5]
},
applications: [{
- type: 'NullableLiteral'
- }]
+ type: 'NullableLiteral',
+ range: [6, 7]
+ }],
+ range: [0, 8]
});
});
it('type application with multiple patterns', function () {
- var type = doctrine.parseType("Array.<String, Number>");
+ var type = doctrine.parseType("Array.<String, Number>", {range: true});
type.should.eql({
type: 'TypeApplication',
expression: {
type: 'NameExpression',
- name: 'Array'
+ name: 'Array',
+ range: [0, 5]
},
applications: [{
type: 'NameExpression',
- name: 'String'
+ name: 'String',
+ range: [7, 13]
}, {
type: 'NameExpression',
- name: 'Number'
- }]
+ name: 'Number',
+ range: [15, 21]
+ }],
+ range: [0, 22]
});
});
it('type application without dot', function () {
- var type = doctrine.parseType("Array<String>");
+ var type = doctrine.parseType("Array<String>", {range: true});
type.should.eql({
type: 'TypeApplication',
expression: {
type: 'NameExpression',
- name: 'Array'
+ name: 'Array',
+ range: [0, 5]
},
applications: [{
type: 'NameExpression',
- name: 'String'
- }]
+ name: 'String',
+ range: [6, 12]
+ }],
+ range: [0, 13]
});
});
@@ -1525,163 +1549,193 @@ describe('parseType', function () {
});
it('function type simple', function () {
- var type = doctrine.parseType("function()");
+ var type = doctrine.parseType("function()", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [],
+ "result": null,
+ range: [0, 10]
+ });
});
it('function type with name', function () {
- var type = doctrine.parseType("function(a)");
+ var type = doctrine.parseType("function(a)", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [
- {
- "type": "NameExpression",
- "name": "a"
- }
- ],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [
+ {
+ "type": "NameExpression",
+ "name": "a",
+ range: [9, 10]
+ }
+ ],
+ "result": null,
+ range: [0, 11]
+ });
});
it('function type with name and type', function () {
- var type = doctrine.parseType("function(a:b)");
+ var type = doctrine.parseType("function(a:b)", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [
- {
- "type": "ParameterType",
- "name": "a",
- "expression": {
- "type": "NameExpression",
- "name": "b"
- }
- }
- ],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [
+ {
+ "type": "ParameterType",
+ "name": "a",
+ "expression": {
+ "type": "NameExpression",
+ "name": "b",
+ range: [11, 12]
+ },
+ range: [9, 12]
+ }
+ ],
+ "result": null,
+ range: [0, 13]
+ });
});
it('function type with optional param', function () {
- var type = doctrine.parseType("function(a=)");
+ var type = doctrine.parseType("function(a=)", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [
- {
- "type": "OptionalType",
- "expression": {
- "type": "NameExpression",
- "name": "a"
- }
- }
- ],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [
+ {
+ "type": "OptionalType",
+ "expression": {
+ "type": "NameExpression",
+ "name": "a",
+ range: [9, 10]
+ },
+ range: [9, 11]
+ }
+ ],
+ "result": null,
+ range: [0, 12]
+ });
});
it('function type with optional param name and type', function () {
- var type = doctrine.parseType("function(a:b=)");
+ var type = doctrine.parseType("function(a:b=)", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [
- {
- "type": "OptionalType",
- "expression": {
- "type": "ParameterType",
- "name": "a",
- "expression": {
- "type": "NameExpression",
- "name": "b"
- }
- }
- }
- ],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [
+ {
+ "type": "OptionalType",
+ "expression": {
+ "type": "ParameterType",
+ "name": "a",
+ "expression": {
+ "type": "NameExpression",
+ "name": "b",
+ range: [11, 12]
+ },
+ range: [9, 12]
+ },
+ range: [9, 13]
+ }
+ ],
+ "result": null,
+ range: [0, 14]
+ });
});
it('function type with rest param', function () {
- var type = doctrine.parseType("function(...a)");
+ var type = doctrine.parseType("function(...a)", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [
- {
- "type": "RestType",
- "expression": {
- "type": "NameExpression",
- "name": "a"
- }
- }
- ],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [
+ {
+ "type": "RestType",
+ "expression": {
+ "type": "NameExpression",
+ "name": "a",
+ range: [12, 13]
+ },
+ range: [9, 13]
+ }
+ ],
+ "result": null,
+ range: [0, 14]
+ });
});
it('function type with rest param name and type', function () {
- var type = doctrine.parseType("function(...a:b)");
+ var type = doctrine.parseType("function(...a:b)", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [
- {
- "type": "RestType",
- "expression": {
- "type": "ParameterType",
- "name": "a",
- "expression": {
- "type": "NameExpression",
- "name": "b"
- }
- }
- }
- ],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [
+ {
+ "type": "RestType",
+ "expression": {
+ "type": "ParameterType",
+ "name": "a",
+ "expression": {
+ "type": "NameExpression",
+ "name": "b",
+ range: [14, 15]
+ },
+ range: [12, 15]
+ },
+ range: [9, 15]
+ }
+ ],
+ "result": null,
+ range: [0, 16]
+ });
});
it('function type with optional rest param', function () {
- var type = doctrine.parseType("function(...a=)");
+ var type = doctrine.parseType("function(...a=)", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [
- {
- "type": "RestType",
- "expression": {
- "type": "OptionalType",
- "expression": {
- "type": "NameExpression",
- "name": "a"
- }
- }
- }
- ],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [
+ {
+ "type": "RestType",
+ "expression": {
+ "type": "OptionalType",
+ "expression": {
+ "type": "NameExpression",
+ "name": "a",
+ range: [12, 13]
+ },
+ range: [12, 14]
+ },
+ range: [9, 14]
+ }
+ ],
+ "result": null,
+ range: [0, 15]
+ });
});
it('function type with optional rest param name and type', function () {
- var type = doctrine.parseType("function(...a:b=)");
+ var type = doctrine.parseType("function(...a:b=)", {range: true});
type.should.eql({
- "type": "FunctionType",
- "params": [
- {
- "type": "RestType",
- "expression": {
- "type": "OptionalType",
- "expression": {
- "type": "ParameterType",
- "name": "a",
- "expression": {
- "type": "NameExpression",
- "name": "b"
- }
- }
- }
- }],
- "result": null
- });
+ "type": "FunctionType",
+ "params": [
+ {
+ "type": "RestType",
+ "expression": {
+ "type": "OptionalType",
+ "expression": {
+ "type": "ParameterType",
+ "name": "a",
+ "expression": {
+ "type": "NameExpression",
+ "name": "b",
+ range: [14, 15]
+ },
+ range: [12, 15]
+ },
+ range: [12, 16]
+ },
+ range: [9, 16]
+ }
+ ],
+ "result": null,
+ range: [0, 17]
+ });
});
it('string value in type', function () {
var type;
- type = doctrine.parseType("{'ok':String}");
+ type = doctrine.parseType("{'ok':String}", {range: true});
type.should.eql({
"fields": [
{
@@ -1689,14 +1743,17 @@ describe('parseType', function () {
"type": "FieldType",
"value": {
"name": "String",
- "type": "NameExpression"
- }
+ "type": "NameExpression",
+ range: [6, 12]
+ },
+ range: [1, 12]
}
],
- "type": "RecordType"
+ "type": "RecordType",
+ range: [0, 13]
});
- type = doctrine.parseType('{"\\r\\n\\t\\u2028\\x20\\u20\\b\\f\\v\\\r\n\\\n\\0\\07\\012\\o":String}');
+ type = doctrine.parseType('{"\\r\\n\\t\\u2028\\x20\\u20\\b\\f\\v\\\r\n\\\n\\0\\07\\012\\o":String}', {range: true});
type.should.eql({
"fields": [
{
@@ -1704,11 +1761,14 @@ describe('parseType', function () {
"type": "FieldType",
"value": {
"name": "String",
- "type": "NameExpression"
- }
+ "type": "NameExpression",
+ range: [46, 52]
+ },
+ range: [1, 52]
}
],
- "type": "RecordType"
+ "type": "RecordType",
+ range: [0, 53]
});
doctrine.parseType.bind(doctrine, "{'ok\":String}").should.throw('unexpected quote');
@@ -1718,7 +1778,7 @@ describe('parseType', function () {
it('number value in type', function () {
var type;
- type = doctrine.parseType("{20:String}");
+ type = doctrine.parseType("{20:String}", {range: true});
type.should.eql({
"fields": [
{
@@ -1726,11 +1786,14 @@ describe('parseType', function () {
"type": "FieldType",
"value": {
"name": "String",
- "type": "NameExpression"
- }
+ "type": "NameExpression",
+ range: [4, 10]
+ },
+ range: [1, 10]
}
],
- "type": "RecordType"
+ "type": "RecordType",
+ range: [0, 11]
});
type = doctrine.parseType("{.2:String, 30:Number, 0x20:String}");
@@ -1824,116 +1887,134 @@ describe('parseType', function () {
it('dotted type', function () {
var type;
- type = doctrine.parseType("Cocoa.Cappuccino");
+ type = doctrine.parseType("Cocoa.Cappuccino", {range: true});
type.should.eql({
"name": "Cocoa.Cappuccino",
- "type": "NameExpression"
+ "type": "NameExpression",
+ range: [0, 16]
});
});
it('rest array type', function () {
var type;
- type = doctrine.parseType("[string,...string]");
+ type = doctrine.parseType("[string,...string]", {range: true});
type.should.eql({
"elements": [
{
"name": "string",
- "type": "NameExpression"
+ "type": "NameExpression",
+ range: [1, 7]
},
{
"expression": {
"name": "string",
- "type": "NameExpression"
+ "type": "NameExpression",
+ range: [11, 17]
},
- "type": "RestType"
+ "type": "RestType",
+ range: [8, 17]
}
],
- "type": "ArrayType"
+ "type": "ArrayType",
+ range: [0, 18]
});
});
it ('nullable type', function () {
var type;
- type = doctrine.parseType("string?");
+ type = doctrine.parseType("string?", {range: true});
type.should.eql({
"expression": {
"name": "string",
- "type": "NameExpression"
+ "type": "NameExpression",
+ range: [0, 6]
},
"prefix": false,
- "type": "NullableType"
+ "type": "NullableType",
+ range: [0, 7]
});
});
it ('non-nullable type', function () {
var type;
- type = doctrine.parseType("string!");
+ type = doctrine.parseType("string!", {range: true});
type.should.eql({
"expression": {
"name": "string",
- "type": "NameExpression"
+ "type": "NameExpression",
+ range: [0, 6]
},
"prefix": false,
- "type": "NonNullableType"
+ "type": "NonNullableType",
+ range: [0, 7]
});
});
it ('toplevel multiple pipe type', function () {
var type;
- type = doctrine.parseType("string|number|Test");
+ type = doctrine.parseType("string|number|Test", {range: true});
type.should.eql({
"elements": [
{
"name": "string",
- "type": "NameExpression"
+ "type": "NameExpression",
+ range: [0, 6]
},
{
"name": "number",
- "type": "NameExpression"
+ "type": "NameExpression",
+ range: [7, 13]
},
{
"name": "Test",
- "type": "NameExpression"
+ "type": "NameExpression",
+ range: [14, 18]
}
],
- "type": "UnionType"
+ "type": "UnionType",
+ range: [0, 18]
});
});
it('string literal type', function () {
var type;
- type = doctrine.parseType('"Hello, World"');
+ type = doctrine.parseType('"Hello, World"', {range: true});
type.should.eql({
type: 'StringLiteralType',
- value: 'Hello, World'
+ value: 'Hello, World',
+ range: [0, 14]
});
});
it('numeric literal type', function () {
var type;
- type = doctrine.parseType('32');
+ type = doctrine.parseType('32', {range: true});
type.should.eql({
type: 'NumericLiteralType',
- value: 32
+ value: 32,
+ range: [0, 2]
});
- type = doctrine.parseType('-142.42');
+ type = doctrine.parseType('-142.42', {range: true});
type.should.eql({
type: 'NumericLiteralType',
- value: -142.42
+ value: -142.42,
+ range: [0, 7]
});
});
it('boolean literal type', function () {
var type;
- type = doctrine.parseType('true');
+ type = doctrine.parseType('true', {range: true});
type.should.eql({
type: 'BooleanLiteralType',
- value: true
+ value: true,
+ range: [0, 4]
});
- type = doctrine.parseType('false');
+ type = doctrine.parseType('false', {range: true});
type.should.eql({
type: 'BooleanLiteralType',
- value: false
+ value: false,
+ range: [0, 5]
});
});
@@ -1947,64 +2028,77 @@ describe('parseType', function () {
describe('parseParamType', function () {
it('question', function () {
- var type = doctrine.parseParamType("?");
+ var type = doctrine.parseParamType("?", {range: true});
type.should.eql({
- type: 'NullableLiteral'
+ type: 'NullableLiteral',
+ range: [0, 1]
});
});
it('question option', function () {
- var type = doctrine.parseParamType("?=");
+ var type = doctrine.parseParamType("?=", {range: true});
type.should.eql({
type: 'OptionalType',
expression: {
- type: 'NullableLiteral'
- }
+ type: 'NullableLiteral',
+ range: [0, 1]
+ },
+ range: [0, 2]
});
});
it('function option parameters former', function () {
- var type = doctrine.parseParamType("function(?, number)");
+ var type = doctrine.parseParamType("function(?, number)", {range: true});
type.should.eql({
type: 'FunctionType',
params: [{
- type: 'NullableLiteral'
+ type: 'NullableLiteral',
+ range: [9, 10]
}, {
type: 'NameExpression',
- name: 'number'
+ name: 'number',
+ range: [12, 18]
}],
- result: null
+ result: null,
+ range: [0, 19]
});
});
it('function option parameters latter', function () {
- var type = doctrine.parseParamType("function(number, ?)");
+ var type = doctrine.parseParamType("function(number, ?)", {range: true});
type.should.eql({
type: 'FunctionType',
params: [{
type: 'NameExpression',
- name: 'number'
+ name: 'number',
+ range: [9, 15]
}, {
- type: 'NullableLiteral'
+ type: 'NullableLiteral',
+ range: [17, 18]
}],
- result: null
+ result: null,
+ range: [0, 19]
});
});
it('function type union', function () {
- var type = doctrine.parseParamType("function(): ?|number");
+ var type = doctrine.parseParamType("function(): ?|number", {range: true});
type.should.eql({
type: 'UnionType',
elements: [{
type: 'FunctionType',
params: [],
result: {
- type: 'NullableLiteral'
- }
+ type: 'NullableLiteral',
+ range: [12, 13]
+ },
+ range: [0, 13]
}, {
type: 'NameExpression',
- name: 'number'
- }]
+ name: 'number',
+ range: [14, 20]
+ }],
+ range: [0, 20]
});
});
});
@@ -2365,6 +2459,102 @@ describe('optional params', function() {
res.tags[3].should.have.property('lineNumber', 5);
});
+ it('range', function() {
+ var res = doctrine.parse(
+ [
+ "/**",
+ " * foo",
+ " * @constructor",
+ " * @param {string} foo",
+ " * @returns {string}",
+ " *",
+ " * @example",
+ " * f('blah'); // => undefined",
+ " */"
+ ].join('\n'),
+ { unwrap: true, range: true }
+ );
+
+
+ res.should.eql({
+ description: 'foo',
+ tags: [
+ { title: "constructor", description: null, range: [14, 26], type: null, name: null },
+ { title: "param", description: null, range: [30, 49], type: { type: "NameExpression", name: "string", range: [38, 44] }, name: "foo" },
+ { title: "returns", description: null, range: [53, 70], type: { type: "NameExpression", name: "string", range: [63, 69] } },
+ { title: "example", description: "f('blah'); // => undefined", range: [77, 115] }
+ ]
+ });
+ });
+
+ it('range with nested types', function() {
+ var res = doctrine.parse("@param {{foo: string,bar: {baz: number}}} beep boop", { range: true });
+
+ res.should.eql({
+ description: '',
+ tags: [
+ {
+ title: "param",
+ description: "boop",
+ name: "beep",
+ type: {
+ type: "RecordType",
+ fields: [
+ {
+ type: "FieldType",
+ key: "foo",
+ value: {
+ type: "NameExpression",
+ name: "string",
+ range: [14, 20]
+ },
+ range: [9, 20]
+ },
+ {
+ type: "FieldType",
+ key: "bar",
+ value: {
+ type: "RecordType",
+ fields: [
+ {
+ type: "FieldType",
+ key: "baz",
+ value: {
+ type: "NameExpression",
+ name: "number",
+ range: [32, 38]
+ },
+ range: [27, 38]
+ }
+ ],
+ range: [26, 39]
+ },
+ range: [21, 39]
+ }
+ ],
+ range: [8, 40]
+ },
+ range: [0, 51]
+ }
+ ]
+ });
+ });
+
+ it('range reaching end of tag', function() {
+ var res = doctrine.parse("/**@example", { range: true, unwrap: true });
+
+ res.should.eql({
+ description: '',
+ tags: [
+ {
+ title: 'example',
+ description: '',
+ range: [3, 11]
+ }
+ ]
+ })
+ });
+
it('example caption', function() {
var res = doctrine.parse(
[
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-doctrine.git
More information about the Pkg-javascript-commits
mailing list