This commit is contained in:
ScottDowne 2010-12-15 15:58:10 -05:00
Родитель 12bad186b3
Коммит 9535dbef93
11 изменённых файлов: 6008 добавлений и 0 удалений

55
Makefile Normal file
Просмотреть файл

@ -0,0 +1,55 @@
# Make sure $JSSHELL points to your js shell binary in .profile or .bashrc
TOOLSDIR=./tools
all: release
create-release: clean
mkdir ./release
# Version number used in naming release files.
VERSION ?= $(error Specify a version for your release (e.g., VERSION=0.5))
release: release-files zipped
release-files: popcorn yui release-docs
zipped: release-files
gzip -c ./release/popcorn-${VERSION}.min.js > ./release/popcorn-${VERSION}.min.js.gz
find ./release -print | zip -j ./release/popcorn.js-${VERSION}.zip -@
release-docs: create-release
cp AUTHORS ./release
cat README | sed -e 's/@VERSION@/${VERSION}/' > ./release/README
cp LICENSE ./release
cp CHANGELOG ./release
pretty: create-release
${TOOLSDIR}/jsbeautify.py ${JSSHELL} popcorn.js > ./release/popcorn-${VERSION}.js.tmp
# check for any parsing errors in pretty version of popcorn.js
${JSSHELL} -f ${TOOLSDIR}/fake-dom.js -f ./release/popcorn-${VERSION}.js.tmp
cat ./release/popcorn-${VERSION}.js.tmp | sed -e 's/@VERSION@/${VERSION}/' > ./release/popcorn-${VERSION}.js
rm -f ./release/popcorn-${VERSION}.js.tmp
popcorn: create-release
cp popcorn.js ./release/popcorn-${VERSION}.js.tmp
# check for any parsing errors in popcorn.js
${JSSHELL} -f ${TOOLSDIR}/fake-dom.js -f ./release/popcorn-${VERSION}.js.tmp
cat ./release/popcorn-${VERSION}.js.tmp | sed -e 's/@VERSION@/${VERSION}/' > ./release/popcorn-${VERSION}.js
rm -f ./release/popcorn-${VERSION}.js.tmp
yui: create-release
# java -jar ${TOOLSDIR}/yui/yuicompressor-2.4.2.jar --nomunge popcorn.js -o ./release/popcorn-${VERSION}.min.js
java -jar ${TOOLSDIR}/yui/yuicompressor-2.4.2.jar popcorn.js -o ./release/popcorn-${VERSION}.min.js
# check for any parsing errors in compiled version of popcorn.js
${JSSHELL} -f ${TOOLSDIR}/fake-dom.js -f ./release/popcorn-${VERSION}.min.js
check: check-lint
check-lint:
${TOOLSDIR}/jslint.py ${JSSHELL} popcorn.js
# Most targets use commands that need a js shell path specified
JSSHELL ?= $(error Specify a valid path to a js shell binary in ~/.profile: export JSSHELL=C:\path\js.exe or /path/js)
clean:
rm -fr ./release

7
tools/cleaner.js Normal file
Просмотреть файл

@ -0,0 +1,7 @@
// Swap escaped bits in code. See jsshellhelper.py for creation of __escaped_string
function __unescape_string() {
return __escaped_string.replace(/@DQUOTE@/g, '"').
replace(/@SQUOTE@/g, "'").
replace(/@NEWLINE@/g, '\n').
replace(/@BACKSLASH@/g, '\\');
}

0
tools/fake-dom.js Normal file
Просмотреть файл

974
tools/jsbeautify.js Normal file
Просмотреть файл

