Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add keepClassName as separate options (fix #298) #311

Merged
merged 3 commits into from Dec 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -69,3 +69,4 @@ require("babel-core").transform("code", {

+ `keepFnName` - prevent plugin from removing function name. Useful for code depending on `fn.name`
+ `keepFnArgs` - prevent plugin from removing function args. Useful for code depending on `fn.length`
+ `keepClassName` - prevent mangler from altering class names.
Expand Up @@ -1292,12 +1292,12 @@ describe("dce-plugin", () => {
expect(transform(source)).toBe(expected);
});

it("should preserve fn/class names when keepFnName is true", () => {
it("should preserve fn names when keepFnName is true", () => {
const source = unpad(`
(function () {
function A() {}
exports.A = A;
var B = class B {};
var B = function B() {};
exports.B = B;
onClick(function C() {});
})();
Expand All @@ -1306,13 +1306,34 @@ describe("dce-plugin", () => {
(function () {
exports.A = function A() {};

exports.B = class B {};
exports.B = function B() {};
onClick(function C() {});
})();
`);
expect(transform(source, { keepFnName: true })).toBe(expected);
});

it("should preserve class names when keepClassName is true", () => {
const source = unpad(`
(function () {
class A {}
exports.A = A;
var B = class B {};
exports.B = B;
class AA {} new AA()
})();
`);
const expected = unpad(`
(function () {
exports.A = class A {};

exports.B = class B {};
new class AA {}();
})();
`);
expect(transform(source, { keepClassName: true })).toBe(expected);
});

// NCE = Named Class Expressions
it("should remove name from NCE", () => {
const source = unpad(`
Expand Down
Expand Up @@ -636,12 +636,19 @@ module.exports = ({ types: t, traverse }) => {

// Remove named function expression name. While this is dangerous as it changes
// `function.name` all minifiers do it and hence became a standard.
"FunctionExpression|ClassExpression"(path) {
"FunctionExpression"(path) {
if (!this.keepFnName) {
removeUnreferencedId(path);
}
},

// remove class names
"ClassExpression"(path) {
if (!this.keepClassName) {
removeUnreferencedId(path);
}
},

// Put the `var` in the left if feasible.
ForInStatement(path) {
const left = path.get("left");
Expand Down Expand Up @@ -696,6 +703,7 @@ module.exports = ({ types: t, traverse }) => {
// set defaults
optimizeRawSize = false,
keepFnName = false,
keepClassName = false,
keepFnArgs = false,
} = {}
} = {}) {
Expand All @@ -707,6 +715,7 @@ module.exports = ({ types: t, traverse }) => {
functionToBindings: new Map(),
optimizeRawSize,
keepFnName,
keepClassName,
keepFnArgs,
});
}
Expand Down
1 change: 1 addition & 0 deletions packages/babel-plugin-minify-mangle-names/README.md
Expand Up @@ -71,3 +71,4 @@ require("babel-core").transform("code", {
+ `blacklist` - A plain JS Object with keys as identifier names and values indicating whether to exclude
+ `eval` - mangle identifiers in scopes accessible by eval
+ `keepFnName` - prevent mangler from altering function names. Useful for code depending on `fn.name`
+ `keepClassName` - prevent mangler from altering class names.
Expand Up @@ -756,11 +756,9 @@ describe("mangle-names", () => {
expect(actual).toBe(expected);
});

it("should NOT mangle functions & classes when keepFnName is true", () => {
it("should NOT mangle functions when keepFnName is true", () => {
const source = unpad(`
(function() {
class Foo {}
const Bar = class Bar extends Foo {}
var foo = function foo() {
foo();
}
Expand All @@ -774,22 +772,46 @@ describe("mangle-names", () => {
`);
const expected = unpad(`
(function () {
class Foo {}
const a = class Bar extends Foo {};
var b = function foo() {
var a = function foo() {
foo();
};
function bar() {
b();
a();
}
bar();
var c = b;
c();
var b = a;
b();
})();
`);
expect(transform(source, {keepFnName: true})).toBe(expected);
});

it("should NOT mangle classes when keepClassName is true", () => {
const source = unpad(`
(function() {
class Foo {}
const Bar = class Bar extends Foo {}
var foo = class Baz {}
function bar() {
new foo();
}
bar();
})();
`);
const expected = unpad(`
(function () {
class Foo {}
const b = class Bar extends Foo {};
var c = class Baz {};
function a() {
new c();
}
a();
})();
`);
expect(transform(source, {keepClassName: true})).toBe(expected);
});

it("should mangle variable re-declaration / K violations", () => {
const source = unpad(`
!function () {
Expand Down
12 changes: 10 additions & 2 deletions packages/babel-plugin-minify-mangle-names/src/index.js
Expand Up @@ -5,12 +5,14 @@ module.exports = ({ types: t }) => {
constructor(charset, program, {
blacklist = {},
keepFnName = false,
keepClassName = false,
eval: _eval = false
} = {}) {
this.charset = charset;
this.program = program;
this.blacklist = blacklist;
this.keepFnName = keepFnName;
this.keepClassName = keepClassName;
this.eval = _eval;

this.unsafeScopes = new Set;
Expand Down Expand Up @@ -127,6 +129,8 @@ module.exports = ({ types: t }) => {
|| mangler.isBlacklist(oldName)
// function names
|| (mangler.keepFnName ? isFunction(binding.path) : false)
// class names
|| (mangler.keepClassName ? isClass(binding.path) : false)
) {
continue;
}
Expand Down Expand Up @@ -280,8 +284,12 @@ class Charset {
// for keepFnName
function isFunction(path) {
return path.isFunctionExpression()
|| path.isFunctionDeclaration()
|| path.isClassExpression()
|| path.isFunctionDeclaration();
}

// for keepClassName
function isClass(path) {
return path.isClassExpression()
|| path.isClassDeclaration();
}

Expand Down
Expand Up @@ -56,13 +56,15 @@ Object {
exports[`preset-options should handle options that are delegated to multiple other options 1`] = `
Object {
"input": Object {
"keepClassName": false,
"keepFnName": false,
},
"output": Array [
"babel-plugin-minify-constant-folding",
Array [
"babel-plugin-minify-dead-code-elimination",
Object {
"keepClassName": false,
"keepFnName": false,
},
],
Expand All @@ -74,6 +76,7 @@ Object {
Array [
"babel-plugin-minify-mangle-names",
Object {
"keepClassName": false,
"keepFnName": false,
},
],
Expand All @@ -95,6 +98,7 @@ Object {
exports[`preset-options should handle options that are delegated to multiple other options 2`] = `
Object {
"input": Object {
"keepClassName": true,
"keepFnName": true,
"mangle": Object {
"blacklist": Array [
Expand All @@ -108,6 +112,7 @@ Object {
Array [
"babel-plugin-minify-dead-code-elimination",
Object {
"keepClassName": true,
"keepFnName": true,
},
],
Expand All @@ -123,6 +128,7 @@ Object {
"foo",
"bar",
],
"keepClassName": true,
"keepFnName": true,
},
],
Expand All @@ -144,11 +150,13 @@ Object {
exports[`preset-options should handle options that are delegated to multiple other options 3`] = `
Object {
"input": Object {
"keepClassName": true,
"keepFnName": true,
"mangle": Object {
"blacklist": Array [
"baz",
],
"keepClassName": false,
"keepFnName": false,
},
},
Expand All @@ -157,6 +165,7 @@ Object {
Array [
"babel-plugin-minify-dead-code-elimination",
Object {
"keepClassName": true,
"keepFnName": true,
},
],
Expand All @@ -171,6 +180,7 @@ Object {
"blacklist": Array [
"baz",
],
"keepClassName": false,
"keepFnName": false,
},
],
Expand Down
8 changes: 6 additions & 2 deletions packages/babel-preset-babili/__tests__/options-tests.js
Expand Up @@ -85,19 +85,23 @@ describe("preset-options", () => {

it("should handle options that are delegated to multiple other options", () => {
testOpts({
keepFnName: false
keepFnName: false,
keepClassName: false
});
testOpts({
keepFnName: true,
keepClassName: true,
mangle: {
blacklist: ["foo", "bar"]
}
});
testOpts({
keepFnName: true,
keepClassName: true,
mangle: {
blacklist: ["baz"],
keepFnName: false
keepFnName: false,
keepClassName: false,
}
});
});
Expand Down
5 changes: 5 additions & 0 deletions packages/babel-preset-babili/src/index.js
Expand Up @@ -85,6 +85,11 @@ function preset(context, _opts = {}) {
proxy("keepFnName", [
optionsMap.mangle,
optionsMap.deadcode
]),

proxy("keepClassName", [
optionsMap.mangle,
optionsMap.deadcode
])
],
"some"
Expand Down