Skip to content

Commit

Permalink
Convert to Babel plugin and add TypeScript types (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
NotWoods authored Jun 3, 2021
1 parent 09c0d37 commit e6bb8a9
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 82 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ jobs:
fail-fast: false
matrix:
node-version:
- 16
- 14
- 12
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
19 changes: 19 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {PluginObj, types} from '@babel/core';

/**
Strip `console`, `alert`, and `debugger` statements from JavaScript code.
@param babel - Babel instance. Passed automatically when using Babel.
@example
```
import {transformSync} from '@babel/core';
import stripDebug from 'strip-debug';
transformSync('function foo(){console.log("foo");alert("foo");debugger;}', {
plugins: [stripDebug]
}).code;
//=> 'function foo() { void 0;void 0; }'
```
*/
export default function stripDebugPlugin(babel: {readonly types: typeof types}): PluginObj;
51 changes: 27 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
'use strict';
const rocambole = require('rocambole');
const stripDebugger = require('rocambole-strip-debugger');
const stripConsole = require('rocambole-strip-console');
const stripAlert = require('rocambole-strip-alert');
const espree = require('espree');
const stripFunctionNameList = [
'alert',
'window.alert',
'console.log',
'window.console.log'
];

rocambole.parseFn = espree.parse;
rocambole.parseContext = espree;
rocambole.parseOptions = {
range: true,
tokens: true,
comment: true,
ecmaVersion: 2019,
ecmaFeatures: {
jsx: true,
globalReturn: false,
impliedStrict: false
}
};
export default function stripDebugPlugin({types}) {
return {
visitor: {
DebuggerStatement(path) {
path.remove();
},
CallExpression(path) {
const isMatched = stripFunctionNameList.some(functionName => {
const calleePath = path.get('callee');
if (calleePath.matchesPattern(functionName)) {
return !calleePath.node.computed;
}

module.exports = source => rocambole.moonwalk(source, node => {
stripDebugger(node);
stripConsole(node);
stripAlert(node);
});
return calleePath.node.name === functionName;
});
if (isMatched) {
path.replaceWith(types.unaryExpression('void', types.numericLiteral(0)));
}
}
}
};
}
13 changes: 6 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"email": "[email protected]",
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./index.js",
"engines": {
"node": ">=12"
},
Expand All @@ -32,17 +34,14 @@
"js",
"javascript",
"ast",
"esprima"
"babel-plugin"
],
"dependencies": {
"espree": "^7.3.1",
"rocambole": "^0.7.0",
"rocambole-strip-alert": "^1.0.0",
"rocambole-strip-console": "^2.0.0",
"rocambole-strip-debugger": "^1.0.1"
"@types/babel__core": "^7.1.14"
},
"devDependencies": {
"ava": "^2.4.0",
"@babel/core": "^7.14.3",
"ava": "^3.15.0",
"xo": "^0.38.2"
}
}
27 changes: 7 additions & 20 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,28 @@
Useful for making sure you didn't leave any logging in production code.

