extract-comments
Advanced tools
Comparing version 0.8.4 to 0.8.5
284
index.js
@@ -8,194 +8,102 @@ 'use strict'; | ||
/** | ||
* Get the first block comment from the given string | ||
* Extract comments from the given `string`. | ||
* | ||
* ```js | ||
* extract(str, options); | ||
* ``` | ||
* @param {String} `string` | ||
* @param {Object} `options` Pass `first: true` to return after the first comment is found. | ||
* @return {String} | ||
* @api public | ||
*/ | ||
function first(str) { | ||
function comments(str, options, fn) { | ||
if (typeof str !== 'string') { | ||
throw new TypeError('expected a string'); | ||
} | ||
str = utils.normalize(str); | ||
if (!/^\/\*{1,2}!?/.test(str)) { | ||
return null; | ||
} | ||
var i = str.indexOf('*/'); | ||
if (i === -1) return null; | ||
if (/['"\w]/.test(str[i + 2])) { | ||
return null; | ||
} | ||
return str.slice(0, i + 2); | ||
return block(str, options, fn) | ||
.concat(line(str, options, fn)) | ||
.sort(compare); | ||
} | ||
/** | ||
* Get block and line comments from the given string | ||
* Extract block comments from the given `string`. | ||
* | ||
* ```js | ||
* extract.block(str, options); | ||
* ``` | ||
* @param {String} `string` | ||
* @param {Object} `options` Pass `first: true` to return after the first comment is found. | ||
* @return {String} | ||
* @api public | ||
*/ | ||
function comments(str, options, fn) { | ||
if (typeof str !== 'string') { | ||
throw new TypeError('expected a string'); | ||
} | ||
function block(str, options, fn) { | ||
return factory('/*', '*/', Block)(str, options, fn); | ||
} | ||
if (typeof options === 'function') { | ||
fn = options; | ||
options = {}; | ||
} | ||
if (typeof fn !== 'function') { | ||
fn = utils.identity; | ||
} | ||
var ranges = utils.getRanges(str); | ||
var opts = extend({}, options); | ||
str = utils.normalize(str); | ||
var arr = []; | ||
var start = findStart('/*'); | ||
var end = findEnd('*/'); | ||
var len = str.length; | ||
var startIdx = start(str, 0); | ||
var endIdx = 0, prevIdx; | ||
while (startIdx !== -1 && endIdx < len) { | ||
endIdx = end(str, startIdx, len); | ||
if (endIdx === -1) break; | ||
var quoted = utils.isQuotedString(startIdx, ranges); | ||
if (quoted) { | ||
startIdx = endIdx; | ||
continue; | ||
} | ||
if (typeof prevIdx === 'number' && opts.line !== false) { | ||
if (typeof opts.combine === 'undefined') { | ||
opts.combine = true; | ||
} | ||
var nonblock = str.slice(prevIdx, startIdx); | ||
var lineComments = line(nonblock, opts, fn); | ||
arr = arr.concat(lineComments); | ||
} | ||
var comment = fn(new Block(str, startIdx, endIdx)); | ||
arr.push(comment); | ||
if (opts.first && arr.length === 1) { | ||
return arr; | ||
} | ||
prevIdx = endIdx + 2; | ||
startIdx = start(str, prevIdx); | ||
if (startIdx >= len) break; | ||
} | ||
if (!arr.length) { | ||
return line(str, opts, fn); | ||
} | ||
return arr; | ||
} | ||
/** | ||
* Get block comments from the given string | ||
* Extract line comments from the given `string`. | ||
* | ||
* ```js | ||
* extract.line(str, options); | ||
* ``` | ||
* @param {String} `string` | ||
* @param {Object} `options` Pass `first: true` to return after the first comment is found. | ||
* @return {String} | ||
* @api public | ||
*/ | ||
function block(str, fn) { | ||
if (typeof str !== 'string') { | ||
throw new TypeError('expected a string'); | ||
} | ||
return comments(str, {line: false}, fn); | ||
function line(str, options, fn) { | ||
return factory('//', '\n', Line)(str, options, fn); | ||
} | ||
/** | ||
* Get line comments from the given string | ||
* Factory for extracting comments from a string. | ||
* | ||
* @param {String} `string` | ||
* @return {String} | ||
*/ | ||
function line(str, options, fn) { | ||
if (typeof str !== 'string') { | ||
throw new TypeError('expected a string'); | ||
} | ||
function factory(open, close, Ctor) { | ||
return function(str, options, fn) { | ||
if (typeof str !== 'string') { | ||
throw new TypeError('expected a string'); | ||
} | ||
str = utils.normalize(str); | ||
var comments = []; | ||
if (typeof options === 'function') { | ||
fn = options; | ||
options = {}; | ||
} | ||
if (typeof fn !== 'function') { | ||
fn = utils.identity; | ||
} | ||
var ranges = utils.getRanges(str); | ||
var opts = extend({}, options); | ||
var combine = opts.combine === true; | ||
var start = findStart('//'); | ||
var end = findEnd('\n'); | ||
var len = str.length; | ||
var startIdx = start(str, 0); | ||
var endIdx = 0, prev; | ||
var stacked = null; | ||
while (startIdx !== -1 && endIdx < len) { | ||
if (startIdx >= len || endIdx >= len) { | ||
break; | ||
if (typeof options === 'function') { | ||
fn = options; | ||
options = {}; | ||
} | ||
endIdx = end(str, startIdx, len); | ||
if (endIdx === -1) { | ||
endIdx = len; | ||
if (typeof fn !== 'function') { | ||
fn = utils.identity; | ||
} | ||
var quoted = utils.isQuotedString(startIdx, ranges); | ||
var comment = new Line(str, startIdx, endIdx); | ||
var opts = extend({}, options); | ||
str = utils.normalize(str); | ||
str = utils.escapeQuoted(str); | ||
startIdx = start(str, endIdx); | ||
if (quoted) { | ||
startIdx = endIdx + 1; | ||
continue; | ||
var res = []; | ||
var start = str.indexOf(open); | ||
var end = str.indexOf(close, start); | ||
var len = str.length; | ||
if (end === -1) { | ||
end = len; | ||
} | ||
if (prev && combine && isStacked(comment, prev, opts)) { | ||
var curr = comment.loc.end.line; | ||
var last = comments[comments.length - 1]; | ||
prev = merge(str, comment, prev); | ||
if (last && prev.start === last.start) { | ||
comments.pop(); | ||
while (start !== -1 && end <= len) { | ||
var comment = fn(new Ctor(str, start, end, open, close)); | ||
res.push(comment); | ||
if (opts.first && res.length === 1) { | ||
return res; | ||
} | ||
prev.loc.start.line = curr; | ||
stacked = prev; | ||
continue; | ||
start = str.indexOf(open, end + 1); | ||
end = str.indexOf(close, start); | ||
if (end === -1) { | ||
end = len; | ||
} | ||
} | ||
if (stacked) { | ||
comments.push(fn(stacked)); | ||
stacked = null; | ||
} | ||
comment = fn(comment); | ||
prev = comment; | ||
comments.push(comment); | ||
} | ||
if (stacked) { | ||
comments.push(fn(stacked)); | ||
} | ||
return comments; | ||
} | ||
/** | ||
* Returns a function for getting the index the | ||
* given "end" character(s) | ||
* | ||
* @param {String} endChars | ||
*/ | ||
function findStart(startChars) { | ||
return function(str, idx) { | ||
var i = str.indexOf(startChars, idx); | ||
var prev = str[i - 1]; | ||
if (prev && /['"\w]/.test(prev)) { | ||
i = str.indexOf(startChars, i + 1); | ||
prev = str[i - 1]; | ||
} | ||
return i; | ||
return res; | ||
}; | ||
@@ -205,38 +113,30 @@ } | ||
/** | ||
* Returns a function for getting the index the | ||
* given "end" character(s) | ||
* Extract the first comment from the given `string`. | ||
* | ||
* @param {String} endChars | ||
* @param {String} `string` | ||
* @param {Object} `options` Pass `first: true` to return after the first comment is found. | ||
* @return {String} | ||
* @api public | ||
*/ | ||
function findEnd(endChars) { | ||
return function(str, start) { | ||
var idx = str.indexOf(endChars, start + 2); | ||
var ch = str[idx + 2]; | ||
while (ch && /['"]/.test(ch)) { | ||
idx = str.indexOf(endChars, idx + 2); | ||
ch = str[idx + 2]; | ||
} | ||
return idx; | ||
}; | ||
} | ||
function first(str) { | ||
if (typeof str !== 'string') { | ||
throw new TypeError('expected a string'); | ||
} | ||
/** | ||
* Returns true if the previous line was a line comment. | ||
*/ | ||
function isStacked(comment, prev) { | ||
var prevLine = prev.loc.start.line; | ||
var line = comment.loc.end.line; | ||
return line === prevLine + 1; | ||
var arr = comments(str, {first: true}); | ||
if (arr && arr.length) { | ||
return arr[0].raw; | ||
} else { | ||
return null; | ||
} | ||
} | ||
/** | ||
* Merge line comments | ||
* Utility for sorting line and block comments into | ||
* the correct order. | ||
*/ | ||
function merge(str, curr, prev) { | ||
var i = prev.loc.start.pos; | ||
var end = curr.loc.end.pos; | ||
return new Line(str, i, end); | ||
function compare(a, b) { | ||
return a.loc.start.pos - b.loc.start.pos; | ||
} | ||
@@ -267,1 +167,7 @@ | ||
module.exports.line = line; | ||
/** | ||
* Expose `extract.factory` method | ||
*/ | ||
module.exports.factory = factory; |
@@ -6,9 +6,20 @@ 'use strict'; | ||
function Comment(str, i, end) { | ||
var value = str.slice(i, end + 2); | ||
var lineno = str.slice(0, i).split('\n').length; | ||
var rawLines = value.split('\n'); | ||
var linesLen = rawLines.length; | ||
var lines = utils.strip(value.slice(2, -2).split('\n')); | ||
/** | ||
* Create a new BlockComment with: | ||
* - `str` the entire string | ||
* - `idx` the starting index of the comment | ||
* - `end` the ending index of the comment | ||
* - `open` the opening character(s) of the comment | ||
* - `close` the closing character(s) of the comment | ||
*/ | ||
function BlockComment(str, idx, end, open, close) { | ||
var ol = open.length; | ||
var cl = close.length; | ||
var lineno = utils.linesCount(str, idx); | ||
var value = utils.restore(str.slice(idx, end + cl)); | ||
var inner = value.slice(ol, -cl); | ||
var lines = utils.strip(inner.split('\n')); | ||
this.type = 'block'; | ||
@@ -18,13 +29,18 @@ this.raw = value; | ||
this.lines = lines; | ||
this.loc = { | ||
start: { | ||
line: lineno, | ||
pos: i | ||
pos: idx | ||
}, | ||
end: { | ||
line: lineno + linesLen - 1, | ||
pos: end + 2 | ||
line: lineno + utils.linesCount(value) - 1, | ||
pos: end + cl | ||
} | ||
}; | ||
/** | ||
* Add code context | ||
*/ | ||
this.code = new Code(str, this); | ||
@@ -34,5 +50,5 @@ } | ||
/** | ||
* expose `Comment` | ||
* expose `BlockComment` | ||
*/ | ||
module.exports = Comment; | ||
module.exports = BlockComment; |
'use strict'; | ||
var codeContext = require('parse-code-context'); | ||
var utils = require('./utils'); | ||
function Code(str, comment) { | ||
str = utils.restore(str); | ||
var start = comment.loc.end.pos; | ||
var endLine = comment.loc.end.line; | ||
var orig = str; | ||
var lineno = comment.loc.end.line + 1; | ||
var ctx = {}; | ||
str = str.slice(start); | ||
var slen = str.length, idx = -1; | ||
var chars, lines = 0; | ||
while (++idx < slen) { | ||
var ch = str[idx]; | ||
if (ch === '\n') { | ||
++lines; | ||
continue; | ||
} | ||
if (!/[\W\s]/.test(ch)) { | ||
chars = idx; | ||
var lines = str.split('\n').slice(lineno); | ||
for (var i = 0; i < lines.length; i++) { | ||
var res = codeContext(lines[i], lineno + i); | ||
if (res) { | ||
ctx = res; | ||
lineno += i; | ||
break; | ||
@@ -24,15 +22,13 @@ } | ||
start += chars; | ||
var next = orig.indexOf('\n', start); | ||
var code = orig.slice(start); | ||
var codeLine = code.slice(0, next); | ||
var lineno = endLine + lines - 1; | ||
var val = ctx.original || ''; | ||
var pos = str.slice(start).indexOf(val) + start; | ||
return { | ||
context: ctx, | ||
line: lineno, | ||
loc: { | ||
start: { line: lineno, pos: start }, | ||
end: { line: lineno, pos: next } | ||
start: { line: lineno, pos: pos }, | ||
end: { line: lineno, pos: pos + val.length } | ||
}, | ||
value: codeLine.trim(), | ||
value: val.trim() | ||
}; | ||
@@ -39,0 +35,0 @@ } |
'use strict'; | ||
function LineComment(str, i, end) { | ||
var value = str.slice(i, end); | ||
var lineno = str.slice(0, i).split('\n').length; | ||
var rawLines = value.split('\n'); | ||
var linesLen = rawLines.length; | ||
var utils = require('./utils'); | ||
/** | ||
* Create a new LineComment with: | ||
* - `str` the entire string | ||
* - `idx` the starting index of the comment | ||
* - `end` the ending index of the comment | ||
* - `open` the opening character(s) of the comment (e.g. '//') | ||
* - `close` the closing character(s) of the comment (e.g. '\n') | ||
*/ | ||
function LineComment(str, idx, end, open, close) { | ||
var lineno = utils.linesCount(str, idx); | ||
var value = utils.restore(str.slice(idx, end)); | ||
this.type = 'line'; | ||
this.raw = value; | ||
value = value.replace(/^\s*[\/\s]+/, ''); | ||
this.value = value.split(/\n\/\//).join('\n'); | ||
this.value = this.raw.replace(/^\s*[\/\s]+/, ''); | ||
@@ -17,6 +25,6 @@ this.loc = { | ||
line: lineno, | ||
pos: i | ||
pos: idx | ||
}, | ||
end: { | ||
line: lineno + linesLen - 1, | ||
line: lineno + utils.linesCount(value) - 1, | ||
pos: end | ||
@@ -23,0 +31,0 @@ } |
@@ -5,6 +5,4 @@ 'use strict'; | ||
var bom = require('strip-bom-string'); | ||
var quotesRe = require('quoted-string-regex'); | ||
var repeat = require('repeat-string'); | ||
var range = require('to-regex-range'); | ||
var cache = {}; | ||
var quotesRegex = require('quoted-string-regex'); | ||
var nonchar = require('noncharacters'); | ||
@@ -35,2 +33,58 @@ /** | ||
/** | ||
* Get the total number of lines from the start | ||
* of a string to the given index. | ||
*/ | ||
utils.linesCount = function(str, i) { | ||
if (typeof i === 'number') { | ||
return str.slice(0, i).split('\n').length; | ||
} | ||
return str.split('\n').length; | ||
}; | ||
/** | ||
* Utility for getting a sequence of non-characters. The | ||
* goal is to return a non-character string that is the | ||
* same length as the characters we're replacing. | ||
* | ||
* http://www.unicode.org/faq/private_use.html#noncharacters | ||
*/ | ||
function ch(num) { | ||
return nonchar[num] + nonchar[num]; | ||
} | ||
/** | ||
* Escaped comment characters in quoted strings | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
*/ | ||
utils.escapeQuoted = function(str) { | ||
return str.replace(quotesRegex(), function(val) { | ||
val = val.split('//').join(ch(0)); | ||
val = val.split('/*').join(ch(1)); | ||
val = val.split('*/').join(ch(2)); | ||
return val; | ||
}); | ||
}; | ||
/** | ||
* Restore comment characters in quoted strings | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
*/ | ||
utils.restore = function(str) { | ||
return str.replace(quotesRegex(), function(val) { | ||
val = val.split(ch(0)).join('//'); | ||
val = val.split(ch(1)).join('/*'); | ||
val = val.split(ch(2)).join('*/'); | ||
return val; | ||
}); | ||
}; | ||
/** | ||
* Strip stars from the beginning of each comment line, | ||
@@ -56,38 +110,1 @@ * and strip whitespace from the end of each line. We | ||
}; | ||
utils.getRanges = function (str) { | ||
if (cache[str]) return cache[str]; | ||
var re = quotesRe(); | ||
var ranges = []; | ||
var m; | ||
while (m = re.exec(str)) { | ||
var regex = utils.toRange(m.index, m.index + m[0].length); | ||
ranges.push({ | ||
regex: regex, | ||
index: m.index, | ||
match: m, | ||
}); | ||
} | ||
cache[str] = ranges; | ||
return ranges; | ||
}; | ||
utils.toRange = function (a, b) { | ||
return new RegExp(range(a, b)); | ||
}; | ||
utils.isQuotedString = function (num, ranges) { | ||
var len = ranges.length, i = -1; | ||
if (len === 0) return false; | ||
var m; | ||
while (++i < len) { | ||
var range = ranges[i]; | ||
var re = range.regex; | ||
if (re.test(num.toString())) { | ||
return range; | ||
} | ||
} | ||
return false; | ||
}; |
{ | ||
"name": "extract-comments", | ||
"description": "Extract code comments from string or from a glob of files.", | ||
"version": "0.8.4", | ||
"version": "0.8.5", | ||
"homepage": "https://github.com/jonschlinkert/extract-comments", | ||
"author": "Jon Schlinkert (https://github.com/jonschlinkert)", | ||
"repository": "jonschlinkert/extract-comments", | ||
"bugs": { | ||
"url": "https://github.com/jonschlinkert/extract-comments/issues" | ||
}, | ||
"bugs": "https://github.com/jonschlinkert/extract-comments/issues", | ||
"license": "MIT", | ||
@@ -27,11 +25,13 @@ "files": [ | ||
"extend-shallow": "^2.0.1", | ||
"noncharacters": "^1.1.0", | ||
"parse-code-context": "^0.1.3", | ||
"quoted-string-regex": "^0.1.1", | ||
"repeat-string": "^1.5.2", | ||
"strip-bom-string": "^0.1.2", | ||
"to-regex-range": "^0.1.1" | ||
"strip-bom-string": "^0.1.2" | ||
}, | ||
"devDependencies": { | ||
"code-context": "^0.5.0", | ||
"gulp": "^3.9.0", | ||
"gulp-eslint": "^1.0.0", | ||
"gulp-istanbul": "^0.10.2", | ||
"gulp-mocha": "^2.1.3", | ||
"mocha": "*", | ||
"parse-code-context": "^0.1.3", | ||
"should": "*" | ||
@@ -53,3 +53,2 @@ }, | ||
"related": { | ||
"description": "", | ||
"list": [ | ||
@@ -59,3 +58,4 @@ "parse-comments", | ||
"esprima-extract-comments" | ||
] | ||
], | ||
"description": "" | ||
}, | ||
@@ -62,0 +62,0 @@ "deps": { |
@@ -41,2 +41,62 @@ # extract-comments [![NPM version](https://badge.fury.io/js/extract-comments.svg)](http://badge.fury.io/js/extract-comments) | ||
## API | ||
### [comments](index.js#L20) | ||
Extract comments from the given `string`. | ||
**Params** | ||
* `string` **{String}** | ||
* `options` **{Object}**: Pass `first: true` to return after the first comment is found. | ||
* `returns` **{String}** | ||
**Example** | ||
```js | ||
extract(str, options); | ||
``` | ||
### [block](index.js#L41) | ||
Extract block comments from the given `string`. | ||
**Params** | ||
* `string` **{String}** | ||
* `options` **{Object}**: Pass `first: true` to return after the first comment is found. | ||
* `returns` **{String}** | ||
**Example** | ||
```js | ||
extract.block(str, options); | ||
``` | ||
### [line](index.js#L57) | ||
Extract line comments from the given `string`. | ||
**Params** | ||
* `string` **{String}** | ||
* `options` **{Object}**: Pass `first: true` to return after the first comment is found. | ||
* `returns` **{String}** | ||
**Example** | ||
```js | ||
extract.line(str, options); | ||
``` | ||
### [first](index.js#L120) | ||
Extract the first comment from the given `string`. | ||
**Params** | ||
* `string` **{String}** | ||
* `options` **{Object}**: Pass `first: true` to return after the first comment is found. | ||
* `returns` **{String}** | ||
## Related | ||
@@ -50,5 +110,5 @@ | ||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/jonschlinkert/extract-comments/issues/new). | ||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](/new). | ||
## Run tests | ||
## Tests | ||
@@ -61,2 +121,21 @@ Install dev dependencies: | ||
### Run tests | ||
Install dev dependencies: | ||
```sh | ||
$ npm i -d && npm test | ||
``` | ||
### Coverage | ||
As of November 04, 2015: | ||
```sh | ||
Statements : 100% (133/133) | ||
Branches : 100% (32/32) | ||
Functions : 100% (19/19) | ||
Lines : 100% (132/132) | ||
``` | ||
## Author | ||
@@ -76,2 +155,2 @@ | ||
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on November 02, 2015._ | ||
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on November 04, 2015._ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
14184
152
6
336
2
1
+ Addednoncharacters@^1.1.0
+ Addedparse-code-context@^0.1.3
+ Addednoncharacters@1.1.0(transitive)
+ Addedparse-code-context@0.1.3(transitive)
- Removedrepeat-string@^1.5.2
- Removedto-regex-range@^0.1.1
- Removedis-buffer@1.1.6(transitive)
- Removedis-number@2.1.0(transitive)
- Removedkind-of@3.2.2(transitive)
- Removedrepeat-string@1.6.1(transitive)
- Removedto-regex-range@0.1.3(transitive)