Compare commits

..

36 Commits
v2.3 ... v2.3.6

Author SHA1 Message Date
Mihai Bazon
188e28efd7 v2.3.6 2013-05-23 23:42:32 +03:00
Mihai Bazon
2df48924cc Merge pull request #213 from mattrobenolt/patch-1
SourceMapping pragma has changed to //#
2013-05-22 11:30:54 -07:00
Mihai Bazon
9fc6796d2a Add negate_iife option to the code generator.
See discussion in a9511dfbe5
2013-05-22 21:22:14 +03:00
Mihai Bazon
9fc8a52142 Set "global" on undeclared SymbolDef-s 2013-05-22 13:08:19 +03:00
Matt Robenolt
3a21861580 The extra /* */ isn't needed now 2013-05-21 08:50:21 -06:00
Matt Robenolt
1dbffd48ea SourceMapping pragma has changed to //#
See: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit

The spec was updated on May 16th since `//@` was causing some issues with IE.
2013-05-21 08:46:27 -06:00
Mihai Bazon
22a038e6a2 Fix output of statement: new function(){...};
Close #209
2013-05-20 08:27:37 +03:00
Mihai Bazon
f652372c9a v2.3.5 2013-05-19 14:25:05 +03:00
Mihai Bazon
ad1fc3b71a Fix package.json (use repository instead of repositories) 2013-05-19 14:24:33 +03:00
Mihai Bazon
2b40a5ac62 v2.3.4 2013-05-15 13:27:40 +03:00
Mihai Bazon
ca3388cf5a Add --expr, an option to parse a single expression (suitable for JSON) 2013-05-15 13:27:23 +03:00
Mihai Bazon
caa8896a8a Only compress code in new Function if all arguments are strings. 2013-05-14 18:36:31 +03:00
Mihai Bazon
d13aa3954d v2.3.3 2013-05-14 11:33:28 +03:00
Mihai Bazon
f64539fb76 Compress code passed to new Function if it's a constant.
Only for `--unsafe`.

