Skip to content

Commit

Permalink
code refactoring, docs updates.
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaly-t committed Dec 31, 2015
1 parent 8eb7599 commit bb8feb9
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 155 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ var text = "var t; // comments";
decomment(text); //=> var t;
```

NOTE: Specifically for CSS, call `decomment.css(text, [options])` instead.

## Features

* Removes both single and multi-line comments from JSON, JavaScript and CSS
* Automatically recognizes HTML and removes all `<!-- comments -->` from it
* Does not change layout / formatting of the original document
* Removes lines that have only comments on them
* Compatible with JSON5 and ECMAScript 6
* Compatible with CSS3, JSON5 and ECMAScript 6

The library does not support mixed content - HTML with JavaScript or CSS in it.
Once the input code is recognized as HTML, only the HTML comments will be removed from it.
Expand All @@ -48,13 +50,12 @@ Once the input code is recognized as HTML, only the HTML comments will be remove

In terms of the performance, this library is as fast as it gets, in part because it makes no use of regular expressions.

For example, it churns through [AngularJS 1.5 Core](https://code.angularjs.org/1.5.0-rc.0/angular.js) (1.1MB ~ 30,000 lines of JavaScript) in under 40ms.
For example, it churns through [AngularJS 1.5 Core](https://code.angularjs.org/1.5.0-rc.0/angular.js) (1.1MB ~ 30,000 lines of JavaScript) in under 200ms.

## API

#### decomment(text, [options]) ⇒ String


##### options.trim ⇒ Boolean
* `false (default)` - do not trim comments
* `true` - remove empty lines that follow removed full-line comments
Expand All @@ -81,7 +82,11 @@ decomment(text, {safe: true}); //=> /*! special */ js code

This option has no effect when processing HTML.

#### decomment.css(text, [options]) ⇒ String

The same as **decomment**, but specific to CSS.

## License

Copyright © 2015 [Vitaly Tomilov](https://github.com/vitaly-t);
Copyright © 2016 [Vitaly Tomilov](https://github.com/vitaly-t);
Released under the MIT license.
157 changes: 157 additions & 0 deletions lib/core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
'use strict';

var utils = require('./utils');
var parser = require('./parser');
var EOL = require('os').EOL; // OS-dependent End-of-Line;

function decomment(text, options, css) {

if (typeof text !== 'string') {
throw new TypeError("Parameter 'text' must be a string.");
}

if (options !== undefined && typeof(options) !== 'object') {
throw new TypeError("Parameter 'options' must be an object.");
}

var idx = 0, // current index;
s = '', // resulting text;
len = text.length, // text length;
emptyLine = true, // set while no symbols encountered on the current line;
emptyLetters = '', // empty letters on a new line;
isHtml = false, // set when the input is recognized as HTML;
optTrim = options && options.trim, // 'trim' option;
optSafe = options && options.safe, // 'safe' option.
regEx = []; // regular expression details;

if (!len) {
return text;
}

if (!css) {
isHtml = utils.isHtml(text);
if (!isHtml) {
regEx = utils.regExAbsolute(text, parser(text));
}
}

do {
if (!isHtml && text[idx] === '/' && idx < len - 1 && (!idx || text[idx - 1] !== '\\')) {
if (text[idx + 1] === '/') {
if (utils.indexInRegEx(idx, regEx)) {
continue;
}
var lb = text.indexOf(EOL, idx + 2);
if (lb < 0) {
break;
}
if (emptyLine) {
emptyLetters = '';
idx = lb + EOL.length - 1; // last symbol of the line break;
trim();
} else {
idx = lb - 1; // just before the line break;
}
continue;
}

if (text[idx + 1] === '*') {
if (utils.indexInRegEx(idx, regEx)) {
continue;
}
var end = text.indexOf('*/', idx + 2);
var keep = optSafe && idx < len - 2 && text[idx + 2] === '!';
if (keep) {
if (end >= 0) {
s += text.substr(idx, end - idx + 2);
} else {
s += text.substr(idx, len - idx);
}
}
if (end < 0) {
break;
}
idx = end + 1;
if (emptyLine) {
emptyLetters = '';
if (!keep) {
var lb = text.indexOf(EOL, idx + 1);
if (lb > idx) {
idx = lb + EOL.length - 1; // last symbol of the line break;
trim();
}
}
}
continue;
}
}

if (isHtml && text[idx] === '<' && idx < len - 3 && text.substr(idx + 1, 3) === '!--') {
var end = text.indexOf('-->', idx + 4);
if (end < 0) {
break;
}
idx = end + 2;
if (emptyLine) {
emptyLetters = '';
var lb = text.indexOf(EOL, idx + 1);
if (lb > idx) {
idx = lb + EOL.length - 1; // last symbol of the line break;
trim();
}
}
continue;
}

var symbol = text[idx];
var isSpace = symbol === ' ' || symbol === '\t';
if (symbol === '\r' || symbol === '\n') {
if (text.indexOf(EOL, idx) === idx) {
emptyLine = true;
}
} else {
if (!isSpace) {
emptyLine = false;
s += emptyLetters;
emptyLetters = '';
}
}
if (emptyLine && isSpace) {
emptyLetters += symbol;
} else {
s += symbol;
}

if (!isHtml && (symbol === '\'' || symbol === '"' || symbol === '`')) {
var closeIdx = text.indexOf(symbol, idx + 1);
if (utils.indexInRegEx(idx, regEx)) {
continue;
}
if (closeIdx < 0) {
break;
}
s += text.substr(idx + 1, closeIdx - idx);
idx = closeIdx;
}

} while (++idx < len);

