<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Серый форум &mdash; JScript: Удаление неиспользуемых функций из кода JScript]]></title>
	<link rel="self" href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=9534&amp;type=atom" />
	<updated>2014-04-28T10:21:31Z</updated>
	<generator>PunBB</generator>
	<id>https://forum.script-coding.com/viewtopic.php?id=9534</id>
		<entry>
			<title type="html"><![CDATA[Re: JScript: Удаление неиспользуемых функций из кода JScript]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=82379#p82379" />
			<content type="html"><![CDATA[<p>Да. Код не модифицируется - имена сущностей остаются без изменений, неиспользуемый код не отбразывается.</p>]]></content>
			<author>
				<name><![CDATA[Rumata]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24846</uri>
			</author>
			<updated>2014-04-28T10:21:31Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=82379#p82379</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: JScript: Удаление неиспользуемых функций из кода JScript]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=82376#p82376" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>Rumata пишет:</cite><blockquote><p>Использую <a href="https://github.com/ildar-shaimordanov/jsmin.js">пропатченный jsmin</a> (версия Френка Марсиа) для обфускации кода и <a href="http://jsbeautifier.org/">js_beautify</a> для деобфускации кода. </p><p>все вместе здесь - <a href="http://code.google.com/p/jsxt/source/browse/trunk/js/eval.js">http://code.google.com/p/jsxt/source/br … js/eval.js</a></p></blockquote></div><p>Я так понял, что он только минимизирует код, обфускация как следствие, верно?</p>]]></content>
			<author>
				<name><![CDATA[JSmаn]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24434</uri>
			</author>
			<updated>2014-04-28T09:37:08Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=82376#p82376</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: JScript: Удаление неиспользуемых функций из кода JScript]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=82375#p82375" />
			<content type="html"><![CDATA[<p>Видел, но еще не смотрел. </p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header"><strong>+</strong>&nbsp;есть альтернатива</div><div class="fancy_spoiler"><p>Использую <a href="https://github.com/ildar-shaimordanov/jsmin.js">пропатченный jsmin</a> (версия Френка Марсиа) для обфускации кода и <a href="http://jsbeautifier.org/">js_beautify</a> для деобфускации кода. </p><p>все вместе здесь - <a href="http://code.google.com/p/jsxt/source/browse/trunk/js/eval.js">http://code.google.com/p/jsxt/source/br … js/eval.js</a></p></div></div>]]></content>
			<author>
				<name><![CDATA[Rumata]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24846</uri>
			</author>
			<updated>2014-04-28T09:17:58Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=82375#p82375</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: JScript: Удаление неиспользуемых функций из кода JScript]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=82370#p82370" />
			<content type="html"><![CDATA[<p>Никто не тестировал? :-) </p><p>Добавлен js-beautify. Теперь результирующий код еще и красивый. </p><p>Если сложности возникли по использованию, может примеры набросать? А то писал столько, а только просмотры, критики даже нет:)</p>]]></content>
			<author>
				<name><![CDATA[JSmаn]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24434</uri>
			</author>
			<updated>2014-04-28T07:35:40Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=82370#p82370</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[JScript: Удаление неиспользуемых функций из кода JScript]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=82275#p82275" />
			<content type="html"><![CDATA[<p>Приветствую, форумчане! Хочу поделиться моей наработкой по удалению неиспользуемых функций из тела скрипта. Разумеется, результат еще нельзя назвать универсальным инструментом, но мне уже здорово упростил жизнь. Почему бы не поделиться?<br />Итак, на входе файл, содержащий код яваскрипта, который необходимо оптимизировать. На выходе получим тот же код, но очищенный от комментариев и неиспользуемых глобальных функций. Анализ неиспользуемых блоков кода, переменных, функций внутри функций не производится.<br />Кстати, указанный проект тесно связан с параллельной работой по созданию фреймворка. Таким образом, пару строк функций фреймворка не будут обязывать кодера тащить за собой всю библиотеку. Бросили файл на скрипт - получили код. </p><p>Примечание: 1) функции вида new Function() обработчик не затрагивает.<br />2) Расширение прототипа также учитывается.</p><p>Код немного жестокий для понимания. Если нужно, расскажу по алгоритму.</p><div class="codebox"><pre><code>
if (WScript.Arguments.length == 0) WScript.Quit();
var FileName = WScript.Arguments(0);
var FileNameOut = /\./.test(FileName) ? FileName.replace(/\.[^\.]+$/, &quot;.out.js&quot;) : (FileName + &quot;.out.js&quot;);

Array.prototype.getUnique = function () {
    var u = {},
        a = [];
    for (var i = 0, l = this.length; i &lt; l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
    return a;
}

var FSO = new ActiveXObject(&quot;Scripting.FileSystemObject&quot;);
var ForReading = 1,
    ForWriting = 2,
    ForAppending = 8;

// Открываем файл и читаем код
var f = FSO.OpenTextFile(FileName, 1);
var source = f.ReadAll();
f.Close();


var text = cleanCodeFromUnusedFunctions(source);

var resFile = FSO.OpenTextFile(FileNameOut, 2, 1);
resFile.Write(js_beautify(text, {indent_size: 1, indent_char: &#039;\t&#039;}));
resFile.Close();
WScript.Echo(&quot;Результаты сохранены в файле: &quot; + FileNameOut);
WScript.Quit();


function cleanCodeFromUnusedFunctions(source)
{
    var tmp = cleanCodeFromValues(source),
    text = tmp[0],
    skip = tmp[1];

    var Funcs = [];

    var globalFuncs = findFunctionDeclaration(text);

    var globalCalls = findCalls(globalFuncs[0]);
    var GlobalFunctions = globalFuncs[1];



    // разворачиваем цепочку функций
    (function (tmp, calls) {
        if (calls == []) return;

        // перебираем массив с вызовами функций, ищем их в коде
        for (var i = 0, l = calls.length; i &lt; l; i++) {
            for (var j = 0, k = GlobalFunctions.length; j &lt; k; j++) {
                if (calls[i] == GlobalFunctions[j][1]) {
                    var flag = true;
                    for (var g = 0; g &lt; Funcs.length; g++) {
                        if (GlobalFunctions[j][1][2] == Funcs[g][2]) flag = false;
                    }

                    if (flag) {
                        Funcs.push(GlobalFunctions[j]);
                        var t = tmp.slice(GlobalFunctions[j][3], GlobalFunctions[j][4]);
                        arguments.callee(tmp, findCalls(t));
                    }
                }
            }
        }
    })(text, globalCalls);

    text = restoreFunction(globalFuncs[0], text, Funcs);

    var last = 0;
    for (var i = 0, l = GlobalFunctions.length; i &lt; l; i++) {
        if (last != GlobalFunctions[i][2])
            text = restoreCode(text, source, skip, /str|reg|res/, last, GlobalFunctions[i][2]);
        last = GlobalFunctions[i][4];
    }
    text = restoreCode(text, source, skip, /str|reg|res/, last, text.length);


    for (var i = 0, l = Funcs.length; i &lt; l; i++) {
        text = restoreCode(text, source, skip, /str|reg|res/, Funcs[i][2], Funcs[i][4])
    }

    text = text.replace(/^\s+$/gm, &quot;\r\n&quot;).replace(/(\r?\n)+/g, &quot;\r\n&quot;).replace(/^\s*;\s*$/gm, &quot;;&quot;);
    return text;
}

// воcстановит кусок кода от ранних изменений. например, восстановит строки или регулярные выражения
function restoreCode(tmp, code, skipInfo, what, start, end) {
    !skipInfo ? skipInfo = [] : 0;
    !start ? start = 0 : 0;
    !end ? end = code.length : 0;
    for (var i = 0, l = skipInfo.length; i &lt; l; i++) {
        if ((start &lt;= skipInfo[i][1]) &amp;&amp; (end &gt;= skipInfo[i][2]))
            if (what.test(skipInfo[i][0])) tmp = tmp.slice(0, skipInfo[i][1]) + code.slice(skipInfo[i][1], skipInfo[i][2]) + tmp.slice(skipInfo[i][2]);
    }
    return tmp;
}

function restoreFunction(tmp, code, func_arr) {
    for (var i = 0; i &lt; func_arr.length; i++) {
        tmp = tmp.slice(0, func_arr[i][2]) + code.slice(func_arr[i][2], func_arr[i][4] + 1) + tmp.slice(func_arr[i][4] + 1);
    }
    return tmp;
}

// вернет массив с информацией о вызовах функций
function findCalls(s) {
    if (!s) return [];

    var ar = s.match(/(function\s+)?\.?[_$\w\d]+\s*\(|\b[\w$_][\.\w\d_]\.call|\b[\w$_][\.\w\d_]\.apply/g);
    if (ar) {
        ar = ar.join(&quot;|&quot;).replace(/\b(function\s+[^\|]+|\b(if|for|while|eval|catch|do|break|case|else|in|return|switch|this|throw|typeof|var|void|with|ActiveXObject|GetObject|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|isFinite|isNaN|Number|parseFloat|Error|parseInt|String|unescape|Array|Date|[Ff]unction|VBArray)\b|RegExp|Enumerator)\s*\|?|\s*\(|/g, &quot;&quot;).replace(/\|/g, &quot;,&quot;).replace(/\.,/g, &#039;,&#039;).replace(/,(,)+/g, &#039;,&#039;).replace(/^,|,$/g, &#039;&#039;);
        ar = ar.split(&quot;,&quot;).getUnique();
        return ar;
    } else return [];
}


// вернет [очищенный code от глобальных функций, информация_о_заменах] 
function findFunctionDeclaration(code) {

    var flag = false,
        Result = [],
        delta = 0,
        tmp = code;

    function processFunction(m) {
        flag = true;
        var pos = arguments[arguments.length-2];
        if (/new\s+Function\b/.test(m)) return;
        /*
        if (/new\s+Function\b/.test(m)) {
            Result.push([&quot;function&quot;, m.replace(/\s*=.+/, &quot;&quot;), delta + pos, delta + pos, delta + pos + m.length + 1, []]);
            code = code.slice(0, delta + pos) + new Array(m.length + 1).join(&quot; &quot;) + code.slice(delta + pos + m.length + 1);
            delta += pos + m.length;
            tmp = tmp.slice(pos + m.length + 1);
            return;
        }
        */

        var tmp2 = tmp.slice(pos + m.length + 1);
        var start = end = pos + m.length + 1;
        var index = 0;

        function searchLimits(m1) {
            var pos1 = arguments[arguments.length-2];
            if (m1 == &quot;{&quot;) index++;
            if (m1 == &quot;}&quot;) index--;
            tmp2 = tmp2.slice(pos1 + 1);
            end += pos1 + 1;
        }

        while (index != -1 &amp;&amp; /[{}]/.test(tmp2)) tmp2.replace(/[{}]/, searchLimits);

        var ar = findCalls(tmp.slice(start, end));

        Result.push([&quot;function&quot;, m.replace(/\(([\r\n]|.)*/, &quot;&quot;).replace(/\bfunction\b|\bnew\b|[^\w\d_\.]/g, &quot;&quot;).match(/\.?[\w\d_$]+$/), delta + pos, delta + start, delta + end, ar]);
        code = code.slice(0, delta + pos) + new Array(end - pos + 1).join(&quot; &quot;) + code.slice(delta + end);

        tmp = tmp.slice(end);
        delta += end;
    }

    do {
        flag = false;
        if (tmp)
            tmp.replace(/(?!=\s*)function\s+[\w$_][\.\w\d_]*\s*\([^\)]*\)[^\{]*{|[\w$_][\.\w\d_]*\s*=\s*function\s*\([^\)]*\)[^\{]*{/, processFunction);
    }
    while (flag);

    return [code, Result];
}

// Эта функция вернет массив [очищенный_код, информация_о_заменах_в_коде] код без строковых значений, регулярных выражений, комментариев и ресурсов. Вместо них будут пробелы так, чтобы не нарушилась длина кода. 
function cleanCodeFromValues(code) {
    var tmp = code,
        found = &quot;&quot;,
        startpos = 0,
        delta = 0,
        skip = [];
    //var searchValues = /\/\*\[?|[&quot;&#039;]|\/\/|(?:(^|[;\}\{\(])\s*)\/(?![\*\/])/m;
    var searchValues = /\/\*\[?|[@#]*[&quot;&#039;]|\/\/|(?:(^|[;\}\{\(])\s*)\/(?![\*\/])/m;
    var types = {
        &#039;/*&#039;: &quot;comment&quot;,
        &#039;/*[&#039;: &quot;resource&quot;,
        &#039;&quot;&#039;: &quot;string&quot;,
        &quot;&#039;&quot;: &quot;string&quot;,
        &#039;//&#039;: &quot;comment&quot;,
        &quot;/&quot;: &quot;regexp&quot;
    };

    function getStartPointOfValues(m) {
        found = m;
        var pos = arguments[arguments.length-2];
        if (!/[^\/]\/$/.test(m)) {
            startpos = delta + pos;
        } else {
            found = &quot;/&quot;;
            //WScript.Echo(m);
            startpos = delta + pos + m.length - 1;
        }
        tmp = tmp.slice(pos + m.length);
        delta += pos + m.length;
    }

    function getEndPointOfValues(m) {
        var pos = arguments[arguments.length-2];
        if (found == &quot;/&quot;) {
            pos++;
            m = &quot;/&quot;;
        }

        if (/.[&quot;&#039;]$/.test(found)) {
            m = found;
            pos++;
        }

        if (found == &quot;//&quot;) pos--;


        //WScript.Echo([&quot;Найдено ранее: &quot;+found, &quot;Его длина:  &quot;+found.length, &quot;Найдено в текущий момент: &quot;+m, &quot;Позиция: &quot;+pos, &quot;Что внутри: &quot;+tmp.slice(0, pos)].join(&quot;\r\n&quot;));
        var content = tmp.slice(0, pos);

        tmp = tmp.slice(pos + m.length);
        delta += pos + m.length;


        skip.push([types[found], startpos, delta]);
        code = code.slice(0, startpos) + new Array(delta - startpos + 1).join(&quot; &quot;) + code.slice(delta);

    }

    function findValues() {
        tmp.replace(searchValues, getStartPointOfValues);

        if (found == &#039;&quot;&#039;) tmp.replace(/(?:^&quot;|(?:\\\\|[^\\])&quot;)/, getEndPointOfValues);
        if (found == &quot;&#039;&quot;) tmp.replace(/(?:^&#039;|(?:\\\\|[^\\])&#039;)/, getEndPointOfValues);
        if (found == &#039;//&#039;) tmp.replace(/[\r\n]/, getEndPointOfValues);
        if (found == &#039;/*&#039; || found == &#039;/*[&#039;) tmp.replace(/\*\//, getEndPointOfValues);
        if (found == &quot;/&quot;) tmp.replace(/(?!\\).\//, getEndPointOfValues);
        found = &quot;&quot;;
        return tmp;
    }

    //Перебираем содержание.
    while (tmp != findValues()) {}
    tmp = &quot;&quot;;
    return [code, skip];
}

/*jslint onevar: false, plusplus: false */
/*

 JS Beautifier
---------------
  Written by Einar Lielmanis, &lt;einars@gmail.com&gt;
      http://jsbeautifier.org/

  Originally converted to javascript by Vital, &lt;vital76@gmail.com&gt;
  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&#039;t need this ever,
    space_after_anon_function (default false) — if true, then space is added between &quot;function ()&quot;
            (jslint is happy about this); if false, then the common &quot;function()&quot; output is used.
    e.g

    js_beautify(js_source_text, {indent_size: 1, indent_char: &#039;\t&#039;});
*/

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 || &#039; &#039;;
    var opt_preserve_newlines = typeof options.preserve_newlines === &#039;undefined&#039; ? true : options.preserve_newlines;
    var opt_indent_level = options.indent_level || 0;
    var opt_space_after_anon_function = options.space_after_anon_function === &#039;undefined&#039; ? false : options.space_after_anon_function;
    var opt_keep_array_indentation = typeof options.keep_array_indentation === &#039;undefined&#039; ? true : options.keep_array_indentation;
    just_added_newline = false;

    function trim_output() {
        while (output.length &amp;&amp; (output[output.length - 1] === &#039; &#039; || output[output.length - 1] === indent_string)) {
            output.pop();
        }
    }

    function print_newline(ignore_repeated) {
        if (opt_keep_array_indentation &amp;&amp; is_array(flags.mode)) {
            return;
        }
        ignore_repeated = typeof ignore_repeated === &#039;undefined&#039; ? true : ignore_repeated;
        flags.if_line = false;
        trim_output();
        if (!output.length) {
            return;
        }
        if (output[output.length - 1] !== &quot;\n&quot; || !ignore_repeated) {
            just_added_newline = true;
            output.push(&quot;\n&quot;);
        }
        for (var i = 0; i &lt; indent_level; i += 1) {
            output.push(indent_string);
        }
    }

    function print_single_space() {
        var last_output = &#039; &#039;;
        if (output.length) {
            last_output = output[output.length - 1];
        }
        if (last_output !== &#039; &#039; &amp;&amp; last_output !== &#039;\n&#039; &amp;&amp; last_output !== indent_string) {
            output.push(&#039; &#039;);
        }
    }

    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 &amp;&amp; output[output.length - 1] === indent_string) {
            output.pop();
        }
    }

    function print_javadoc_comment() {
        var lines = token_text.split(&#039;\n&#039;);
        output.push(lines[0]);
        for (var i = 1; i &lt; lines.length; i++) {
            print_newline();
            output.push(&#039; &#039;);
            output.push(lines[i].replace(/^\s+/, &#039;&#039;));
        }
    }

    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 === &#039;[EXPRESSION]&#039; || mode === &#039;[INDENTED-EXPRESSION]&#039; || mode === &#039;(EXPRESSION)&#039;;
    }

    function is_array(mode) {
        return mode === &#039;[EXPRESSION]&#039; || mode === &#039;[INDENTED-EXPRESSION]&#039;;
    }

    function restore_mode() {
        do_block_just_closed = flags.mode === &#039;DO_BLOCK&#039;;
        flags = flag_store.pop();
    }

    function in_array(what, arr) {
        for (var i = 0; i &lt; arr.length; i += 1) {
            if (arr[i] === what) {
                return true;
            }
        }
        return false;
    }

    function is_ternary_op() {
        var level = 0,
            colon_count = 0;
        for (var i = output.length - 1; i &gt;= 0; i--) {
            switch (output[i]) {
            case &#039;:&#039;:
                if (level === 0) {
                    colon_count++;
                }
                break;
            case &#039;?&#039;:
                if (level === 0) {
                    if (colon_count === 0) {
                        return true;
                    } else {
                        colon_count--;
                    }
                }
                break;
            case &#039;{&#039;:
                if (level === 0) {
                    return false;
                }
                level--;
                break;
            case &#039;(&#039;:
            case &#039;[&#039;:
                level--;
                break;
            case &#039;)&#039;:
            case &#039;]&#039;:
            case &#039;}&#039;:
                level++;
                break;
            }
        }
    }

    function get_next_token() {
        n_newlines = 0;
        if (parser_pos &gt;= input.length) {
            return [&#039;&#039;, &#039;TK_EOF&#039;];
        }
        var c = input.charAt(parser_pos);
        parser_pos += 1;
        var keep_whitespace = opt_keep_array_indentation &amp;&amp; is_array(flags.mode);
        wanted_newline = false;
        if (keep_whitespace) {
            var whitespace_count = 0;
            while (in_array(c, whitespace)) {
                if (c === &quot;\n&quot;) {
                    trim_output();
                    output.push(&quot;\n&quot;);
                    just_added_newline = true;
                    whitespace_count = 0;
                } else {
                    if (c === &#039;\t&#039;) {
                        whitespace_count += 4;
                    } else {
                        whitespace_count += 1;
                    }
                }
                if (parser_pos &gt;= input.length) {
                    return [&#039;&#039;, &#039;TK_EOF&#039;];
                }
                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 &lt; indent_level + 1; i += 1) {
                    output.push(indent_string);
                }
                if (flags.indentation_baseline !== -1) {
                    for (var i = 0; i &lt; whitespace_count - flags.indentation_baseline; i++) {
                        output.push(&#039; &#039;);
                    }
                }
            }
        } else {
            while (in_array(c, whitespace)) {
                if (c === &quot;\n&quot;) {
                    n_newlines += 1;
                }
                if (parser_pos &gt;= input.length) {
                    return [&#039;&#039;, &#039;TK_EOF&#039;];
                }
                c = input.charAt(parser_pos);
                parser_pos += 1;
            }
            if (opt_preserve_newlines) {
                if (n_newlines &gt; 1) {
                    for (var i = 0; i &lt; n_newlines; i += 1) {
                        print_newline(i === 0);
                        just_added_newline = true;
                    }
                }
            }
            wanted_newline = n_newlines &gt; 0;
        }
        if (in_array(c, wordchar)) {
            if (parser_pos &lt; input.length) {
                while (in_array(input.charAt(parser_pos), wordchar)) {
                    c += input.charAt(parser_pos);
                    parser_pos += 1;
                    if (parser_pos === input.length) {
                        break;
                    }
                }
            }
            if (parser_pos !== input.length &amp;&amp; c.match(/^[0-9]+[Ee]$/) &amp;&amp; (input.charAt(parser_pos) === &#039;-&#039; || input.charAt(parser_pos) === &#039;+&#039;)) {
                var sign = input.charAt(parser_pos);
                parser_pos += 1;
                var t = get_next_token(parser_pos);
                c += sign + t[0];
                return [c, &#039;TK_WORD&#039;];
            }
            if (c === &#039;in&#039;) {
                return [c, &#039;TK_OPERATOR&#039;];
            }
            if (wanted_newline &amp;&amp; last_type !== &#039;TK_OPERATOR&#039; &amp;&amp; !flags.if_line &amp;&amp; (opt_preserve_newlines || last_text !== &#039;var&#039;)) {
                print_newline();
            }
            return [c, &#039;TK_WORD&#039;];
        }
        if (c === &#039;(&#039; || c === &#039;[&#039;) {
            return [c, &#039;TK_START_EXPR&#039;];
        }
        if (c === &#039;)&#039; || c === &#039;]&#039;) {
            return [c, &#039;TK_END_EXPR&#039;];
        }
        if (c === &#039;{&#039;) {
            return [c, &#039;TK_START_BLOCK&#039;];
        }
        if (c === &#039;}&#039;) {
            return [c, &#039;TK_END_BLOCK&#039;];
        }
        if (c === &#039;;&#039;) {
            return [c, &#039;TK_SEMICOLON&#039;];
        }
        if (c === &#039;/&#039;) {
            var comment = &#039;&#039;;
            if (input.charAt(parser_pos) === &#039;*&#039;) {
                parser_pos += 1;
                if (parser_pos &lt; input.length) {
                    while (! (input.charAt(parser_pos) === &#039;*&#039; &amp;&amp; input.charAt(parser_pos + 1) &amp;&amp; input.charAt(parser_pos + 1) === &#039;/&#039;) &amp;&amp; parser_pos &lt; input.length) {
                        comment += input.charAt(parser_pos);
                        parser_pos += 1;
                        if (parser_pos &gt;= input.length) {
                            break;
                        }
                    }
                }
                parser_pos += 2;
                return [&#039;/*&#039; + comment + &#039;*/&#039;, &#039;TK_BLOCK_COMMENT&#039;];
            }
            if (input.charAt(parser_pos) === &#039;/&#039;) {
                comment = c;
                while (input.charAt(parser_pos) !== &quot;\x0d&quot; &amp;&amp; input.charAt(parser_pos) !== &quot;\x0a&quot;) {
                    comment += input.charAt(parser_pos);
                    parser_pos += 1;
                    if (parser_pos &gt;= input.length) {
                        break;
                    }
                }
                parser_pos += 1;
                if (wanted_newline) {
                    print_newline();
                }
                return [comment, &#039;TK_COMMENT&#039;];
            }
        }
        if (c === &quot;&#039;&quot; || c === &#039;&quot;&#039; || (c === &#039;/&#039; &amp;&amp; ((last_type === &#039;TK_WORD&#039; &amp;&amp; in_array(last_text, [&#039;return&#039;, &#039;do&#039;])) || (last_type === &#039;TK_START_EXPR&#039; || last_type === &#039;TK_START_BLOCK&#039; || last_type === &#039;TK_END_BLOCK&#039; || last_type === &#039;TK_OPERATOR&#039; || last_type === &#039;TK_EOF&#039; || last_type === &#039;TK_SEMICOLON&#039;)))) {
            var sep = c;
            var esc = false;
            var resulting_string = c;
            if (parser_pos &lt; input.length) {
                if (sep === &#039;/&#039;) {
                    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) === &#039;\\&#039;;
                            if (input.charAt(parser_pos) === &#039;[&#039;) {
                                in_char_class = true;
                            } else if (input.charAt(parser_pos) === &#039;]&#039;) {
                                in_char_class = false;
                            }
                        } else {
                            esc = false;
                        }
                        parser_pos += 1;
                        if (parser_pos &gt;= input.length) {
                            return [resulting_string, &#039;TK_STRING&#039;];
                        }
                    }
                } else {
                    while (esc || input.charAt(parser_pos) !== sep) {
                        resulting_string += input.charAt(parser_pos);
                        if (!esc) {
                            esc = input.charAt(parser_pos) === &#039;\\&#039;;
                        } else {
                            esc = false;
                        }
                        parser_pos += 1;
                        if (parser_pos &gt;= input.length) {
                            return [resulting_string, &#039;TK_STRING&#039;];
                        }
                    }
                }
            }
            parser_pos += 1;
            resulting_string += sep;
            if (sep === &#039;/&#039;) {
                while (parser_pos &lt; input.length &amp;&amp; in_array(input.charAt(parser_pos), wordchar)) {
                    resulting_string += input.charAt(parser_pos);
                    parser_pos += 1;
                }
            }
            return [resulting_string, &#039;TK_STRING&#039;];
        }
        if (c === &#039;#&#039;) {
            var sharp = &#039;#&#039;;
            if (parser_pos &lt; input.length &amp;&amp; in_array(input.charAt(parser_pos), digits)) {
                do {
                    c = input.charAt(parser_pos);
                    sharp += c;
                    parser_pos += 1;
                } while (parser_pos &lt; input.length &amp;&amp; c !== &#039;#&#039; &amp;&amp; c !== &#039;=&#039;);
                if (c === &#039;#&#039;) {
                    return [sharp, &#039;TK_WORD&#039;];
                } else {
                    return [sharp, &#039;TK_OPERATOR&#039;];
                }
            }
        }
        if (c === &#039;&lt;&#039; &amp;&amp; input.substring(parser_pos - 1, parser_pos + 3) === &#039;&lt;!--&#039;) {
            parser_pos += 3;
            return [&#039;&lt;!--&#039;, &#039;TK_COMMENT&#039;];
        }
        if (c === &#039;-&#039; &amp;&amp; input.substring(parser_pos - 1, parser_pos + 2) === &#039;--&gt;&#039;) {
            parser_pos += 2;
            if (wanted_newline) {
                print_newline();
            }
            return [&#039;--&gt;&#039;, &#039;TK_COMMENT&#039;];
        }
        if (in_array(c, punct)) {
            while (parser_pos &lt; input.length &amp;&amp; in_array(c + input.charAt(parser_pos), punct)) {
                c += input.charAt(parser_pos);
                parser_pos += 1;
                if (parser_pos &gt;= input.length) {
                    break;
                }
            }
            return [c, &#039;TK_OPERATOR&#039;];
        }
        return [c, &#039;TK_UNKNOWN&#039;];
    }
    indent_string = &#039;&#039;;
    while (opt_indent_size &gt; 0) {
        indent_string += opt_indent_char;
        opt_indent_size -= 1;
    }
    indent_level = opt_indent_level;
    input = js_source_text;
    last_word = &#039;&#039;;
    last_type = &#039;TK_START_EXPR&#039;;
    last_text = &#039;&#039;;
    last_last_text = &#039;&#039;;
    output = [];
    do_block_just_closed = false;
    whitespace = &quot;\n\r\t &quot;.split(&#039;&#039;);
    wordchar = &#039;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$&#039;.split(&#039;&#039;);
    digits = &#039;0123456789&#039;.split(&#039;&#039;);
    punct = &#039;+ - * / % &amp; ++ -- = += -= *= /= %= == === != !== &gt; &lt; &gt;= &lt;= &gt;&gt; &lt;&lt; &gt;&gt;&gt; &gt;&gt;&gt;= &gt;&gt;= &lt;&lt;= &amp;&amp; &amp;= | || ! !! , : ? ^ ^= |= ::&#039;.split(&#039; &#039;);
    line_starters = &#039;continue,try,throw,return,var,if,switch,case,default,for,while,break,function&#039;.split(&#039;,&#039;);
    flag_store = [];
    set_mode(&#039;BLOCK&#039;);
    parser_pos = 0;
    while (true) {
        var t = get_next_token(parser_pos);
        token_text = t[0];
        token_type = t[1];
        if (token_type === &#039;TK_EOF&#039;) {
            break;
        }
        switch (token_type) {
        case &#039;TK_START_EXPR&#039;:
            if (token_text === &#039;[&#039;) {
                if (last_type === &#039;TK_WORD&#039; || last_text === &#039;)&#039;) {
                    if (last_word === &#039;return&#039; || last_word === &#039;throw&#039;) {
                        print_single_space();
                    }
                    set_mode(&#039;(EXPRESSION)&#039;);
                    print_token();
                    break;
                }
                if (flags.mode === &#039;[EXPRESSION]&#039; || flags.mode === &#039;[INDENTED-EXPRESSION]&#039;) {
                    if (last_last_text === &#039;]&#039; &amp;&amp; last_text === &#039;,&#039;) {
                        if (!opt_keep_array_indentation) {
                            indent();
                            print_newline();
                        }
                        set_mode(&#039;[INDENTED-EXPRESSION]&#039;);
                    } else if (last_text === &#039;[&#039;) {
                        if (!opt_keep_array_indentation) {
                            indent();
                            print_newline();
                        }
                        set_mode(&#039;[INDENTED-EXPRESSION]&#039;);
                    } else {
                        set_mode(&#039;[EXPRESSION]&#039;);
                    }
                } else {
                    set_mode(&#039;[EXPRESSION]&#039;);
                }
            } else {
                set_mode(&#039;(EXPRESSION)&#039;);
            }
            if (last_text === &#039;;&#039; || last_type === &#039;TK_START_BLOCK&#039;) {
                print_newline();
            } else if (last_type === &#039;TK_END_EXPR&#039; || last_type === &#039;TK_START_EXPR&#039;) {} else if (last_type !== &#039;TK_WORD&#039; &amp;&amp; last_type !== &#039;TK_OPERATOR&#039;) {
                print_single_space();
            } else if (last_word === &#039;function&#039;) {
                if (opt_space_after_anon_function) {
                    print_single_space();
                }
            } else if (in_array(last_word, line_starters)) {
                print_single_space();
            }
            print_token();
            break;
        case &#039;TK_END_EXPR&#039;:
            if (token_text === &#039;]&#039; &amp;&amp; flags.mode === &#039;[INDENTED-EXPRESSION]&#039;) {
                unindent();
            }
            restore_mode();
            print_token();
            break;
        case &#039;TK_START_BLOCK&#039;:
            if (last_word === &#039;do&#039;) {
                set_mode(&#039;DO_BLOCK&#039;);
            } else {
                set_mode(&#039;BLOCK&#039;);
            }
            if (last_type !== &#039;TK_OPERATOR&#039; &amp;&amp; last_type !== &#039;TK_START_EXPR&#039;) {
                if (last_type === &#039;TK_START_BLOCK&#039;) {
                    print_newline();
                } else {
                    print_single_space();
                }
            }
            print_token();
            indent();
            break;
        case &#039;TK_END_BLOCK&#039;:
            if (last_type === &#039;TK_START_BLOCK&#039;) {
                if (just_added_newline) {
                    remove_indent();
                } else {
                    trim_output();
                }
                unindent();
            } else {
                unindent();
                print_newline();
            }
            print_token();
            restore_mode();
            break;
        case &#039;TK_WORD&#039;:
            if (do_block_just_closed) {
                print_single_space();
                print_token();
                print_single_space();
                do_block_just_closed = false;
                break;
            }
            if (token_text === &#039;function&#039;) {
                if ((just_added_newline || last_text == &#039;;&#039;) &amp;&amp; last_text !== &#039;{&#039;) {
                    n_newlines = just_added_newline ? n_newlines : 0;
                    for (var i = 0; i &lt; 2 - n_newlines; i++) {
                        print_newline(false);
                    }
                }
            }
            if (token_text === &#039;case&#039; || token_text === &#039;default&#039;) {
                if (last_text === &#039;:&#039;) {
                    remove_indent();
                } else {
                    unindent();
                    print_newline();
                    indent();
                }
                print_token();
                flags.in_case = true;
                break;
            }
            prefix = &#039;NONE&#039;;
            if (last_type === &#039;TK_END_BLOCK&#039;) {
                if (!in_array(token_text.toLowerCase(), [&#039;else&#039;, &#039;catch&#039;, &#039;finally&#039;])) {
                    prefix = &#039;NEWLINE&#039;;
                } else {
                    prefix = &#039;SPACE&#039;;
                    print_single_space();
                }
            } else if (last_type === &#039;TK_SEMICOLON&#039; &amp;&amp; (flags.mode === &#039;BLOCK&#039; || flags.mode === &#039;DO_BLOCK&#039;)) {
                prefix = &#039;NEWLINE&#039;;
            } else if (last_type === &#039;TK_SEMICOLON&#039; &amp;&amp; is_expression(flags.mode)) {
                prefix = &#039;SPACE&#039;;
            } else if (last_type === &#039;TK_STRING&#039;) {
                prefix = &#039;NEWLINE&#039;;
            } else if (last_type === &#039;TK_WORD&#039;) {
                prefix = &#039;SPACE&#039;;
            } else if (last_type === &#039;TK_START_BLOCK&#039;) {
                prefix = &#039;NEWLINE&#039;;
            } else if (last_type === &#039;TK_END_EXPR&#039;) {
                print_single_space();
                prefix = &#039;NEWLINE&#039;;
            }
            if (last_type !== &#039;TK_END_BLOCK&#039; &amp;&amp; in_array(token_text.toLowerCase(), [&#039;else&#039;, &#039;catch&#039;, &#039;finally&#039;])) {
                print_newline();
            } else if (in_array(token_text, line_starters) || prefix === &#039;NEWLINE&#039;) {
                if (last_text === &#039;else&#039;) {
                    print_single_space();
                } else if ((last_type === &#039;TK_START_EXPR&#039; || last_text === &#039;=&#039; || last_text === &#039;,&#039;) &amp;&amp; token_text === &#039;function&#039;) {} else if (last_text === &#039;return&#039; || last_text === &#039;throw&#039;) {
                    print_single_space();
                } else if (last_type !== &#039;TK_END_EXPR&#039;) {
                    if ((last_type !== &#039;TK_START_EXPR&#039; || token_text !== &#039;var&#039;) &amp;&amp; last_text !== &#039;:&#039;) {
                        if (token_text === &#039;if&#039; &amp;&amp; last_word === &#039;else&#039; &amp;&amp; last_text !== &#039;{&#039;) {
                            print_single_space();
                        } else {
                            print_newline();
                        }
                    }
                } else {
                    if (in_array(token_text, line_starters) &amp;&amp; last_text !== &#039;)&#039;) {
                        print_newline();
                    }
                }
            } else if (prefix === &#039;SPACE&#039;) {
                print_single_space();
            }
            print_token();
            last_word = token_text;
            if (token_text === &#039;var&#039;) {
                flags.var_line = true;
                flags.var_line_tainted = false;
            }
            if (token_text === &#039;if&#039; || token_text === &#039;else&#039;) {
                flags.if_line = true;
            }
            break;
        case &#039;TK_SEMICOLON&#039;:
            print_token();
            flags.var_line = false;
            break;
        case &#039;TK_STRING&#039;:
            if (last_type === &#039;TK_START_BLOCK&#039; || last_type === &#039;TK_END_BLOCK&#039; || last_type === &#039;TK_SEMICOLON&#039;) {
                print_newline();
            } else if (last_type === &#039;TK_WORD&#039;) {
                print_single_space();
            }
            print_token();
            break;
        case &#039;TK_OPERATOR&#039;:
            var start_delim = true;
            var end_delim = true;
            if (flags.var_line &amp;&amp; token_text === &#039;,&#039; &amp;&amp; (is_expression(flags.mode))) {
                flags.var_line_tainted = false;
            }
            if (flags.var_line) {
                if (token_text === &#039;,&#039;) {
                    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 === &#039;:&#039;) {
                        flags.var_line = false;
                    }
                }
            }
            if (last_text === &#039;return&#039; || last_text === &#039;throw&#039;) {
                print_single_space();
                print_token();
                break;
            }
            if (token_text === &#039;:&#039; &amp;&amp; flags.in_case) {
                print_token();
                print_newline();
                flags.in_case = false;
                break;
            }
            if (token_text === &#039;::&#039;) {
                print_token();
                break;
            }
            if (token_text === &#039;,&#039;) {
                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 === &#039;TK_END_BLOCK&#039;) {
                    print_token();
                    print_newline();
                } else {
                    if (flags.mode === &#039;BLOCK&#039;) {
                        print_token();
                        print_newline();
                    } else {
                        print_token();
                        print_single_space();
                    }
                }
                break;
            } else if (token_text === &#039;--&#039; || token_text === &#039;++&#039;) {
                if (last_text === &#039;;&#039;) {
                    if (flags.mode === &#039;BLOCK&#039;) {
                        print_newline();
                        start_delim = true;
                        end_delim = false;
                    } else {
                        start_delim = true;
                        end_delim = false;
                    }
                } else {
                    if (last_text === &#039;{&#039;) {
                        print_newline();
                    }
                    start_delim = false;
                    end_delim = false;
                }
            } else if ((token_text === &#039;!&#039; || token_text === &#039;+&#039; || token_text === &#039;-&#039;) &amp;&amp; (last_text === &#039;return&#039; || last_text === &#039;case&#039;)) {
                start_delim = true;
                end_delim = false;
            } else if ((token_text === &#039;!&#039; || token_text === &#039;+&#039; || token_text === &#039;-&#039;) &amp;&amp; last_type === &#039;TK_START_EXPR&#039;) {
                start_delim = false;
                end_delim = false;
            } else if (last_type === &#039;TK_OPERATOR&#039;) {
                start_delim = false;
                end_delim = false;
            } else if (last_type === &#039;TK_END_EXPR&#039;) {
                start_delim = true;
                end_delim = true;
            } else if (token_text === &#039;.&#039;) {
                start_delim = false;
                end_delim = false;
            } else if (token_text === &#039;:&#039;) {
                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 &#039;TK_BLOCK_COMMENT&#039;:
            print_newline();
            if (token_text.substring(0, 3) == &#039;/**&#039;) {
                print_javadoc_comment();
            } else {
                print_token();
            }
            print_newline();
            break;
        case &#039;TK_COMMENT&#039;:
            if (wanted_newline) {
                print_newline();
            } else {
                print_single_space();
            }
            print_token();
            print_newline();
            break;
        case &#039;TK_UNKNOWN&#039;:
            print_token();
            break;
        }
        last_last_text = last_text;
        last_type = token_type;
        last_text = token_text;
    }
    return output.join(&#039;&#039;).replace(/\n+$/, &#039;&#039;);
}</code></pre></div>]]></content>
			<author>
				<name><![CDATA[JSmаn]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24434</uri>
			</author>
			<updated>2014-04-25T10:07:35Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=82275#p82275</id>
		</entry>
</feed>