@ -0,0 +1,974 @@
/*jslint onevar: false, plusplus: false */
/*
JS Beautifier
---------------
Written by Einar Lielmanis, <einars@gmail.com>
http://jsbeautifier.org/
Originally converted to javascript by Vital, <vital76@gmail.com>
You are free to use this in any way you want, in case you find this useful or working for you.
Usage:
js_beautify(js_source_text);
js_beautify(js_source_text, options);
The options are:
indent_size (default 4) indentation size,
indent_char (default space) character to indent with,
preserve_newlines (default true) whether existing line breaks should be preserved,
indent_level (default 0) initial indentation level, you probably won't need this ever,
space_after_anon_function (default false) if true, then space is added between "function ()"
(jslint is happy about this); if false, then the common "function()" output is used.
e.g
js_beautify(js_source_text, {indent_size: 1, indent_char: '\t'});
*/
function js_beautify(js_source_text, options) {
var input, output, token_text, last_type, last_text, last_last_text, last_word, flags, flag_store, indent_string;
var whitespace, wordchar, punct, parser_pos, line_starters, digits;
var prefix, token_type, do_block_just_closed;
var indent_level, wanted_newline, just_added_newline, n_newlines;
options = options || {};
var opt_indent_size = options.indent_size || 4;
var opt_indent_char = options.indent_char || ' ';
var opt_preserve_newlines = typeof options.preserve_newlines === 'undefined' ? true : options.preserve_newlines;
var opt_indent_level = options.indent_level || 0; // starting indentation
var opt_space_after_anon_function = options.space_after_anon_function === 'undefined' ? false : options.space_after_anon_function;
var opt_keep_array_indentation = typeof options.keep_array_indentation === 'undefined' ? true : options.keep_array_indentation;
just_added_newline = false;
function trim_output() {
while (output.length && (output[output.length - 1] === ' ' || output[output.length - 1] === indent_string)) {
output.pop();
}
}
function print_newline(ignore_repeated) {
if (opt_keep_array_indentation && is_array(flags.mode)) {
return;
}
ignore_repeated = typeof ignore_repeated === 'undefined' ? true : ignore_repeated;
flags.if_line = false;
trim_output();
if (!output.length) {
return; // no newline on start of file
}
if (output[output.length - 1] !== "\n" || !ignore_repeated) {
just_added_newline = true;
output.push("\n");
}
for (var i = 0; i < indent_level; i += 1) {
output.push(indent_string);
}
}
function print_single_space() {
var last_output = ' ';
if (output.length) {
last_output = output[output.length - 1];
}
if (last_output !== ' ' && last_output !== '\n' && last_output !== indent_string) { // prevent occassional duplicate space
output.push(' ');
}
}
function print_token() {
just_added_newline = false;
output.push(token_text);
}
function indent() {
indent_level += 1;
}
function unindent() {
if (indent_level) {
indent_level -= 1;
}
}
function remove_indent() {
if (output.length && output[output.length - 1] === indent_string) {
output.pop();
}
}
function print_javadoc_comment() {
var lines = token_text.split('\n');
output.push(lines[0]);
for (var i = 1; i < lines.length; i++) {
print_newline();
output.push(' ');
output.push(lines[i].replace(/^\s+/, ''));
}
}
function set_mode(mode) {
if (flags) {
flag_store.push(flags);
}
flags = {
mode: mode,
var_line: false,
var_line_tainted: false,
if_line: false,
in_case: false,
indentation_baseline: -1
};
}
function is_expression(mode) {
return mode === '[EXPRESSION]' || mode === '[INDENTED-EXPRESSION]' || mode === '(EXPRESSION)';
}
function is_array(mode) {
return mode === '[EXPRESSION]' || mode === '[INDENTED-EXPRESSION]';
}
function restore_mode() {
do_block_just_closed = flags.mode === 'DO_BLOCK';
if (flag_store.length > 0) {
flags = flag_store.pop();
}
}
function in_array(what, arr) {
for (var i = 0; i < arr.length; i += 1) {
if (arr[i] === what) {
return true;
}
}
return false;
}
// Walk backwards from the colon to find a '?' (colon is part of a ternary op)
// or a '{' (colon is part of a class literal). Along the way, keep track of
// the blocks and expressions we pass so we only trigger on those chars in our
// own level, and keep track of the colons so we only trigger on the matching '?'.
function is_ternary_op() {
var level = 0,
colon_count = 0;
for (var i = output.length - 1; i >= 0; i--) {
switch (output[i]) {
case ':':
if (level === 0) {
colon_count++;
}
break;
case '?':
if (level === 0) {
if (colon_count === 0) {
return true;
} else {
colon_count--;
}
}
break;
case '{':
if (level === 0) {
return false;
}
level--;
break;
case '(':
case '[':
level--;
break;
case ')':
case ']':
case '}':
level++;
break;
}
}
}
function get_next_token() {
n_newlines = 0;
if (parser_pos >= input.length) {
return ['', 'TK_EOF'];
}
var c = input.charAt(parser_pos);
parser_pos += 1;
var keep_whitespace = opt_keep_array_indentation && is_array(flags.mode);
wanted_newline = false;
if (keep_whitespace) {
//
// slight mess to allow nice preservation of array indentation and reindent that correctly
// first time when we get to the arrays:
// var a = [
// ....'something'
// we make note of whitespace_count = 4 into flags.indentation_baseline
// so we know that 4 whitespaces in original source match indent_level of reindented source
//
// and afterwards, when we get to
// 'something,
// .......'something else'
// we know that this should be indented to indent_level + (7 - indentation_baseline) spaces
//
var whitespace_count = 0;
while (in_array(c, whitespace)) {
if (c === "\n") {
trim_output();
output.push("\n");
just_added_newline = true;
whitespace_count = 0;
} else {
if (c === '\t') {
whitespace_count += 4;
} else {
whitespace_count += 1;
}
}
if (parser_pos >= input.length) {
return ['', 'TK_EOF'];
}
c = input.charAt(parser_pos);
parser_pos += 1;
}
if (flags.indentation_baseline === -1) {
flags.indentation_baseline = whitespace_count;
}
if (just_added_newline) {
for (var i = 0; i < indent_level + 1; i += 1) {
output.push(indent_string);
}
if (flags.indentation_baseline !== -1) {
for (var i = 0; i < whitespace_count - flags.indentation_baseline; i++) {
output.push(' ');
}
}
}
} else {
while (in_array(c, whitespace)) {
if (c === "\n") {
n_newlines += 1;
}
if (parser_pos >= input.length) {
return ['', 'TK_EOF'];
}
c = input.charAt(parser_pos);
parser_pos += 1;
}
if (opt_preserve_newlines) {
if (n_newlines > 1) {
for (var i = 0; i < n_newlines; i += 1) {
print_newline(i === 0);
just_added_newline = true;
}
}
}
wanted_newline = n_newlines > 0;
}
if (in_array(c, wordchar)) {
if (parser_pos < input.length) {
while (in_array(input.charAt(parser_pos), wordchar)) {
c += input.charAt(parser_pos);
parser_pos += 1;
if (parser_pos === input.length) {
break;
}
}
}
// small and surprisingly unugly hack for 1E-10 representation
if (parser_pos !== input.length && c.match(/^[0-9]+[Ee]$/) && (input.charAt(parser_pos) === '-' || input.charAt(parser_pos) === '+')) {
var sign = input.charAt(parser_pos);
parser_pos += 1;
var t = get_next_token(parser_pos);
c += sign + t[0];
return [c, 'TK_WORD'];
}
if (c === 'in') { // hack for 'in' operator
return [c, 'TK_OPERATOR'];
}
if (wanted_newline && last_type !== 'TK_OPERATOR' && !flags.if_line && (opt_preserve_newlines || last_text !== 'var')) {
print_newline();
}
return [c, 'TK_WORD'];
}
if (c === '(' || c === '[') {
return [c, 'TK_START_EXPR'];
}
if (c === ')' || c === ']') {
return [c, 'TK_END_EXPR'];
}
if (c === '{') {
return [c, 'TK_START_BLOCK'];
}
if (c === '}') {
return [c, 'TK_END_BLOCK'];
}
if (c === ';') {
return [c, 'TK_SEMICOLON'];
}
if (c === '/') {
var comment = '';
// peek for comment /* ... */
if (input.charAt(parser_pos) === '*') {
parser_pos += 1;
if (parser_pos < input.length) {
while (! (input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/') && parser_pos < input.length) {
comment += input.charAt(parser_pos);
parser_pos += 1;
if (parser_pos >= input.length) {
break;
}
}
}
parser_pos += 2;
return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT'];
}
// peek for comment // ...
if (input.charAt(parser_pos) === '/') {
comment = c;
while (input.charAt(parser_pos) !== "\x0d" && input.charAt(parser_pos) !== "\x0a") {
comment += input.charAt(parser_pos);
parser_pos += 1;
if (parser_pos >= input.length) {
break;
}
}
parser_pos += 1;
if (wanted_newline) {
print_newline();
}
return [comment, 'TK_COMMENT'];
}
}
if (c === "'" || // string
c === '"' || // string
(c === '/' && ((last_type === 'TK_WORD' && in_array(last_text, ['return', 'do'])) || (last_type === 'TK_START_EXPR' || last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_OPERATOR' || last_type === 'TK_EOF' || last_type === 'TK_SEMICOLON')))) { // regexp
var sep = c;
var esc = false;
var resulting_string = c;
if (parser_pos < input.length) {
if (sep === '/') {
//
// handle regexp separately...
//
var in_char_class = false;
while (esc || in_char_class || input.charAt(parser_pos) !== sep) {
resulting_string += input.charAt(parser_pos);
if (!esc) {
esc = input.charAt(parser_pos) === '\\';
if (input.charAt(parser_pos) === '[') {
in_char_class = true;
} else if (input.charAt(parser_pos) === ']') {
in_char_class = false;
}
} else {
esc = false;
}
parser_pos += 1;
if (parser_pos >= input.length) {
// incomplete string/rexp when end-of-file reached.
// bail out with what had been received so far.
return [resulting_string, 'TK_STRING'];
}
}
} else {
//
// and handle string also separately
//
while (esc || input.charAt(parser_pos) !== sep) {
resulting_string += input.charAt(parser_pos);
if (!esc) {
esc = input.charAt(parser_pos) === '\\';
} else {
esc = false;
}
parser_pos += 1;
if (parser_pos >= input.length) {
// incomplete string/rexp when end-of-file reached.
// bail out with what had been received so far.
return [resulting_string, 'TK_STRING'];
}
}
}
}
parser_pos += 1;
resulting_string += sep;
if (sep === '/') {
// regexps may have modifiers /regexp/MOD , so fetch those, too
while (parser_pos < input.length && in_array(input.charAt(parser_pos), wordchar)) {
resulting_string += input.charAt(parser_pos);
parser_pos += 1;
}
}
return [resulting_string, 'TK_STRING'];
}
if (c === '#') {
// Spidermonkey-specific sharp variables for circular references
// https://developer.mozilla.org/En/Sharp_variables_in_JavaScript
// http://mxr.mozilla.org/mozilla-central/source/js/src/jsscan.cpp around line 1935
var sharp = '#';
if (parser_pos < input.length && in_array(input.charAt(parser_pos), digits)) {
do {
c = input.charAt(parser_pos);
sharp += c;
parser_pos += 1;
} while (parser_pos < input.length && c !== '#' && c !== '=');
if (c === '#') {
return [sharp, 'TK_WORD'];
} else {
return [sharp, 'TK_OPERATOR'];
}
}
}
if (c === '<' && input.substring(parser_pos - 1, parser_pos + 3) === '<!--') {
parser_pos += 3;
return ['<!--', 'TK_COMMENT'];
}
if (c === '-' && input.substring(parser_pos - 1, parser_pos + 2) === '-->') {
parser_pos += 2;
if (wanted_newline) {
print_newline();
}
return ['-->', 'TK_COMMENT'];
}
if (in_array(c, punct)) {
while (parser_pos < input.length && in_array(c + input.charAt(parser_pos), punct)) {
c += input.charAt(parser_pos);
parser_pos += 1;
if (parser_pos >= input.length) {
break;
}
}
return [c, 'TK_OPERATOR'];
}
return [c, 'TK_UNKNOWN'];
}
//----------------------------------
indent_string = '';
while (opt_indent_size > 0) {
indent_string += opt_indent_char;
opt_indent_size -= 1;
}
indent_level = opt_indent_level;
input = js_source_text;
last_word = ''; // last 'TK_WORD' passed
last_type = 'TK_START_EXPR'; // last token type
last_text = ''; // last token text
last_last_text = ''; // pre-last token text
output = [];
do_block_just_closed = false;
whitespace = "\n\r\t ".split('');
wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'.split('');
digits = '0123456789'.split('');
// <!-- is a special case (ok, it's a minor hack actually)
punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::'.split(' ');
// words which should always start on new line.
line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(',');
// states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'.
// some formatting depends on that.
flag_store = [];
set_mode('BLOCK');
parser_pos = 0;
while (true) {
var t = get_next_token(parser_pos);
token_text = t[0];
token_type = t[1];
if (token_type === 'TK_EOF') {
break;
}
switch (token_type) {
case 'TK_START_EXPR':
if (token_text === '[') {
if (last_type === 'TK_WORD' || last_text === ')') {
// this is array index specifier, break immediately
// a[x], fn()[x]
if (last_word === 'return' || last_word === 'throw') {
print_single_space();
}
set_mode('(EXPRESSION)');
print_token();
break;
}
if (flags.mode === '[EXPRESSION]' || flags.mode === '[INDENTED-EXPRESSION]') {
if (last_last_text === ']' && last_text === ',') {
// ], [ goes to new line
if (flags.mode === '[EXPRESSION]') {
if (!opt_keep_array_indentation) {
indent();
}
flags.mode = '[INDENTED-EXPRESSION]';
}
if (!opt_keep_array_indentation) {
print_newline();
}
set_mode('[EXPRESSION]');
} else if (last_text === '[') {
if (flags.mode === '[EXPRESSION]') {
if (!opt_keep_array_indentation) {
indent();
}
flags.mode = '[INDENTED-EXPRESSION]';
}
if (!opt_keep_array_indentation) {
print_newline();
}
set_mode('[EXPRESSION]');
} else {
set_mode('[EXPRESSION]');
}
} else {
set_mode('[EXPRESSION]');
}
} else {
set_mode('(EXPRESSION)');
}
if (last_text === ';' || last_type === 'TK_START_BLOCK') {
print_newline();
} else if (last_type === 'TK_END_EXPR' || last_type === 'TK_START_EXPR' || last_type === 'TK_END_BLOCK') {
// do nothing on (( and )( and ][ and ]( ..
} else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') {
print_single_space();
} else if (last_word === 'function') {
// function() vs function ()
if (opt_space_after_anon_function) {
print_single_space();
}
} else if (in_array(last_word, line_starters)) {
print_single_space();
}
print_token();
break;
case 'TK_END_EXPR':
if (token_text === ']') {
if (flags.mode === '[INDENTED-EXPRESSION]') {
unindent();
if (last_text === ']') {
print_newline();
}
}
}
restore_mode();
print_token();
break;
case 'TK_START_BLOCK':
if (last_word === 'do') {
set_mode('DO_BLOCK');
} else {
set_mode('BLOCK');
}
if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') {
if (last_type === 'TK_START_BLOCK') {
print_newline();
} else {
print_single_space();
}
}
print_token();
indent();
break;
case 'TK_END_BLOCK':
if (last_type === 'TK_START_BLOCK') {
// nothing
if (just_added_newline) {
remove_indent();
// {
//
// }
} else {
// {}
trim_output();
}
unindent();
} else {
unindent();
print_newline();
}
print_token();
restore_mode();
break;
case 'TK_WORD':
// no, it's not you. even I have problems understanding how this works
// and what does what.
if (do_block_just_closed) {
// do {} ## while ()
print_single_space();
print_token();
print_single_space();
do_block_just_closed = false;
break;
}
if (token_text === 'function') {
if ((just_added_newline || last_text == ';') && last_text !== '{') {
// make sure there is a nice clean space of at least one blank line
// before a new function definition
n_newlines = just_added_newline ? n_newlines : 0;
for (var i = 0; i < 2 - n_newlines; i++) {
print_newline(false);
}
}
}
if (token_text === 'case' || token_text === 'default') {
if (last_text === ':') {
// switch cases following one another
remove_indent();
} else {
// case statement starts in the same line where switch
unindent();
print_newline();
indent();
}
print_token();
flags.in_case = true;
break;
}
prefix = 'NONE';
if (last_type === 'TK_END_BLOCK') {
if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
prefix = 'NEWLINE';
} else {
prefix = 'SPACE';
print_single_space();
}
} else if (last_type === 'TK_SEMICOLON' && (flags.mode === 'BLOCK' || flags.mode === 'DO_BLOCK')) {
prefix = 'NEWLINE';
} else if (last_type === 'TK_SEMICOLON' && is_expression(flags.mode)) {
prefix = 'SPACE';
} else if (last_type === 'TK_STRING') {
prefix = 'NEWLINE';
} else if (last_type === 'TK_WORD') {
prefix = 'SPACE';
} else if (last_type === 'TK_START_BLOCK') {
prefix = 'NEWLINE';
} else if (last_type === 'TK_END_EXPR') {
print_single_space();
prefix = 'NEWLINE';
}
if (last_type !== 'TK_END_BLOCK' && in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
print_newline();
} else if (in_array(token_text, line_starters) || prefix === 'NEWLINE') {
if (last_text === 'else') {
// no need to force newline on else break
print_single_space();
} else if ((last_type === 'TK_START_EXPR' || last_text === '=' || last_text === ',') && token_text === 'function') {
// no need to force newline on 'function': (function
// DONOTHING
} else if (last_text === 'return' || last_text === 'throw') {
// no newline between 'return nnn'
print_single_space();
} else if (last_type !== 'TK_END_EXPR') {
if ((last_type !== 'TK_START_EXPR' || token_text !== 'var') && last_text !== ':') {
// no need to force newline on 'var': for (var x = 0...)
if (token_text === 'if' && last_word === 'else' && last_text !== '{') {
// no newline for } else if {
print_single_space();
} else {
print_newline();
}
}
} else {
if (in_array(token_text, line_starters) && last_text !== ')') {
print_newline();
}
}
} else if (prefix === 'SPACE') {
print_single_space();
}
print_token();
last_word = token_text;
if (token_text === 'var') {
flags.var_line = true;
flags.var_line_tainted = false;
}
if (token_text === 'if' || token_text === 'else') {
flags.if_line = true;
}
break;
case 'TK_SEMICOLON':
print_token();
flags.var_line = false;
break;
case 'TK_STRING':
if (last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_SEMICOLON') {
print_newline();
} else if (last_type === 'TK_WORD') {
print_single_space();
}
print_token();
break;
case 'TK_OPERATOR':
var start_delim = true;
var end_delim = true;
if (flags.var_line && token_text === ',' && (is_expression(flags.mode))) {
// do not break on comma, for(var a = 1, b = 2)
flags.var_line_tainted = false;
}
if (flags.var_line) {
if (token_text === ',') {
if (flags.var_line_tainted) {
print_token();
print_newline();
output.push(indent_string);
flags.var_line_tainted = false;
break;
} else {
flags.var_line_tainted = false;
}
} else {
flags.var_line_tainted = true;
if (token_text === ':') {
flags.var_line = false;
}
}
}
if (last_text === 'return' || last_text === 'throw') {
// "return" had a special handling in TK_WORD. Now we need to return the favor
print_single_space();
print_token();
break;
}
if (token_text === ':' && flags.in_case) {
print_token(); // colon really asks for separate treatment
print_newline();
flags.in_case = false;
break;
}
if (token_text === '::') {
// no spaces around exotic namespacing syntax operator
print_token();
break;
}
if (token_text === ',') {
if (flags.var_line) {
if (flags.var_line_tainted) {
print_token();
print_newline();
flags.var_line_tainted = false;
} else {
print_token();
print_single_space();
}
} else if (last_type === 'TK_END_BLOCK') {
print_token();
print_newline();
} else {
if (flags.mode === 'BLOCK') {
print_token();
print_newline();
} else {
// EXPR or DO_BLOCK
print_token();
print_single_space();
}
}
break;
} else if (token_text === '--' || token_text === '++') { // unary operators special case
if (last_text === ';') {
if (flags.mode === 'BLOCK') {
// { foo; --i }
print_newline();
start_delim = true;
end_delim = false;
} else {
// space for (;; ++i)
start_delim = true;
end_delim = false;
}
} else {
if (last_text === '{') {
// {--i
print_newline();
}
start_delim = false;
end_delim = false;
}
} else if ((token_text === '!' || token_text === '+' || token_text === '-') && (last_text === 'return' || last_text === 'case')) {
start_delim = true;
end_delim = false;
} else if ((token_text === '!' || token_text === '+' || token_text === '-') && last_type === 'TK_START_EXPR') {
// special case handling: if (!a)
start_delim = false;
end_delim = false;
} else if (last_type === 'TK_OPERATOR') {
start_delim = false;
end_delim = false;
} else if (last_type === 'TK_END_EXPR') {
start_delim = true;
end_delim = true;
} else if (token_text === '.') {
// decimal digits or object.property
start_delim = false;
end_delim = false;
} else if (token_text === ':') {
if (is_ternary_op()) {
start_delim = true;
} else {
start_delim = false;
}
}
if (start_delim) {
print_single_space();
}
print_token();
if (end_delim) {
print_single_space();
}
break;
case 'TK_BLOCK_COMMENT':
print_newline();
if (token_text.substring(0, 3) == '/**') {
print_javadoc_comment();
} else {
print_token();
}
print_newline();
break;
case 'TK_COMMENT':
// print_newline();
if (wanted_newline) {
print_newline();
} else {
print_single_space();
}
print_token();
print_newline();
break;
case 'TK_UNKNOWN':
print_token();
break;
}
last_last_text = last_text;
last_type = token_type;
last_text = token_text;
}
return output.join('').replace(/\n+$/, '');
}

42
tools/jsbeautify.py Executable file
Просмотреть файл

@ -0,0 +1,42 @@
#!/usr/bin/env python
import sys, os, os.path, signal
import jsshellhelper
from optparse import OptionParser
from subprocess import Popen, PIPE, STDOUT
# Uses jsshell https://developer.mozilla.org/en/Introduction_to_the_JavaScript_shell
class Beautifier(object):
toolsdir = os.path.dirname(os.path.abspath(__file__))
def run(self, jsshell, filename):
tmpFile = jsshellhelper.createEscapedFile(filename)
cmd = [jsshell,
'-f', os.path.join(self.toolsdir, 'jsbeautify.js'),
'-f', os.path.join(self.toolsdir, 'cleaner.js'),
'-f', tmpFile,
'-e', "var input = __unescape_string(); print(js_beautify(input, {indent_size: 2}));"]
proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
stdout, stderr = proc.communicate()
if stdout:
print stdout
else:
print stderr
jsshellhelper.cleanUp(tmpFile)
def main():
parser = OptionParser()
options, args = parser.parse_args()
if len(args) < 2:
print >>sys.stderr, """Usage: %s <path to jsshell> <js file>""" % sys.argv[0]
sys.exit(1)
beautifier = Beautifier()
beautifier.run(args[0], args[1])
if __name__ == '__main__':
main()

4718
tools/jslint-cmdline.js Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

44
tools/jslint.py Executable file
Просмотреть файл

@ -0,0 +1,44 @@
#!/usr/bin/env python
import sys, os, os.path, signal
import jsshellhelper
from optparse import OptionParser
from subprocess import Popen, PIPE, STDOUT
# Uses jsshell https://developer.mozilla.org/en/Introduction_to_the_JavaScript_shell
class Linter(object):
toolsdir = os.path.dirname(os.path.abspath(__file__))
def run(self, jsshell, filename):
tmpFile = jsshellhelper.createEscapedFile(filename)
cmd = [jsshell,
'-f', os.path.join(self.toolsdir, 'cleaner.js'),
'-f', tmpFile,
'-e', 'var input = __unescape_string();\n',
'-f', os.path.join(self.toolsdir, 'jslint-cmdline.js')]
proc = Popen(cmd)
stdout, stderr = proc.communicate()
if stdout:
print stdout
else:
print stderr
jsshellhelper.cleanUp(tmpFile)
def main():
parser = OptionParser()
options, args = parser.parse_args()
if len(args) < 2:
print >>sys.stderr, """Usage: %s <path to jsshell> <js file>""" % sys.argv[0]
sys.exit(1)
linter = Linter()
linter.run(args[0], args[1])
if __name__ == '__main__':
main()

28
tools/jsshellhelper.py Executable file
Просмотреть файл

@ -0,0 +1,28 @@
#!/usr/bin/env python
import os, os.path
import tempfile
# Uses jsshell https://developer.mozilla.org/en/Introduction_to_the_JavaScript_shell
def createEscapedFile(filename):
""" Stringifies a file (.js, .pde) and sticks it tmp file as an escaped js string with variable __escaped_string """
filepath = os.path.abspath(filename)
es = 'var __escaped_string ="'
f = open(filepath, "r");
for line in f:
es += line.rstrip('\r\n').replace('"', '@DQUOTE@').replace("'", '@SQUOTE@').replace("\\", "@BACKSLASH@") + "@NEWLINE@"
f.close()
es += '";\n'
# write the escaped string out to a tmp file, return the filename
tmp = tempfile.mkstemp()
os.close(tmp[0])
t = open(tmp[1], 'w')
t.write(es)
t.close()
return tmp[1]
def cleanUp(filepath):
os.remove(filepath)

Двоичные данные
tools/jsshellhelper.pyc Normal file

Двоичный файл не отображается.

140
tools/yui/README Executable file
Просмотреть файл

@ -0,0 +1,140 @@
==============================================================================
YUI Compressor
==============================================================================
NAME
YUI Compressor - The Yahoo! JavaScript and CSS Compressor
SYNOPSIS
Usage: java -jar yuicompressor-x.y.z.jar [options] [input file]
Global Options
-h, --help Displays this information
--type <js|css> Specifies the type of the input file
--charset <charset> Read the input file using <charset>
--line-break <column> Insert a line break after the specified column number
-v, --verbose Display informational messages and warnings
-o <file> Place the output into <file>. Defaults to stdout.
JavaScript Options
--nomunge Minify only, do not obfuscate
--preserve-semi Preserve all semicolons
--disable-optimizations Disable all micro optimizations
DESCRIPTION
The YUI Compressor is a JavaScript compressor which, in addition to removing
comments and white-spaces, obfuscates local variables using the smallest
possible variable name. This obfuscation is safe, even when using constructs
such as 'eval' or 'with' (although the compression is not optimal is those
cases) Compared to jsmin, the average savings is around 20%.
The YUI Compressor is also able to safely compress CSS files. The decision
on which compressor is being used is made on the file extension (js or css)
GLOBAL OPTIONS
-h, --help
Prints help on how to use the YUI Compressor
--line-break
Some source control tools don't like files containing lines longer than,
say 8000 characters. The linebreak option is used in that case to split
long lines after a specific column. It can also be used to make the code
more readable, easier to debug (especially with the MS Script Debugger)
Specify 0 to get a line break after each semi-colon in JavaScript, and
after each rule in CSS.
--type js|css
The type of compressor (JavaScript or CSS) is chosen based on the
extension of the input file name (.js or .css) This option is required
if no input file has been specified. Otherwise, this option is only
required if the input file extension is neither 'js' nor 'css'.
--charset character-set
If a supported character set is specified, the YUI Compressor will use it
to read the input file. Otherwise, it will assume that the platform's
default character set is being used. The output file is encoded using
the same character set.
-o outfile
Place output in file outfile. If not specified, the YUI Compressor will
default to the standard output, which you can redirect to a file.
-v, --verbose
Display informational messages and warnings.
JAVASCRIPT ONLY OPTIONS
--nomunge
Minify only. Do not obfuscate local symbols.
--preserve-semi
Preserve unnecessary semicolons (such as right before a '}') This option
is useful when compressed code has to be run through JSLint (which is the
case of YUI for example)
--disable-optimizations
Disable all the built-in micro optimizations.
NOTES
+ If no input file is specified, it defaults to stdin.
+ The YUI Compressor requires Java version >= 1.4.
+ It is possible to prevent a local variable, nested function or function
argument from being obfuscated by using "hints". A hint is a string that
is located at the very beginning of a function body like so:
function fn (arg1, arg2, arg3) {
"arg2:nomunge, localVar:nomunge, nestedFn:nomunge";
...
var localVar;
...
function nestedFn () {
....
}
...
}
The hint itself disappears from the compressed file.
+ C-style comments starting with /*! are preserved. This is useful with
comments containing copyright/license information. For example:
/*!
* TERMS OF USE - EASING EQUATIONS
* Open source under the BSD License.
* Copyright 2001 Robert Penner All rights reserved.
*/
becomes:
/*
* TERMS OF USE - EASING EQUATIONS
* Open source under the BSD License.
* Copyright 2001 Robert Penner All rights reserved.
*/
AUTHOR
The YUI Compressor was written and is maintained by:
Julien Lecomte <jlecomte@yahoo-inc.com>
The CSS portion is a port of Isaac Schlueter's cssmin utility.
COPYRIGHT
Copyright (c) 2007-2009, Yahoo! Inc. All rights reserved.
LICENSE
All code specific to YUI Compressor is issued under a BSD license.
YUI Compressor extends and implements code from Mozilla's Rhino project.
Rhino is issued under the Mozilla Public License (MPL), and MPL applies
to the Rhino source and binaries that are distributed with YUI Compressor.

Двоичные данные
tools/yui/yuicompressor-2.4.2.jar Executable file

Двоичный файл не отображается.