doc-parser
Advanced tools
Comparing version 0.2.2 to 0.3.0
@@ -0,1 +1,39 @@ | ||
## [Version 0.3.0](https://github.com/glayzzle/docblock-parser/releases/tag/v0.3.0) (2017-1-9) | ||
### Major Changes | ||
- rewrite parser structure (xo++): [`edda0c4`](https://github.com/glayzzle/docblock-parser/commit/edda0c4) | ||
- start to define generic parsers for grammar: [`ffbe9c3`](https://github.com/glayzzle/docblock-parser/commit/ffbe9c3) | ||
- rename package: [`6b01724`](https://github.com/glayzzle/docblock-parser/commit/6b01724) | ||
- implement type, text & tests: [`7ff0b34`](https://github.com/glayzzle/docblock-parser/commit/7ff0b34) | ||
### Minor Changes | ||
- fix xo on tests: [`ddde5f8`](https://github.com/glayzzle/docblock-parser/commit/ddde5f8) | ||
- extract summary: [`1134c84`](https://github.com/glayzzle/docblock-parser/commit/1134c84) | ||
- add a backup function & implement float numbers: [`0802ad5`](https://github.com/glayzzle/docblock-parser/commit/0802ad5) | ||
- add new symbols: [`6216fe0`](https://github.com/glayzzle/docblock-parser/commit/6216fe0) | ||
- implement the variable reader: [`cf2eb94`](https://github.com/glayzzle/docblock-parser/commit/cf2eb94) | ||
- implement semver parser & deprecated block + test: [`afedeff`](https://github.com/glayzzle/docblock-parser/commit/afedeff) | ||
- implement object parsing: [`9861453`](https://github.com/glayzzle/docblock-parser/commit/9861453) | ||
### Patches | ||
- beautify: [`caa80e6`](https://github.com/glayzzle/docblock-parser/commit/caa80e6) | ||
- improve tests: [`2c8e479`](https://github.com/glayzzle/docblock-parser/commit/2c8e479) | ||
- fix lexer & cover with tests: [`0356720`](https://github.com/glayzzle/docblock-parser/commit/0356720) | ||
- fix tests: [`1064114`](https://github.com/glayzzle/docblock-parser/commit/1064114) | ||
- update badges: [`060206d`](https://github.com/glayzzle/docblock-parser/commit/060206d) | ||
- update badges: [`2d2422e`](https://github.com/glayzzle/docblock-parser/commit/2d2422e) | ||
- update coveralls token: [`6cd7ba1`](https://github.com/glayzzle/docblock-parser/commit/6cd7ba1) | ||
- up nodejs version: [`6677f79`](https://github.com/glayzzle/docblock-parser/commit/6677f79) | ||
- fix the backup state reverse: [`ca58ab2`](https://github.com/glayzzle/docblock-parser/commit/ca58ab2) | ||
- improve the documentation: [`a676169`](https://github.com/glayzzle/docblock-parser/commit/a676169) | ||
- fix point symbol / tests: [`897be4d`](https://github.com/glayzzle/docblock-parser/commit/897be4d) | ||
- rewrite next token eating: [`547b20f`](https://github.com/glayzzle/docblock-parser/commit/547b20f) | ||
- improve tests & fix array parsing: [`ecbe333`](https://github.com/glayzzle/docblock-parser/commit/ecbe333) | ||
- fix type parser & improve coverage: [`f17d295`](https://github.com/glayzzle/docblock-parser/commit/f17d295) | ||
[...full changes](https://github.com/glayzzle/docblock-parser/compare/v0.2.2...v0.3.0) | ||
## [Version 0.2.2](https://github.com/glayzzle/docblock-parser/releases/tag/v0.2.2) (2017-1-5) | ||
@@ -2,0 +40,0 @@ |
@@ -39,4 +39,14 @@ <!-- Generated by documentation.js. Update this documentation by updating the source code. --> | ||
**Parameters** | ||
- `state` | ||
Returns **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))** the previous token | ||
### state | ||
Revert back the current consumed token | ||
Returns **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))** the previous token | ||
### lex | ||
@@ -43,0 +53,0 @@ |
@@ -8,7 +8,16 @@ <!-- Generated by documentation.js. Update this documentation by updating the source code. --> | ||
- `lexer` | ||
- `grammar` | ||
**Properties** | ||
- `lexer` **[Lexer](#lexer)** | ||
- `lexer` **Lexer** | ||
### extendGrammar | ||
extending the grammar | ||
**Parameters** | ||
- `grammar` | ||
### parse | ||
@@ -24,50 +33,67 @@ | ||
## Lexer | ||
### parseAnnotation | ||
**Parameters** | ||
Parses a @annotation | ||
- `tokens` | ||
### parseGrammar | ||
**Properties** | ||
Parsing a rule | ||
- `text` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Current parsed text (attached to current token) | ||
- `offset` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Current offset | ||
- `token` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))** Current parsed token | ||
**Parameters** | ||
### read | ||
- `name` | ||
Initialize the lexer with specified text | ||
### parseRule | ||
Parsing a rule | ||
**Parameters** | ||
- `input` | ||
- `rule` | ||
### input | ||
### parseType | ||
Consumes a char | ||
Check if current token can be a type | ||
Returns **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** | ||
```ebnf | ||
type ::= '\\'? T_STRING ('\\' T_STRING) * | ||
parseType ::= type | | ||
type '[' (type (',' type)*)? ']' | | ||
type '<' (type (',' type)*)? '>' | ||
``` | ||
### unput | ||
### parseVarName | ||
Revert back the current consumed char | ||
Reads a variable name | ||
Returns **void** | ||
### parseText | ||
### unlex | ||
Parsing an entire line string | ||
Revert back the current consumed token | ||
### parseVersion | ||
Returns **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))** the previous token | ||
Reads a version informations | ||
### lex | ||
```ebnf | ||
parseVersion ::= T_NUM ('.' T_NUM ('.' T_NUM ('-' T_STRING)?)?)? | ||
``` | ||
Consumes the next token (ignores whitespaces) | ||
### parseArray | ||
Returns **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))** the current token | ||
Parses an array | ||
### next | ||
### parseBoolean | ||
Eats a token (see lex for public usage) including whitespace | ||
Parses a boolean value | ||
Returns **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))** the current token | ||
### parseNumber | ||
Parses a number | ||
### parseString | ||
Parses an email | ||
### parseStatement | ||
Parses a T_STRING statement |
@@ -5,2 +5,6 @@ <!-- Generated by documentation.js. Update this documentation by updating the source code. --> | ||
**Parameters** | ||
- `grammar` | ||
**Properties** | ||
@@ -7,0 +11,0 @@ |
{ | ||
"name": "doc-parser", | ||
"version": "0.2.2", | ||
"version": "0.3.0", | ||
"description": "Parses docblocks comments", | ||
@@ -19,3 +19,6 @@ "main": "src/index.js", | ||
"files": "test/*.js", | ||
"envs": ["node", "mocha"] | ||
"envs": [ | ||
"node", | ||
"mocha" | ||
] | ||
} | ||
@@ -49,2 +52,2 @@ ] | ||
} | ||
} | ||
} |
# DocBlock & Annotations Parser | ||
[![npm version](https://badge.fury.io/js/docblock-parser.svg)](https://www.npmjs.com/package/parsedoc) | ||
[![Build Status](https://travis-ci.org/glayzzle/docblock-parser.svg?branch=master)](https://travis-ci.org/glayzzle/docblock-parser) | ||
[![Coverage Status](https://coveralls.io/repos/github/glayzzle/docblock-parser/badge.svg?branch=master)](https://coveralls.io/github/glayzzle/docblock-parser?branch=master) | ||
[![npm version](https://badge.fury.io/js/doc-parser.svg)](https://www.npmjs.com/package/doc-parser) | ||
[![Build Status](https://travis-ci.org/glayzzle/doc-parser.svg?branch=master)](https://travis-ci.org/glayzzle/doc-parser) | ||
[![Coverage Status](https://coveralls.io/repos/github/glayzzle/doc-parser/badge.svg?branch=master)](https://coveralls.io/github/glayzzle/doc-parser?branch=master) | ||
[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo) | ||
@@ -75,4 +75,50 @@ [![Gitter](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/glayzzle/Lobby) | ||
# Declaring custom doc blocks | ||
By default, `doc-parser` supports `@return`,`@param`,`@throws` and `@deprecated` | ||
doc blocks. | ||
You can extend the support to any doc block : | ||
```js | ||
// lets handle @global (type) (var) (description) | ||
var DocParser = require('doc-parser'); | ||
var reader = new DocParser({ | ||
'global': [ | ||
{ | ||
property: 'type', | ||
parser: 'type', | ||
optional: true | ||
}, | ||
{ | ||
property: 'what', | ||
parser: 'variable', | ||
optional: true | ||
}, | ||
{ | ||
property: 'description', | ||
parser: 'text', | ||
optional: true, | ||
default: '' | ||
} | ||
] | ||
}); | ||
var data = reader.parse('/** @global string some description */'); | ||
``` | ||
This will result in a new kind of doc block with the specified properties. Here | ||
a list of supported parsers : | ||
- type : a simple type, class name, or array of types | ||
- variable : a variable name | ||
- text : a line of text (will eat every token until the current line ends) | ||
- version: a semantic version | ||
- array : an array of items | ||
- object : a json object definition | ||
- boolean : a boolean | ||
- number : a number (integer or float) | ||
- string : a simple or double quoted text | ||
# Misc | ||
This library is released under BSD-3 license clause. |
@@ -20,3 +20,3 @@ /*! | ||
var lexerSymbols = [ | ||
',', '=', ':', '(', ')', '[', ']', '{', '}', '@', '"', '\'' | ||
',', '=', ':', '(', ')', '[', ']', '{', '}', '@', '"', '\'', '\\', '<', '>', '$', '-', '.' | ||
]; | ||
@@ -88,2 +88,3 @@ | ||
} | ||
this.backup = null; | ||
if (state) { | ||
@@ -94,4 +95,6 @@ this.offset = state.offset; | ||
this.line = state.line; | ||
if (state.backup) { | ||
this.backup = state.backup; | ||
} | ||
} | ||
this.backup = null; | ||
return this.token; | ||
@@ -109,3 +112,4 @@ }; | ||
token: this.token, | ||
line: this.line | ||
line: this.line, | ||
backup: this.backup | ||
}; | ||
@@ -126,2 +130,3 @@ }; | ||
} | ||
// console.log(this.line, this.text); | ||
return this.token; | ||
@@ -149,2 +154,8 @@ }; | ||
} else if (lexerSymbols.indexOf(ch) > -1) { | ||
if (ch === '.') { | ||
var nCh = this._input[this.offset].charCodeAt(0); | ||
if (nCh > 47 && nCh < 58) { | ||
return this.readNumber(); | ||
} | ||
} | ||
if (ch === ':') { | ||
@@ -151,0 +162,0 @@ ch = '=>'; // alias |
@@ -41,3 +41,2 @@ /*! | ||
variable: this.parseVarName, | ||
name: this.parseVarName, // alias of variable | ||
text: this.parseText, | ||
@@ -62,3 +61,3 @@ version: this.parseVersion, | ||
property: 'name', | ||
parser: 'name', | ||
parser: 'variable', | ||
optional: true | ||
@@ -69,3 +68,4 @@ }, | ||
parser: 'text', | ||
optional: true | ||
optional: true, | ||
default: '' | ||
}], | ||
@@ -76,3 +76,3 @@ return: [{ | ||
optional: true, | ||
default: 'void' | ||
default: false | ||
}, | ||
@@ -82,3 +82,4 @@ { | ||
parser: 'text', | ||
optional: true | ||
optional: true, | ||
default: '' | ||
}], | ||
@@ -100,3 +101,8 @@ throws: [{ | ||
optional: true, | ||
default: 'latest' | ||
default: { | ||
major: 0, | ||
minor: 0, | ||
patch: 0, | ||
label: null | ||
} | ||
}, | ||
@@ -186,3 +192,2 @@ { | ||
} | ||
this.token = this.lexer.lex(); | ||
} | ||
@@ -193,2 +198,3 @@ return ast; | ||
Parser.prototype.parseTopStatement = function () { | ||
var value; | ||
if (this.token === this.lexer._t.T_STRING) { | ||
@@ -198,11 +204,15 @@ return this.parseStatement(); | ||
// found a text | ||
value = this.lexer.text; | ||
this.token = this.lexer.lex(); | ||
return { | ||
kind: 'text', | ||
value: this.lexer.text | ||
value: value | ||
}; | ||
} else if (this.token === this.lexer._t.T_NUM) { | ||
// number | ||
value = this.lexer.text; | ||
this.token = this.lexer.lex(); | ||
return { | ||
kind: 'number', | ||
value: this.lexer.text | ||
value: parseFloat(value) | ||
}; | ||
@@ -237,12 +247,14 @@ } else if (this.token === '[') { | ||
if (this.token === this.lexer._t.T_STRING) { | ||
var line = this.lexer.backup.line; | ||
type = this.lexer.text.toLowerCase(); | ||
var line = this.lexer.line; | ||
this.token = this.lexer.lex(); // eat | ||
this.token = this.lexer.lex(); // eat the tag name | ||
// grammar specific annotation | ||
if (this.grammar[type]) { | ||
var backup = this.lexer.state(); | ||
result = this.parseGrammar(type); | ||
if (result) { | ||
if (result !== null) { | ||
return result; | ||
} | ||
this.token = this.lexer.unlex(backup); | ||
} | ||
@@ -276,3 +288,2 @@ | ||
} | ||
this.token = this.lexer.lex(); | ||
} | ||
@@ -282,4 +293,2 @@ } | ||
} | ||
// ignore it | ||
this.token = this.lexer.unlex(); | ||
return null; | ||
@@ -308,5 +317,7 @@ }; | ||
if (typeof this.parsers[rule.parser] === 'function') { | ||
var backup = this.lexer.state(); | ||
var result = this.parsers[rule.parser].apply(this, []); | ||
if (result === null) { | ||
if (rule.default) { | ||
this.lexer.unlex(backup); | ||
if (typeof rule.default !== 'undefined') { | ||
return rule.default; | ||
@@ -321,2 +332,239 @@ } | ||
/** | ||
* Check if current token can be a type | ||
* ```ebnf | ||
* type ::= '\\'? T_STRING ('\\' T_STRING) * | ||
* parseType ::= type | | ||
* type '[' (type (',' type)*)? ']' | | ||
* type '<' (type (',' type)*)? '>' | ||
* ``` | ||
*/ | ||
Parser.prototype.parseType = function () { | ||
var result = { | ||
kind: 'type', | ||
fqn: false, | ||
name: '' | ||
}; | ||
if (this.token === '\\') { | ||
result.fqn = true; | ||
this.token = this.lexer.lex(); | ||
} | ||
if (this.token !== this.lexer._t.T_STRING) { | ||
return null; | ||
} | ||
while (this.token === this.lexer._t.T_STRING) { | ||
result.name += this.lexer.text; | ||
this.token = this.lexer.lex(); // eat | ||
if (this.token === '\\') { | ||
result.name += '\\'; | ||
this.token = this.lexer.lex(); // eat && continue | ||
} else if (this.token === '[') { | ||
// collection | ||
result = { | ||
kind: 'collection', | ||
value: result, | ||
index: this.parseListOfTypes(']') | ||
}; | ||
if (result.index === null) { | ||
return null; | ||
} | ||
break; | ||
} else if (this.token === '<') { | ||
// template class | ||
result = { | ||
kind: 'class', | ||
class: result, | ||
parameters: this.parseListOfTypes('>') | ||
}; | ||
if (result.parameters === null) { | ||
return null; | ||
} | ||
break; | ||
} else { | ||
break; | ||
} | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Parse a list of type | ||
* @private | ||
*/ | ||
Parser.prototype.parseListOfTypes = function (charEnd) { | ||
var result = []; | ||
this.token = this.lexer.lex(); // eat && continue | ||
if (this.token === charEnd) { | ||
this.token = this.lexer.lex(); // eat && continue | ||
} else { | ||
var indexType = this.parseType(); | ||
if (indexType !== null) { | ||
result.push(indexType); | ||
while (this.token === ',') { | ||
this.token = this.lexer.lex(); // eat && continue | ||
indexType = this.parseType(); | ||
if (indexType !== null) { | ||
result.push(indexType); | ||
} | ||
} | ||
} | ||
if (this.token === charEnd) { | ||
this.token = this.lexer.lex(); // eat && continue | ||
} | ||
} | ||
return result; | ||
}; | ||
/** | ||
* Reads a variable name | ||
*/ | ||
Parser.prototype.parseVarName = function () { | ||
if (this.token === '$') { | ||
this.token = this.lexer.lex(); // eat && continue | ||
if (this.token === this.lexer._t.T_STRING) { | ||
var result = this.lexer.text; | ||
this.token = this.lexer.lex(); // eat && continue | ||
return result; | ||
} | ||
} | ||
return null; | ||
}; | ||
/** | ||
* Parsing an entire line string | ||
*/ | ||
Parser.prototype.parseText = function () { | ||
if (this.token !== this.lexer._t.T_STRING) { | ||
return null; | ||
} | ||
var line = this.lexer.backup.line; | ||
var offset = this.lexer.backup.offset; | ||
while (this.token !== this.lexer._t.EOF) { | ||
this.token = this.lexer.lex(); // eat && continue | ||
if (this.lexer.line !== line) { | ||
this.lexer.unlex(); | ||
break; | ||
} | ||
} | ||
var result = this.lexer._input.substring(offset, this.lexer.offset).trim(); | ||
this.token = this.lexer.lex(); // eat && continue | ||
return result; | ||
}; | ||
/** | ||
* Reads a version informations | ||
* ```ebnf | ||
* parseVersion ::= T_NUM ('.' T_NUM ('.' T_NUM ('-' T_STRING)?)?)? | ||
* ``` | ||
*/ | ||
Parser.prototype.parseVersion = function () { | ||
var version = { | ||
major: 0, | ||
minor: 0, | ||
patch: 0, | ||
label: null | ||
}; | ||
if (this.token !== this.lexer._t.T_NUM) { | ||
return null; | ||
} | ||
// PARSE THE NUMERIC PART | ||
var v = this.lexer.text; | ||
this.token = this.lexer.lex(); // eat && continue | ||
if (this.token === this.lexer._t.T_NUM) { | ||
v += this.lexer.text; | ||
this.token = this.lexer.lex(); // eat && continue | ||
} | ||
// EAT THE LABEL | ||
if (this.token === '-') { | ||
this.token = this.lexer.lex(); // eat && continue | ||
if (this.token === this.lexer._t.T_STRING) { | ||
version.label = this.lexer.text; | ||
this.token = this.lexer.lex(); // eat && continue | ||
if (this.token === this.lexer._t.T_NUM) { | ||
version.label += this.lexer.text; | ||
this.token = this.lexer.lex(); // eat && continue | ||
} | ||
} | ||
} | ||
// READ THE VERSION | ||
v = v.split('.'); | ||
version.major = parseInt(v[0], 10); | ||
if (v.length > 1) { | ||
version.minor = parseInt(v[1], 10); | ||
if (v.length > 2) { | ||
version.patch = parseInt(v[2], 10); | ||
} | ||
} | ||
return version; | ||
}; | ||
/** | ||
* Parses an array | ||
*/ | ||
Parser.prototype.parseArray = function () { | ||
if (this.token === '[') { | ||
return this.readArray(']'); | ||
} else if (this.lexer.text.toLowerCase() === 'array') { | ||
this.token = this.lexer.lex(); | ||
if (this.token === '(') { | ||
return this.readArray(')'); | ||
} | ||
} | ||
return null; | ||
}; | ||
/** | ||
* Parse an object | ||
*/ | ||
Parser.prototype.parseObject = function () { | ||
if (this.token === '{') { | ||
return this.readJson(); | ||
} | ||
return null; | ||
}; | ||
/** | ||
* Parses a boolean value | ||
*/ | ||
Parser.prototype.parseBoolean = function () { | ||
if (this.token === this.lexer._t.T_STRING) { | ||
var word = this.lexer.text.toLowerCase(); | ||
this.token = this.lexer.lex(); | ||
if (word === 'true') { | ||
return true; | ||
} else if (word === 'false') { | ||
return false; | ||
} | ||
} | ||
return null; | ||
}; | ||
/** | ||
* Parses a number | ||
*/ | ||
Parser.prototype.parseNumber = function () { | ||
if (this.token === this.lexer._t.T_NUM) { | ||
var word = this.lexer.text; | ||
this.token = this.lexer.lex(); | ||
return parseFloat(word); | ||
} | ||
return null; | ||
}; | ||
/** | ||
* Parses an email | ||
*/ | ||
Parser.prototype.parseString = function () { | ||
if (this.token === this.lexer._t.T_TEXT) { | ||
var text = this.lexer.text.substring(1, this.lexer.text.length - 1); | ||
this.token = this.lexer.lex(); | ||
return text; | ||
} | ||
return null; | ||
}; | ||
/** | ||
* Parses a T_STRING statement | ||
@@ -327,2 +575,3 @@ */ | ||
if (word === 'true') { | ||
this.token = this.lexer.lex(); | ||
return { | ||
@@ -333,2 +582,3 @@ kind: 'boolean', | ||
} else if (word === 'false') { | ||
this.token = this.lexer.lex(); | ||
return { | ||
@@ -339,2 +589,3 @@ kind: 'boolean', | ||
} else if (word === 'null') { | ||
this.token = this.lexer.lex(); | ||
return { | ||
@@ -351,6 +602,5 @@ kind: 'null' | ||
} | ||
this.token = this.lexer.unlex(); | ||
return { | ||
kind: 'word', | ||
value: this.lexer.text | ||
value: this.lexer.backup.text | ||
}; | ||
@@ -368,3 +618,3 @@ } | ||
name: name, | ||
value: this.getJsonValue(this.body()) | ||
value: this.getJsonValue(this.parseTopStatement()) | ||
}; | ||
@@ -387,3 +637,2 @@ } else if (this.token === '(') { | ||
} | ||
this.token = this.lexer.unlex(); | ||
return { | ||
@@ -397,25 +646,17 @@ kind: 'word', | ||
var result = []; | ||
this.token = this.lexer.lex(); // consume start char | ||
do { | ||
this.token = this.lexer.lex(); // consume start char | ||
var item = this.body(); | ||
var item = this.parseTopStatement(); | ||
if (item !== null) { // ignore | ||
this.token = this.lexer.lex(); | ||
item = this.getJsonValue(item); | ||
if (this.token === '=>') { | ||
this.token = this.lexer.lex(); // eat | ||
item = { | ||
kind: 'key', | ||
name: item, | ||
value: this.getJsonValue( | ||
this.parseTopStatement() | ||
) | ||
}; | ||
this.token = this.lexer.lex(); // eat | ||
} | ||
result.push(item); | ||
if (this.token !== ',') { | ||
this.token = this.lexer.unlex(); | ||
break; | ||
} | ||
result.push(item); | ||
this.token = this.lexer.lex(); | ||
} | ||
} while (this.token !== endChar && this.token !== this.lexer._t.T_EOF); | ||
if (this.token === endChar) { | ||
this.token = this.lexer.lex(); | ||
} | ||
return result; | ||
@@ -426,8 +667,9 @@ }; | ||
var result = {}; | ||
this.token = this.lexer.lex(); | ||
do { | ||
this.token = this.lexer.lex(); | ||
var item = this.parseTopStatement(); | ||
if (item !== null) { // ignore | ||
this.token = this.lexer.lex(); // eat | ||
if (this.token === '=>') { | ||
if (item.kind === 'key') { | ||
result[item.name] = item.value; | ||
} else if (this.token === '=>') { | ||
item = this.getJsonKey(item); | ||
@@ -440,10 +682,12 @@ if (item !== null) { | ||
} | ||
this.token = this.lexer.lex(); | ||
} | ||
if (this.token !== ',') { | ||
this.token = this.lexer.unlex(); | ||
break; | ||
} | ||
this.token = this.lexer.lex(); | ||
} | ||
} while (this.token !== '}' && this.token !== this.lexer._t.T_EOF); | ||
this.token = this.lexer.lex(); | ||
if (this.token === '}') { | ||
this.token = this.lexer.lex(); | ||
} | ||
return result; | ||
@@ -483,3 +727,3 @@ }; | ||
} else if (ast.kind === 'number') { | ||
result = JSON.parse(ast[1]); | ||
result = JSON.parse(ast.value); | ||
} else if (ast.kind === 'word' || ast.kind === 'boolean') { | ||
@@ -486,0 +730,0 @@ result = ast.value; |
@@ -14,3 +14,3 @@ /*! | ||
var reader = new Lexer(tokens); | ||
describe('Test windows lines', function () { | ||
it('Test windows lines', function () { | ||
reader.read([ | ||
@@ -36,3 +36,3 @@ 'hello', | ||
}); | ||
describe('Test mac lines', function () { | ||
it('Test mac lines', function () { | ||
reader.read([ | ||
@@ -51,3 +51,3 @@ 'hello', | ||
}); | ||
describe('Test unlex', function () { | ||
it('Test unlex', function () { | ||
reader.read([ | ||
@@ -83,3 +83,3 @@ 'hello', | ||
}); | ||
describe('Test float', function () { | ||
it('Test float', function () { | ||
reader.read('1.2.3'); | ||
@@ -91,3 +91,3 @@ reader.lex().should.be.exactly(tokens.T_NUM); | ||
}); | ||
describe('Test assign', function () { | ||
it('Test assign', function () { | ||
reader.read('foo => a, bar: b'); | ||
@@ -102,3 +102,3 @@ reader.lex().should.be.exactly(tokens.T_STRING); | ||
}); | ||
describe('Test text', function () { | ||
it('Test text', function () { | ||
reader.read('\'aze\\\'rty\''); | ||
@@ -105,0 +105,0 @@ reader.lex().should.be.exactly(tokens.T_TEXT); |
@@ -11,3 +11,40 @@ /*! | ||
describe('Test parser', function () { | ||
var doc = new DocBlockParser(); | ||
var doc = new DocBlockParser({ | ||
boolean: [ | ||
{ | ||
property: 'value', | ||
parser: 'boolean' | ||
} | ||
], | ||
array: [ | ||
{ | ||
property: 'value', | ||
parser: 'array' | ||
} | ||
], | ||
number: [ | ||
{ | ||
property: 'value', | ||
parser: 'number' | ||
} | ||
], | ||
string: [ | ||
{ | ||
property: 'value', | ||
parser: 'string' | ||
} | ||
], | ||
text: [ | ||
{ | ||
property: 'value', | ||
parser: 'text' | ||
} | ||
], | ||
object: [ | ||
{ | ||
property: 'value', | ||
parser: 'object' | ||
} | ||
] | ||
}); | ||
@@ -32,16 +69,43 @@ it('extend grammar', function () { | ||
' * Description', | ||
' * @test 123 1.23', | ||
' * @test 123 1.23 null', | ||
' */' | ||
].join('\n')); | ||
].join('\r\n')); | ||
ast.body[0].type.should.be.exactly('test'); | ||
ast.body[0].options.length.should.be.exactly(2); | ||
ast.body[0].options.length.should.be.exactly(3); | ||
ast.body[0].options[0].kind.should.be.exactly('number'); | ||
ast.body[0].options[0].value.should.be.exactly('123'); | ||
ast.body[0].options[0].value.should.be.exactly(123); | ||
ast.body[0].options[1].kind.should.be.exactly('number'); | ||
ast.body[0].options[1].value.should.be.exactly('1.23'); | ||
ast.body[0].options[1].value.should.be.exactly(1.23); | ||
ast.body[0].options[2].kind.should.be.exactly('null'); | ||
}); | ||
it('test rule', function () { | ||
it('test array', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @test [1, 2, a => b]', | ||
' */' | ||
].join('\r\n')); | ||
ast.body[0].type.should.be.exactly('test'); | ||
ast.body[0].options.length.should.be.exactly(1); | ||
ast.body[0].options[0].kind.should.be.exactly('array'); | ||
// @todo console.log(ast.body[0].options[0]); | ||
}); | ||
it('test boolean', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @test true false', | ||
' */' | ||
].join('\r\n')); | ||
ast.body[0].type.should.be.exactly('test'); | ||
ast.body[0].options.length.should.be.exactly(2); | ||
ast.body[0].options[0].kind.should.be.exactly('boolean'); | ||
ast.body[0].options[0].value.should.be.exactly(true); | ||
ast.body[0].options[1].kind.should.be.exactly('boolean'); | ||
ast.body[0].options[1].value.should.be.exactly(false); | ||
}); | ||
it('test return rule', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * Description', | ||
@@ -52,4 +116,211 @@ ' * @return void Some extra informations', | ||
ast.body[0].kind.should.be.exactly('return'); | ||
console.log(ast.body[0]); | ||
ast.body[0].what.kind.should.be.exactly('type'); | ||
ast.body[0].what.name.should.be.exactly('void'); | ||
ast.body[0].description.should.be.exactly('Some extra informations'); | ||
}); | ||
it('test return optional values', function () { | ||
var ast = doc.parse('/* @return \\Foo\\Bar[] */'); | ||
ast.body[0].kind.should.be.exactly('return'); | ||
ast.body[0].what.kind.should.be.exactly('collection'); | ||
ast.body[0].what.value.kind.should.be.exactly('type'); | ||
ast.body[0].what.value.name.should.be.exactly('Foo\\Bar'); | ||
ast.body[0].what.value.fqn.should.be.exactly(true); | ||
ast.body[0].description.should.be.exactly(''); | ||
}); | ||
it('test return defaults', function () { | ||
var ast = doc.parse('/* @return */'); | ||
ast.body[0].kind.should.be.exactly('return'); | ||
ast.body[0].what.should.be.exactly(false); | ||
ast.body[0].description.should.be.exactly(''); | ||
}); | ||
it('test param', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * Description', | ||
' * @param String $var Foo is Bar', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('param'); | ||
ast.body[0].type.name.should.be.exactly('String'); | ||
ast.body[0].name.should.be.exactly('var'); | ||
ast.body[0].description.should.be.exactly('Foo is Bar'); | ||
}); | ||
it('test param defaults', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * Description', | ||
' * @param String Foo is Bar', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('param'); | ||
ast.body[0].type.name.should.be.exactly('String'); | ||
should.equal(ast.body[0].name, null); | ||
ast.body[0].description.should.be.exactly('Foo is Bar'); | ||
}); | ||
it('test deprecated', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @deprecated 13.223.314-beta.5', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('deprecated'); | ||
ast.body[0].version.major.should.be.exactly(13); | ||
ast.body[0].version.minor.should.be.exactly(223); | ||
ast.body[0].version.patch.should.be.exactly(314); | ||
ast.body[0].version.label.should.be.exactly('beta.5'); | ||
}); | ||
it('test deprecated options', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @deprecated Foo', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('deprecated'); | ||
ast.body[0].description.should.be.exactly('Foo'); | ||
}); | ||
it('test boolean', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @boolean true', | ||
' * @boolean false', | ||
' * @boolean', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('boolean'); | ||
ast.body[0].value.should.be.exactly(true); | ||
ast.body[1].kind.should.be.exactly('boolean'); | ||
ast.body[1].value.should.be.exactly(false); | ||
ast.body[2].kind.should.be.exactly('boolean'); | ||
should.equal(ast.body[2].value, null); | ||
}); | ||
it('test number', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @number 123', | ||
' * @number 1.23', | ||
' * @number', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('number'); | ||
ast.body[0].value.should.be.exactly(123); | ||
ast.body[1].kind.should.be.exactly('number'); | ||
ast.body[1].value.should.be.exactly(1.23); | ||
ast.body[2].kind.should.be.exactly('number'); | ||
should.equal(ast.body[2].value, null); | ||
}); | ||
it('test string', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @string "azerty"', | ||
' * @string \'azerty\'', | ||
' * @string', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('string'); | ||
ast.body[0].value.should.be.exactly('azerty'); | ||
ast.body[1].kind.should.be.exactly('string'); | ||
ast.body[1].value.should.be.exactly('azerty'); | ||
ast.body[2].kind.should.be.exactly('string'); | ||
should.equal(ast.body[2].value, null); | ||
}); | ||
it('test array', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @array [1, 2, 3]', | ||
' * @array array(4, 5, 6)', | ||
' * @array', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('array'); | ||
ast.body[0].value.should.be.eql([1, 2, 3]); | ||
ast.body[1].kind.should.be.exactly('array'); | ||
ast.body[1].value.should.be.eql([4, 5, 6]); | ||
ast.body[2].kind.should.be.exactly('array'); | ||
should.equal(ast.body[2].value, null); | ||
}); | ||
it('test object', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @object { foo: 1 }', | ||
' * @object { "bar": false }', | ||
' * @object', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('object'); | ||
ast.body[0].value.should.be.eql({foo: 1}); | ||
ast.body[1].kind.should.be.exactly('object'); | ||
ast.body[1].value.should.be.eql({bar: false}); | ||
ast.body[2].kind.should.be.exactly('object'); | ||
should.equal(ast.body[2].value, null); | ||
}); | ||
it('test getJsonValue', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @object { foo: { bar: false }, "key": [1, 2, 3] }', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('object'); | ||
ast.body[0].value.should.be.eql({foo: {bar: false}, key: [1, 2, 3]}); | ||
}); | ||
it('test readArray', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @array [foo => bar, 1, 2, array]', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('array'); | ||
ast.body[0].value.should.be.eql([ | ||
{ | ||
kind: 'key', | ||
name: 'foo', | ||
value: 'bar' | ||
}, | ||
1, | ||
2, | ||
'array' | ||
]); | ||
}); | ||
it('test parseListOfTypes', function () { | ||
var ast = doc.parse([ | ||
'/**', | ||
' * @return String[Number, Number]', | ||
' * @return Iterable<String, Foo>', | ||
' */' | ||
].join('\n')); | ||
ast.body[0].kind.should.be.exactly('return'); | ||
ast.body[0].what.should.be.eql({ | ||
index: [ | ||
{ | ||
fqn: false, | ||
kind: 'type', | ||
name: 'Number' | ||
}, | ||
{ | ||
fqn: false, | ||
kind: 'type', | ||
name: 'Number' | ||
} | ||
], | ||
kind: 'collection', | ||
value: { | ||
fqn: false, | ||
kind: 'type', | ||
name: 'String' | ||
} | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
76056
23
1847
124