Close #203
2013-05-14 10:47:06 +03:00
Mihai Bazon
d56ebd7d7b Fix a["1_1"]
Close #204
2013-05-14 10:42:34 +03:00
Mihai Bazon
3edfe7d0ee Merge pull request #202 from nschonni/add-travis-ci
Add CI build for supported Node versions
2013-05-10 02:56:24 -07:00
Mihai Bazon
7f77edadb3 v2.3.2 2013-05-09 08:58:55 +03:00
Mihai Bazon
a9511dfbe5 Use the negation hack rather than parens for a toplevel function expression call
(only in !beautify mode)
2013-05-09 08:58:47 +03:00
Mihai Bazon
064e7aa1bb Fix is_assignable
(not likely to be noticed, it's only used in `strict` parse mode)
2013-05-09 08:44:24 +03:00
Nick Schonning
46814f88d9 Add Travis build badge to README 2013-05-08 23:48:12 -04:00
Nick Schonning
4a19802d0c Add CI build for supported Node versions 2013-05-08 23:42:06 -04:00
Trey Griffith
1e9f98aa51 add a test for zero-length string in is_identifier_string, which is used in property compression. Also added a test exercising the change. 2013-05-08 22:43:20 +03:00
Mihai Bazon
11e24d53a1 Fix property names
Close #199
2013-05-08 22:37:48 +03:00
Mihai Bazon
0f509f8336 v2.3.1 2013-05-08 16:45:36 +03:00
Mihai Bazon
a6ed2c84ac Better fix for equality of typeof ... against "undefined" 2013-05-08 16:22:48 +03:00
Justin Lau
a1958aad56 Fixed typeof undefined optimization and updated related test case to
accomodates the sort behaviour changes made in commit
mishoo/UglifyJS2@aebafad41e.
Signed-off-by: Justin Lau <justin@tclau.com>
2013-05-08 16:22:48 +03:00
Justin Lau
672699613e Added test cases for #104.
Signed-off-by: Justin Lau <justin@tclau.com>
2013-05-08 16:22:48 +03:00
Mihai Bazon
645d5bdbc5 Merge pull request #195 from kjbekkelund/typo
Fix typo in bin and readme
2013-05-08 05:51:52 -07:00
Justin Lau
9af2bbffde Fixed dot properties not optimizing unicode identifiers. Signed-off-by: Justin Lau <justin@tclau.com> 2013-05-07 14:20:19 +03:00
Justin Lau
fcd544cc10 Added test scenario with unicode in properties name.
Signed-off-by: Justin Lau <justin@tclau.com>
2013-05-06 01:26:33 +08:00
Justin Lau
1e3bc0caa0 Fixed dot property issue with invlid identifier names.
Signed-off-by: Justin Lau <justin@tclau.com>
2013-05-05 22:27:43 +08:00
Justin Lau
8227e8795b Added scenario in test case where properties shouldn't be accessed with
dotted syntax even with screw_ie8 option.
Signed-off-by: Justin Lau <justin@tclau.com>
2013-05-05 22:08:13 +08:00
Kim Joar Bekkelund
790b3bcdc6 Fix typo in bin and readme 2013-05-02 11:15:33 +02:00
Mihai Bazon
d6e6458f68 Merge pull request #194 from ulikoehler/master
Add README syntax highlighting
2013-05-01 07:04:01 -07:00
Uli Köhler
a54b6703c0 Add README syntax highlighting 2013-05-01 15:56:20 +02:00
Mihai Bazon
8e6266136d Take two. v2.3.0 2013-05-01 13:15:34 +03:00
13 changed files with 278 additions and 113 deletions

7
.travis.yml Normal file
View File

@@ -0,0 +1,7 @@
language: node_js
node_js:
- "0.4"
- "0.6"
- "0.8"
- "0.10"
- "0.11"

181
README.md
View File

@@ -1,5 +1,6 @@
UglifyJS 2
==========
[![Build Status](https://travis-ci.org/mishoo/UglifyJS2.png)](https://travis-ci.org/mishoo/UglifyJS2)
UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.
@@ -80,7 +81,7 @@ The available options are:
cascading statements into sequences. [string]
--stats Display operations run time on STDERR. [boolean]
--acorn Use Acorn for parsing. [boolean]
--spidermonkey Assume input fles are SpiderMonkey AST format (as JSON).
--spidermonkey Assume input files are SpiderMonkey AST format (as JSON).
[boolean]
--self Build itself (UglifyJS2) as a library (implies
--wrap=UglifyJS --export-all) [boolean]
@@ -222,10 +223,11 @@ You can use the `--define` (`-d`) switch in order to declare global
variables that UglifyJS will assume to be constants (unless defined in
scope). For example if you pass `--define DEBUG=false` then, coupled with
dead code removal UglifyJS will discard the following from the output:
if (DEBUG) {
console.log("debug stuff");
}
```javascript
if (DEBUG) {
console.log("debug stuff");
}
```
UglifyJS will warn about the condition being always false and about dropping
unreachable code; for now there is no option to turn off only this specific
@@ -234,10 +236,11 @@ warning, you can pass `warnings=false` to turn off *all* warnings.
Another way of doing that is to declare your globals as constants in a
separate file and include it into the build. For example you can have a
`build/defines.js` file with the following:
const DEBUG = false;
const PRODUCTION = true;
// etc.
```javascript
const DEBUG = false;
const PRODUCTION = true;
// etc.
```
and build your code like this:
@@ -284,6 +287,10 @@ can pass additional arguments that control the code output:
you pass `false` then whenever possible we will use a newline instead of a
semicolon, leading to more readable output of uglified code (size before
gzip could be smaller; size after gzip insignificantly larger).
- `negate-iife` (default `!beautify`) -- prefer negation, rather than
parens, for "Immediately-Called Function Expressions". This defaults to
`true` when beautification is off, and `false` if beautification is on;
pass it manually to force a value.
### Keeping copyright notices or other comments
@@ -296,14 +303,15 @@ keep only comments that match this regexp. For example `--comments
Note, however, that there might be situations where comments are lost. For
example:
function f() {
/** @preserve Foo Bar */
function g() {
// this function is never called
}
return something();
}
```javascript
function f() {
/** @preserve Foo Bar */
function g() {
// this function is never called
}
return something();
}
```
Even though it has "@preserve", the comment will be lost because the inner
function `g` (which is the AST node to which the comment is attached to) is
@@ -345,8 +353,9 @@ API Reference
Assuming installation via NPM, you can load UglifyJS in your application
like this:
var UglifyJS = require("uglify-js");
```javascript
var UglifyJS = require("uglify-js");
```
It exports a lot of names, but I'll discuss here the basics that are needed
for parsing, mangling and compressing a piece of code. The sequence is (1)
@@ -357,45 +366,49 @@ parse, (2) compress, (3) mangle, (4) generate output code.
There's a single toplevel function which combines all the steps. If you
don't need additional customization, you might want to go with `minify`.
Example:
var result = UglifyJS.minify("/path/to/file.js");
console.log(result.code); // minified output
// if you need to pass code instead of file name
var result = UglifyJS.minify("var b = function () {};", {fromString: true});
```javascript
var result = UglifyJS.minify("/path/to/file.js");
console.log(result.code); // minified output
// if you need to pass code instead of file name
var result = UglifyJS.minify("var b = function () {};", {fromString: true});
```
You can also compress multiple files:
var result = UglifyJS.minify([ "file1.js", "file2.js", "file3.js" ]);
console.log(result.code);
```javascript
var result = UglifyJS.minify([ "file1.js", "file2.js", "file3.js" ]);
console.log(result.code);
```
To generate a source map:
var result = UglifyJS.minify([ "file1.js", "file2.js", "file3.js" ], {
outSourceMap: "out.js.map"
});
console.log(result.code); // minified output
console.log(result.map);
```javascript
var result = UglifyJS.minify([ "file1.js", "file2.js", "file3.js" ], {
outSourceMap: "out.js.map"
});
console.log(result.code); // minified output
console.log(result.map);
```
Note that the source map is not saved in a file, it's just returned in
`result.map`. The value passed for `outSourceMap` is only used to set the
`file` attribute in the source map (see [the spec][sm-spec]).
You can also specify sourceRoot property to be included in source map:
var result = UglifyJS.minify([ "file1.js", "file2.js", "file3.js" ], {
outSourceMap: "out.js.map",
sourceRoot: "http://example.com/src"
});
```javascript
var result = UglifyJS.minify([ "file1.js", "file2.js", "file3.js" ], {
outSourceMap: "out.js.map",
sourceRoot: "http://example.com/src"
});
```
If you're compressing compiled JavaScript and have a source map for it, you
can use the `inSourceMap` argument:
var result = UglifyJS.minify("compiled.js", {
inSourceMap: "compiled.js.map",
outSourceMap: "minified.js.map"
});
// same as before, it returns `code` and `map`
```javascript
var result = UglifyJS.minify("compiled.js", {
inSourceMap: "compiled.js.map",
outSourceMap: "minified.js.map"
});
// same as before, it returns `code` and `map`
```
The `inSourceMap` is only used if you also request `outSourceMap` (it makes
no sense otherwise).
@@ -425,8 +438,9 @@ Following there's more detailed API info, in case the `minify` function is
too simple for your needs.
#### The parser
var toplevel_ast = UglifyJS.parse(code, options);
```javascript
var toplevel_ast = UglifyJS.parse(code, options);
```
`options` is optional and if present it must be an object. The following
properties are available:
@@ -440,15 +454,16 @@ properties are available:
The last two options are useful when you'd like to minify multiple files and
get a single file as the output and a proper source map. Our CLI tool does
something like this:
var toplevel = null;
files.forEach(function(file){
var code = fs.readFileSync(file);
toplevel = UglifyJS.parse(code, {
filename: file,
toplevel: toplevel
});
});
```javascript
var toplevel = null;
files.forEach(function(file){
var code = fs.readFileSync(file);
toplevel = UglifyJS.parse(code, {
filename: file,
toplevel: toplevel
});
});
```
After this, we have in `toplevel` a big AST containing all our files, with
each token having proper information about where it came from.
@@ -462,15 +477,17 @@ referenced, if it is a global or not, if a function is using `eval` or the
`with` statement etc. I will discuss this some place else, for now what's
important to know is that you need to call the following before doing
anything with the tree:
toplevel.figure_out_scope()
```javascript
toplevel.figure_out_scope()
```
#### Compression
Like this:
var compressor = UglifyJS.Compressor(options);
var compressed_ast = toplevel.transform(compressor);
```javascript
var compressor = UglifyJS.Compressor(options);
var compressed_ast = toplevel.transform(compressor);
```
The `options` can be missing. Available options are discussed above in
“Compressor options”. Defaults should lead to best compression in most
@@ -486,23 +503,26 @@ the compressor might drop unused variables / unreachable code and this might
change the number of identifiers or their position). Optionally, you can
call a trick that helps after Gzip (counting character frequency in
non-mangleable words). Example:
compressed_ast.figure_out_scope();
compressed_ast.compute_char_frequency();
compressed_ast.mangle_names();
```javascript
compressed_ast.figure_out_scope();
compressed_ast.compute_char_frequency();
compressed_ast.mangle_names();
```
#### Generating output
AST nodes have a `print` method that takes an output stream. Essentially,
to generate code you do this:
var stream = UglifyJS.OutputStream(options);
compressed_ast.print(stream);
var code = stream.toString(); // this is your minified code
```javascript
var stream = UglifyJS.OutputStream(options);
compressed_ast.print(stream);
var code = stream.toString(); // this is your minified code
```
or, for a shortcut you can do:
var code = compressed_ast.print_to_string(options);
```javascript
var code = compressed_ast.print_to_string(options);
```
As usual, `options` is optional. The output stream accepts a lot of otions,
most of them documented above in section “Beautifier options”. The two
@@ -540,16 +560,17 @@ to be a `SourceMap` object (which is a thin wrapper on top of the
[source-map][source-map] library).
Example:
```javascript
var source_map = UglifyJS.SourceMap(source_map_options);
var stream = UglifyJS.OutputStream({
...
source_map: source_map
});
compressed_ast.print(stream);
var source_map = UglifyJS.SourceMap(source_map_options);
var stream = UglifyJS.OutputStream({
...
source_map: source_map
});
compressed_ast.print(stream);
var code = stream.toString();
var map = source_map.toString(); // json output for your source map
var code = stream.toString();
var map = source_map.toString(); // json output for your source map
```
The `source_map_options` (optional) can contain the following properties:

View File

@@ -20,9 +20,10 @@ mangling you need to use `-c` and `-m`.\
")
.describe("source-map", "Specify an output file where to generate source map.")
.describe("source-map-root", "The path to the original source to be included in the source map.")
.describe("source-map-url", "The path to the source map to be added in //@ sourceMappingURL. Defaults to the value passed with --source-map.")
.describe("source-map-url", "The path to the source map to be added in //# sourceMappingURL. Defaults to the value passed with --source-map.")
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
.describe("screw-ie8", "Pass this flag if you don't care about full compliance with Internet Explorer 6-8 quirks (by default UglifyJS will try to be IE-proof).")
.describe("expr", "Parse a single expression, rather than a program (for parsing JSON)")
.describe("p", "Skip prefix for original filenames that appear in source maps. \
For example -p 3 will drop 3 directories from file names and ensure they are relative paths.")
.describe("o", "Output file (default STDOUT).")
@@ -46,7 +47,7 @@ because of dead code removal or cascading statements into sequences.")
.describe("stats", "Display operations run time on STDERR.")
.describe("acorn", "Use Acorn for parsing.")
.describe("spidermonkey", "Assume input fles are SpiderMonkey AST format (as JSON).")
.describe("spidermonkey", "Assume input files are SpiderMonkey AST format (as JSON).")
.describe("self", "Build itself (UglifyJS2) as a library (implies --wrap=UglifyJS --export-all)")
.describe("wrap", "Embed everything in a big function, making the “exports” and “global” variables available. \
You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser.")
@@ -76,6 +77,8 @@ You need to pass an argument to this option to specify the name that your module
.string("e")
.string("comments")
.string("wrap")
.boolean("expr")
.boolean("screw-ie8")
.boolean("export-all")
.boolean("self")
@@ -242,8 +245,9 @@ async.eachLimit(files, 1, function (file, cb) {
}
else {
TOPLEVEL = UglifyJS.parse(code, {
filename: file,
toplevel: TOPLEVEL
filename : file,
toplevel : TOPLEVEL,
expression : ARGS.expr,
});
};
});
@@ -305,7 +309,7 @@ async.eachLimit(files, 1, function (file, cb) {
if (SOURCE_MAP) {
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
output += "\n/*\n//@ sourceMappingURL=" + (ARGS.source_map_url || ARGS.source_map) + "\n*/";
output += "\n//# sourceMappingURL=" + (ARGS.source_map_url || ARGS.source_map);
}
if (OUTPUT_FILE) {

View File

@@ -1589,6 +1589,45 @@ merge(Compressor.prototype, {
operator: "+",
right: make_node(AST_String, self, { value: "" })
});
case "Function":
if (all(self.args, function(x){ return x instanceof AST_String })) {
// quite a corner-case, but we can handle it:
// https://github.com/mishoo/UglifyJS2/issues/203
// if the code argument is a constant, then we can minify it.
try {
var code = "(function(" + self.args.slice(0, -1).map(function(arg){
return arg.value;
}).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
var ast = parse(code);
ast.figure_out_scope();
var comp = new Compressor(compressor.options);
ast = ast.transform(comp);
ast.figure_out_scope();
ast.mangle_names();
var fun = ast.body[0].body.expression;
var args = fun.argnames.map(function(arg, i){
return make_node(AST_String, self.args[i], {
value: arg.print_to_string()
});
});
var code = OutputStream();
AST_BlockStatement.prototype._codegen.call(fun, fun, code);
code = code.toString().replace(/^\{|\}$/g, "");
args.push(make_node(AST_String, self.args[self.args.length - 1], {
value: code
}));
self.args = args;
return self;
} catch(ex) {
if (ex instanceof JS_Parse_Error) {
compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
compressor.warn(ex.toString());
} else {
console.log(ex);
}
}
}
break;
}
}
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
@@ -1726,8 +1765,8 @@ merge(Compressor.prototype, {
var commutativeOperators = makePredicate("== === != !== * & | ^");
OPT(AST_Binary, function(self, compressor){
function reverse(op) {
if (!(self.left.has_side_effects() || self.right.has_side_effects())) {
function reverse(op, force) {
if (force || !(self.left.has_side_effects() || self.right.has_side_effects())) {
if (op) self.operator = op;
var tmp = self.left;
self.left = self.right;
@@ -1737,7 +1776,10 @@ merge(Compressor.prototype, {
if (commutativeOperators(self.operator)) {
if (self.right instanceof AST_Constant
&& !(self.left instanceof AST_Constant)) {
reverse();
// if right is a constant, whatever side effects the
// left side might have could not influence the
// result. hence, force switch.
reverse(null, true);
}
}
self = self.lift_sequences(compressor);
@@ -1758,8 +1800,8 @@ merge(Compressor.prototype, {
&& compressor.option("unsafe")) {
if (!(self.right.expression instanceof AST_SymbolRef)
|| !self.right.expression.undeclared()) {
self.left = self.right.expression;
self.right = make_node(AST_Undefined, self.left).optimize(compressor);
self.right = self.right.expression;
self.left = make_node(AST_Undefined, self.left).optimize(compressor);
if (self.operator.length == 2) self.operator += "=";
}
}
@@ -1962,7 +2004,8 @@ merge(Compressor.prototype, {
var prop = self.property;
if (prop instanceof AST_String && compressor.option("properties")) {
prop = prop.getValue();
if (is_identifier(prop) || compressor.option("screw_ie8")) {
if ((compressor.option("screw_ie8") && RESERVED_WORDS(prop))
|| (!(RESERVED_WORDS(prop)) && is_identifier_string(prop))) {
return make_node(AST_Dot, self, {
expression : self.expression,
property : prop

View File

@@ -60,7 +60,8 @@ function OutputStream(options) {
bracketize : false,
semicolons : true,
comments : false,
preserve_line : false
preserve_line : false,
negate_iife : !(options && options.beautify),
}, true);
var indentation = 0;
@@ -351,7 +352,9 @@ function OutputStream(options) {
AST_Node.DEFMETHOD("print", function(stream, force_parens){
var self = this, generator = self._codegen;
stream.push_node(self);
if (force_parens || self.needs_parens(stream)) {
var needs_parens = self.needs_parens(stream);
var fc = self instanceof AST_Function && stream.option("negate_iife");
if (force_parens || (needs_parens && !fc)) {
stream.with_parens(function(){
self.add_comments(stream);
self.add_source_map(stream);
@@ -359,6 +362,7 @@ function OutputStream(options) {
});
} else {
self.add_comments(stream);
if (needs_parens && fc) stream.print("!");
self.add_source_map(stream);
generator(self, stream);
}
@@ -1119,7 +1123,7 @@ function OutputStream(options) {
if (p instanceof AST_Statement && p.body === node)
return true;
if ((p instanceof AST_Seq && p.car === node ) ||
(p instanceof AST_Call && p.expression === node ) ||
(p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
(p instanceof AST_Dot && p.expression === node ) ||
(p instanceof AST_Sub && p.expression === node ) ||
(p instanceof AST_Conditional && p.condition === node ) ||

View File

@@ -167,6 +167,17 @@ function is_identifier_char(ch) {
;
};
function is_identifier_string(str){
var i = str.length;
if (i == 0) return false;
if (is_digit(str.charCodeAt(0))) return false;
while (--i >= 0) {
if (!is_identifier_char(str.charAt(i)))
return false;
}
return true;
};
function parse_js_number(num) {
if (RE_HEX_NUMBER.test(num)) {
return parseInt(num.substr(2), 16);
@@ -577,9 +588,10 @@ var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "nam
function parse($TEXT, options) {
options = defaults(options, {
strict : false,
filename : null,
toplevel : null
strict : false,
filename : null,
toplevel : null,
expression : false
});
var S = {
@@ -1330,15 +1342,8 @@ function parse($TEXT, options) {
function is_assignable(expr) {
if (!options.strict) return true;
switch (expr[0]+"") {
case "dot":
case "sub":
case "new":
case "call":
return true;
case "name":
return expr[1] != "this";
}
if (expr instanceof AST_This) return false;
return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
};
var maybe_assign = function(no_in) {
@@ -1382,6 +1387,10 @@ function parse($TEXT, options) {
return ret;
};
if (options.expression) {
return expression(true);
}
return (function(){
var start = S.token;
var body = [];

View File

@@ -187,6 +187,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
} else {
g = new SymbolDef(self, globals.size(), node);
g.undeclared = true;
g.global = true;
globals.set(name, g);
}
node.thedef = g;

View File

@@ -44,7 +44,6 @@
"use strict";
// Tree transformer helpers.
// XXX: eventually I should refactor the compressor to use this infrastructure.
function TreeTransformer(before, after) {
TreeWalker.call(this);

View File

@@ -245,6 +245,13 @@ function makePredicate(words) {
return new Function("str", f);
};
function all(array, predicate) {
for (var i = array.length; --i >= 0;)
if (!predicate(array[i]))
return false;
return true;
};
function Dictionary() {
this._values = Object.create(null);
this._size = 0;

View File

@@ -3,17 +3,17 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"homepage": "http://lisperator.net/uglifyjs",
"main": "tools/node.js",
"version": "2.3",
"version": "2.3.6",
"engines": { "node" : ">=0.4.0" },
"maintainers": [{
"name": "Mihai Bazon",
"email": "mihai.bazon@gmail.com",
"web": "http://lisperator.net/"
}],
"repositories": [{
"repository": {
"type": "git",
"url": "https://github.com/mishoo/UglifyJS2.git"
}],
},
"dependencies": {
"async" : "~0.2.6",
"source-map" : "~0.1.7",

View File

@@ -1,7 +1,6 @@
typeof_eq_undefined: {
options = {
comparisons: true,
unsafe: false
comparisons: true
};
input: { a = typeof b.c != "undefined" }
expect: { a = "undefined" != typeof b.c }
@@ -13,5 +12,14 @@ typeof_eq_undefined_unsafe: {
unsafe: true
};
input: { a = typeof b.c != "undefined" }
expect: { a = b.c !== void 0 }
expect: { a = void 0 !== b.c }
}
typeof_eq_undefined_unsafe2: {
options = {
comparisons: true,
unsafe: true
};
input: { a = "undefined" != typeof b.c }
expect: { a = void 0 !== b.c }
}

View File

@@ -0,0 +1,48 @@
/**
* There was an incorrect sort behaviour documented in issue #143:
* (x = f(…)) <= x → x >= (x = f(…))
*
* For example, let the equation be:
* (a = parseInt('100')) <= a
*
* If a was an integer and has the value of 99,
* (a = parseInt('100')) <= a → 100 <= 100 → true
*
* When transformed incorrectly:
* a >= (a = parseInt('100')) → 99 >= 100 → false
*/
tranformation_sort_order_equal: {
options = {
comparisons: true,
};
input: { (a = parseInt('100')) == a }
expect: { (a = parseInt('100')) == a }
}
tranformation_sort_order_unequal: {
options = {
comparisons: true,
};
input: { (a = parseInt('100')) != a }
expect: { (a = parseInt('100')) != a }
}
tranformation_sort_order_lesser_or_equal: {
options = {
comparisons: true,
};
input: { (a = parseInt('100')) <= a }
expect: { (a = parseInt('100')) <= a }
}
tranformation_sort_order_greater_or_equal: {
options = {
comparisons: true,
};
input: { (a = parseInt('100')) >= a }
expect: { (a = parseInt('100')) >= a }
}

View File

@@ -17,10 +17,18 @@ dot_properties: {
input: {
a["foo"] = "bar";
a["if"] = "if";
a["*"] = "asterisk";
a["\u0EB3"] = "unicode";
a[""] = "whitespace";
a["1_1"] = "foo";
}
expect: {
a.foo = "bar";
a["if"] = "if";
a["*"] = "asterisk";
a.\u0EB3 = "unicode";
a[""] = "whitespace";
a["1_1"] = "foo";
}
}
@@ -32,9 +40,15 @@ dot_properties_es5: {
input: {
a["foo"] = "bar";
a["if"] = "if";
a["*"] = "asterisk";
a["\u0EB3"] = "unicode";
a[""] = "whitespace";
}
expect: {
a.foo = "bar";
a.if = "if";
a["*"] = "asterisk";
a.\u0EB3 = "unicode";
a[""] = "whitespace";
}
}