Skip to content

Commit

Permalink
feat(strip)!: support specifying both functions and labels (#471)
Browse files Browse the repository at this point in the history
* FIX: Now supports specifying both functions and labels in the same
config.
FIX: Supports spaces around the . for functions and : for labels
DOC: Updated documentation
REFACTOR: Adjust tests so that the input and expected output can be seen
next to each other.

* restoring test fixtures

* code review changes

* additional tests

* attempt to clean up filemodes

* revert subjective style change

* revert extra newline

* revert extra newlines

Co-authored-by: Andrew Powell <shellscape@users.noreply.github.com>
  • Loading branch information
dgkimpton and shellscape committed Jul 9, 2020
1 parent 56b3725 commit a014c66
Show file tree
Hide file tree
Showing 14 changed files with 327 additions and 23 deletions.
26 changes: 18 additions & 8 deletions packages/strip/README.md
Expand Up @@ -51,42 +51,52 @@ Then call `rollup` either via the [CLI](https://www.rollupjs.org/guide/en/#comma
### `include`

Type: `String | RegExp | Array[...String|RegExp]`<br>
Default: `['**/*.js']`
Default: `['**/*.js']`<br>
Example: `include: '**/*.(mjs|js)',`<br>

A pattern, or array of patterns, which specify the files in the build the plugin should operate on.

### `exclude`

Type: `String | RegExp | Array[...String|RegExp]`<br>
Default: `[]`
Default: `[]`<br>
Example: `exlude: 'tests/**/*',`<br>

A pattern, or array of patterns, which specify the files in the build the plugin should _ignore_.

### `debugger`

Type: `Boolean`<br>
Default: `true`
Default: `true`<br>
Example: `debugger: false,`<br>

If `true`, instructs the plugin to remove debugger statements.
If `true` instructs the plugin to remove debugger statements.

### `functions`

Type: `Array[...String]`<br>
Default: `[ 'console.*', 'assert.*' ]`
Default: `[ 'console.*', 'assert.*' ]`<br>
Example: `functions: [ 'console.log', 'MyClass.Test' ],`<br>

Specifies the functions that the plugin will target and remove.

_Note: specifying functions that are used at the begining of a chain, such as 'a().b().c()', will result in '(void 0).b().c()' which will generate an error at runtime._

### `labels`

Type: `Array[...String]`<br>
Default: `[]`
Default: `[]`<br>
Example: `labels: ['unittest'],`<br>

Specifies the [labeled blocks or statements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label) that the plugin will target and remove.

Specifies the [labeled blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label) that the plugin will target and remove.
_Note: the '**:**' is implied and should not be specified in the config._

### `sourceMap`

Type: `Boolean`<br>
Default: `true`
Default: `true`<br>
Example: `sourceMap: false,`<br>

If `true`, instructs the plugin to update source maps accordingly after removing configured targets from the bundle.

Expand Down
32 changes: 23 additions & 9 deletions packages/strip/src/index.js
Expand Up @@ -39,20 +39,30 @@ export default function strip(options = {}) {

const removeDebuggerStatements = options.debugger !== false;
const functions = (options.functions || ['console.*', 'assert.*']).map((keypath) =>
keypath.replace(/\./g, '\\.').replace(/\*/g, '\\w+')
keypath.replace(/\*/g, '\\w+').replace(/\./g, '\\s*\\.\\s*')
);

const labels = options.labels || [];

const firstpass = new RegExp(`\\b(?:${functions.join('|')}|debugger)\\b`);
const pattern = new RegExp(`^(?:${functions.join('|')})$`);
const labelsPatterns = labels.map((l) => `${l}\\s*:`);

const firstPass = [...functions, ...labelsPatterns];
if (removeDebuggerStatements) {
firstPass.push('debugger\\b');
}

const reFunctions = new RegExp(`^(?:${functions.join('|')})$`);
const reFirstpass = new RegExp(`\\b(?:${firstPass.join('|')})`);
const firstPassFilter = firstPass.length > 0 ? (code) => reFirstpass.test(code) : () => false;
const UNCHANGED = null;

return {
name: 'strip',

transform(code, id) {
if (!filter(id)) return null;
if (functions.length > 0 && !firstpass.test(code)) return null;
if (!filter(id) || !firstPassFilter(code)) {
return UNCHANGED;
}

let ast;

Expand Down Expand Up @@ -81,7 +91,7 @@ export default function strip(options = {}) {
if (parent.type === 'ExpressionStatement') {
removeStatement(parent);
} else {
magicString.overwrite(node.start, node.end, 'void 0');
magicString.overwrite(node.start, node.end, '(void 0)');
}

edited = true;
Expand All @@ -93,7 +103,7 @@ export default function strip(options = {}) {
if (isBlock(parent)) {
remove(node.start, node.end);
} else {
magicString.overwrite(node.start, node.end, 'void 0;');
magicString.overwrite(node.start, node.end, '(void 0);');
}

edited = true;
Expand All @@ -114,21 +124,25 @@ export default function strip(options = {}) {

if (removeDebuggerStatements && node.type === 'DebuggerStatement') {
removeStatement(node);
this.skip();
} else if (node.type === 'LabeledStatement') {
if (node.label && labels.includes(node.label.name)) {
removeStatement(node);
this.skip();
}
} else if (node.type === 'CallExpression') {
const keypath = flatten(node.callee);
if (keypath && pattern.test(keypath)) {
if (keypath && reFunctions.test(keypath)) {
removeExpression(node);
this.skip();
}
}
}
});

if (!edited) return null;
if (!edited) {
return UNCHANGED;
}

code = magicString.toString();
const map = sourceMap ? magicString.generateMap() : null;
Expand Down
9 changes: 9 additions & 0 deletions packages/strip/test/fixtures/excluded-not-changed/input.js
@@ -0,0 +1,9 @@
/* eslint-disable */
export default function foo() {
before();
debugger;
logging:
console.log('a');
console.error('b');
after();
}
4 changes: 4 additions & 0 deletions packages/strip/test/fixtures/functions-direct/input.js
@@ -0,0 +1,4 @@
/* eslint-disable */
before();
f().t();
after();
20 changes: 20 additions & 0 deletions packages/strip/test/fixtures/functions-spaced/input.js
@@ -0,0 +1,20 @@
/* eslint-disable */
before();
function f() {
return {
g: function () {
return {
hello: function () {
console.log('hello');
}
};
}
};
}

Test
.
f()
. g() .
hello();
after();
10 changes: 10 additions & 0 deletions packages/strip/test/fixtures/label-awkward-spacing/input.js
@@ -0,0 +1,10 @@
/* eslint-disable */
before();
unittest
: {
test('some test', (assert) => {
});
}
again();
unittest:console.log();
after();
2 changes: 2 additions & 0 deletions packages/strip/test/fixtures/label-expression/input.js
@@ -0,0 +1,2 @@
/* eslint-disable */
before();unittest:console.log();after();
10 changes: 10 additions & 0 deletions packages/strip/test/fixtures/label-multiple-times/input.js
@@ -0,0 +1,10 @@
/* eslint-disable */
before();
unittest
: {
test('some test', (assert) => {
});
}
again();
unittest:console.log();
after();
7 changes: 7 additions & 0 deletions packages/strip/test/fixtures/label-whitespace/input.js
@@ -0,0 +1,7 @@
/* eslint-disable */
before();
unittest : {
test('some test', (assert) => {
});
}
after();
2 changes: 2 additions & 0 deletions packages/strip/test/fixtures/lambda-void/input.js
@@ -0,0 +1,2 @@
/* eslint-disable */
console.log(['h', 'e', 'y'].forEach((letter) => console.warn(letter)))
9 changes: 9 additions & 0 deletions packages/strip/test/fixtures/no-changes/input.js
@@ -0,0 +1,9 @@
/* eslint-disable */
export default function foo() {
before();
debugger;
logging:
console.log('a');
console.error('b');
after();
}

0 comments on commit a014c66

Please sign in to comment.