Also available as [Gulp](https://github.com/sindresorhus/gulp-strip-debug)/[Grunt](https://github.com/sindresorhus/grunt-strip-debug)/[Broccoli](https://github.com/sindresorhus/broccoli-strip-debug) plugins.

## Usage

```
$ npm install strip-debug
$ npm install @babel/core strip-debug
```

## Usage

```js
const stripDebug = require('strip-debug');
import {transformSync} from '@babel/core';
import stripDebug from 'strip-debug';

stripDebug('function foo(){console.log("foo");alert("foo");debugger;}').toString();
//=> 'function foo(){void 0;void 0;}'
transformSync('function foo(){console.log("foo");alert("foo");debugger;}', {
plugins: [stripDebug]
}).code;
//=> 'function foo() { void 0;void 0; }'
```

### API

## stripDebug(input)

Returns the modified [Esprima AST](http://esprima.org) which can be used to make additional modifications.

Call `.toString()` to get the stringified output.

To prevent any side-effects, `console.*`/`alert*` is replaced with `void 0` instead of being stripped.

If you shadow the `console` global with your own local variable, it will still be removed.

### input

Type: `string` `Object`

Pass in a string of JavaScript code or a [Esprima compatible AST](http://esprima.org).

## Related

- [strip-debug-cli](https://github.com/sindresorhus/strip-debug-cli) - API for this module
73 changes: 43 additions & 30 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,56 @@
import {transformAsync} from '@babel/core';
import test from 'ava';
import stripDebug from './index.js';
import stripDebugPlugin from './index.js';

test('strip debugger statement', t => {
t.is(stripDebug('function test(){debugger;}').toString(), 'function test(){}');
t.is(stripDebug('"use strict";debugger;foo()').toString(), '"use strict";foo()');
async function stripDebug(source) {
const {code} = await transformAsync(source, {
plugins: [stripDebugPlugin]
});
return code;
}

test('strip debugger statement', async t => {
t.is(await stripDebug('function test(){debugger;}'), 'function test() {}');
t.is(await stripDebug('"use strict";debugger;foo()'), '"use strict";\n\nfoo();');
});

test('strip console statement', t => {
t.is(stripDebug('function test(){console.log("foo");}').toString(), 'function test(){void 0;}');
t.is(stripDebug('function test(){window.console.log("foo");}').toString(), 'function test(){void 0;}');
t.is(stripDebug('var test = () => console.log("foo");').toString(), 'var test = () => void 0;');
t.is(stripDebug('"use strict";console.log("foo");foo()').toString(), '"use strict";void 0;foo()');
t.is(stripDebug('if(console){console.log("foo", "bar");}').toString(), 'if(console){void 0;}');
t.is(stripDebug('foo && console.log("foo");').toString(), 'foo && void 0;');
t.is(stripDebug('if (foo) console.log("foo")\nnextLine();').toString(), 'if (foo) void 0\nnextLine();');
t.is(stripDebug('function test(){console.log(...colors);}').toString(), 'function test(){void 0;}');
test('strip console statement', async t => {
t.is(await stripDebug('function test(){console.log("foo");}'), 'function test() {\n void 0;\n}');
t.is(await stripDebug('function test(){window.console.log("foo");}'), 'function test() {\n void 0;\n}');
t.is(await stripDebug('var test = () => console.log("foo");'), 'var test = () => void 0;');
t.is(await stripDebug('"use strict";console.log("foo");foo()'), '"use strict";\n\nvoid 0;\nfoo();');
t.is(await stripDebug('if(console){console.log("foo", "bar");}'), 'if (console) {\n void 0;\n}');
t.is(await stripDebug('foo && console.log("foo");'), 'foo && void 0;');
t.is(await stripDebug('if (foo) console.log("foo")\nnextLine();'), 'if (foo) void 0;\nnextLine();');
t.is(await stripDebug('function test(){console.log(...colors);}'), 'function test() {\n void 0;\n}');
});

test('strip alert statement', t => {
t.is(stripDebug('function test(){alert("foo");}').toString(), 'function test(){void 0;}');
t.is(stripDebug('function test(){window.alert("foo");}').toString(), 'function test(){void 0;}');
t.is(stripDebug('var test = () => alert("foo");').toString(), 'var test = () => void 0;');
t.is(stripDebug('"use strict";alert("foo");foo()').toString(), '"use strict";void 0;foo()');
t.is(stripDebug('if(alert){alert("foo", "bar");}').toString(), 'if(alert){void 0;}');
t.is(stripDebug('foo && alert("foo");').toString(), 'foo && void 0;');
t.is(stripDebug('if (foo) alert("foo")\nnextLine();').toString(), 'if (foo) void 0\nnextLine();');
test('strip alert statement', async t => {
t.is(await stripDebug('function test(){alert("foo");}'), 'function test() {\n void 0;\n}');
t.is(await stripDebug('function test(){window.alert("foo");}'), 'function test() {\n void 0;\n}');
t.is(await stripDebug('var test = () => alert("foo");'), 'var test = () => void 0;');
t.is(await stripDebug('"use strict";alert("foo");foo()'), '"use strict";\n\nvoid 0;\nfoo();');
t.is(await stripDebug('if(alert){alert("foo", "bar");}'), 'if (alert) {\n void 0;\n}');
t.is(await stripDebug('foo && alert("foo");'), 'foo && void 0;');
t.is(await stripDebug('if (foo) alert("foo")\nnextLine();'), 'if (foo) void 0;\nnextLine();');
});

test('never strip away non-debugging code', t => {
const fixture = 'var test = {\n getReadSections: function(){\n var readSections = window.localStorage.getItestripDebug(\'storyReadSections\') || \'[]\';\n return JSON.parse(readSections);\n }\n};';
t.is(stripDebug(fixture).toString(), fixture);
test('never strip away non-debugging code', async t => {
const fixture = `var test = {
getReadSections: function () {
var readSections = window.localStorage.getItestripDebug('storyReadSections') || '[]';
return JSON.parse(readSections);
}
};`;
t.is(await stripDebug(fixture), fixture);
});

test('shouldn\'t leak memory', t => {
t.notThrows(() => {
stripDebug('var obj = null; try { obj = \'something\'; } catch (e) { console.warn(\'NOPE!\'); }').toString();
});
test('shouldn\'t leak memory', async t => {
await t.notThrowsAsync(() =>
stripDebug('var obj = null; try { obj = \'something\'; } catch (e) { console.warn(\'NOPE!\'); }')
);
});

test('supports async functions', t => {
t.is(stripDebug('async function test(){debugger; await foo();}').toString(), 'async function test(){ await foo();}');
test('supports async functions', async t => {
t.is(await stripDebug('async function test(){debugger; await foo();}'), 'async function test() {\n await foo();\n}');
});

0 comments on commit e6bb8a9

Please sign in to comment.