function trim() {
if (optTrim) {
var startIdx, endIdx, i;
do {
startIdx = idx + 1;
endIdx = text.indexOf(EOL, startIdx);
i = startIdx;
while ((text[i] === ' ' || text[i] === '\t') && ++i < endIdx);
if (i === endIdx) {
idx = endIdx + EOL.length - 1;
}
} while (i === endIdx);
}
}

return s;
}

module.exports = decomment;
159 changes: 8 additions & 151 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,156 +1,13 @@
'use strict';

var utils = require('./utils');
var parser = require('./parser');
var EOL = require('os').EOL; // OS-dependent End-of-Line;
var core = require('./core');

function decomment(text, options) {

if (typeof text !== 'string') {
throw new TypeError("Parameter 'text' must be a string.");
}

if (options !== undefined && typeof(options) !== 'object') {
throw new TypeError("Parameter 'options' must be an object.");
}

var idx = 0, // current index;
s = '', // resulting text;
len = text.length, // text length;
emptyLine = true, // set while no symbols encountered on the current line;
emptyLetters = '', // empty letters on a new line;
isHtml = false, // set when the input is recognized as HTML;
optTrim = options && options.trim, // 'trim' option;
optSafe = options && options.safe, // 'safe' option.
regEx; // regular expression details;

if (!len) {
return text;
}

isHtml = utils.isHtml(text);

if (!isHtml) {
regEx = utils.regExAbsolute(text, parser(text));
}

do {
if (!isHtml && text[idx] === '/' && idx < len - 1 && (!idx || text[idx - 1] !== '\\')) {
if (text[idx + 1] === '/') {
if (utils.indexInRegEx(idx, regEx)) {
continue;
}
var lb = text.indexOf(EOL, idx + 2);
if (lb < 0) {
break;
}
if (emptyLine) {
emptyLetters = '';
idx = lb + EOL.length - 1; // last symbol of the line break;
trim();
} else {
idx = lb - 1; // just before the line break;
}
continue;
}

if (text[idx + 1] === '*') {
if (utils.indexInRegEx(idx, regEx)) {
continue;
}
var end = text.indexOf('*/', idx + 2);
var keep = optSafe && idx < len - 2 && text[idx + 2] === '!';
if (keep) {
if (end >= 0) {
s += text.substr(idx, end - idx + 2);
} else {
s += text.substr(idx, len - idx);
}
}
if (end < 0) {
break;
}
idx = end + 1;
if (emptyLine) {
emptyLetters = '';
if (!keep) {
var lb = text.indexOf(EOL, idx + 1);
if (lb > idx) {
idx = lb + EOL.length - 1; // last symbol of the line break;
trim();
}
}
}
continue;
}
}

if (isHtml && text[idx] === '<' && idx < len - 3 && text.substr(idx + 1, 3) === '!--') {
var end = text.indexOf('-->', idx + 4);
if (end < 0) {
break;
}
idx = end + 2;
if (emptyLine) {
emptyLetters = '';
var lb = text.indexOf(EOL, idx + 1);
if (lb > idx) {
idx = lb + EOL.length - 1; // last symbol of the line break;
trim();
}
}
continue;
}

var symbol = text[idx];
var isSpace = symbol === ' ' || symbol === '\t';
if (symbol === '\r' || symbol === '\n') {
if (text.indexOf(EOL, idx) === idx) {
emptyLine = true;
}
} else {
if (!isSpace) {
emptyLine = false;
s += emptyLetters;
emptyLetters = '';
}
}
if (emptyLine && isSpace) {
emptyLetters += symbol;
} else {
s += symbol;
}

if (!isHtml && (symbol === '\'' || symbol === '"' || symbol === '`')) {
var closeIdx = text.indexOf(symbol, idx + 1);
if (utils.indexInRegEx(idx, regEx)) {
continue;
}
if (closeIdx < 0) {
break;
}
s += text.substr(idx + 1, closeIdx - idx);
idx = closeIdx;
}

} while (++idx < len);

function trim() {
if (optTrim) {
var startIdx, endIdx, i;
do {
startIdx = idx + 1;
endIdx = text.indexOf(EOL, startIdx);
i = startIdx;
while ((text[i] === ' ' || text[i] === '\t') && ++i < endIdx);
if (i === endIdx) {
idx = endIdx + EOL.length - 1;
}
} while (i === endIdx);
}
}

return s;
function main(text, options) {
return core(text, options, false);
}

module.exports = decomment;
main.css = function (text, options) {
return core(text, options, true);
};

module.exports = main;

0 comments on commit bb8feb9

Please sign in to comment.