1 (изменено: XGuest, 2012-05-16 17:57:56)

Тема: VBS: Parsing & Beautify & Minify кода JScript & VBScript

Доброго времени суток
Даже собственный хорошо откоментированный код читается, если он отформатирован,
а что говорить о чужом коде.
Покопал интернет, кое-что нашел, но хоть сам переписывай.
Может кото что посоветует

Beautify VBS of VBS


FileOut = WScript.Arguments(0)

With CreateObject("Scripting.FileSystemObject")
 Do While .FileExists(FileOut & BakCount)
  BakCount="." & Right("0" & CStr(i+1),2) & ".bak"
 Loop
 FileInp=FileOut & BakCount
 .GetFile(FileOut).Move FileInp
 Strinp=.GetFile(FileInp).OpenAsTextStream(1).ReadAll
 StrOut=BeautifyVBS(Strinp,1)
 .OpenTextFile(FileOut,2,True,False).Write StrOut
End With

Function BeautifyVBS(sSource,nTabSpacing)
 ' Takes VBScript source code and rebuilds the indentation.
 Dim sRawLine,sLine,sTest,bAdjustIndent,bInQuote
 Dim iIndentIndex,iIndex,oS,sWhiteSpace,aRows,aKey(34)
 Const INDENT_String=0
 Const INDENT_Exeception_String=1
 Const INDENT_Pre_Indent=2
 Const INDENT_Post_Indent=3
 ' The indent and unindent list is as complete as I
 ' could make it(from the MS VBScript reference).
 aKey(0)=Array("if "," then",0,1)
 aKey(1)=Array("select ","",0,2)
 aKey(2)=Array("sub ","",0,1)
 aKey(3)=Array("function ","",0,1)
 aKey(4)=Array("do ","",0,1)
 aKey(5)=Array("while ","",0,1)
 aKey(6)=Array("for ","",0,1)
 aKey(7)=Array("case ","", - 1,1)
 aKey(8)=Array("with ","",0,1)
 aKey(9)=Array("class ","",0,1)
 aKey(10)=Array("public sub","",0,1)
 aKey(11)=Array("private sub ","",0,1)
 aKey(12)=Array("public function ","",0,1)
 aKey(13)=Array("private function ","",0,1)
 aKey(14)=Array("property get ","",0,1)
 aKey(15)=Array("public property get ","",0,1)
 aKey(16)=Array("private property get ","",0,1)
 aKey(17)=Array("property let ","",0,1)
 aKey(18)=Array("public property let ","",0,1)
 aKey(19)=Array("private property let ","",0,1)
 aKey(20)=Array("property set ","",0,1)
 aKey(21)=Array("public property set ","",0,1)
 aKey(22)=Array("private property set ","",0,1)
 aKey(23)=Array("else ","", - 1,1)
 aKey(24)=Array("elseif ","", - 1,1)
 aKey(25)=Array("end if","", - 1,0)
 aKey(26)=Array("end select","", - 2,0)
 aKey(27)=Array("end sub","", - 1,0)
 aKey(28)=Array("end function","", - 1,0)
 aKey(29)=Array("loop","", - 1,0)
 aKey(30)=Array("wend","", - 1,0)
 aKey(31)=Array("next","", - 1,0)
 aKey(32)=Array("end class","", - 1,0)
 aKey(33)=Array("end property","", - 1,0)
 aKey(34)=Array("end with","", - 1,0)
 sWhiteSpace =Chr(32) & vbTab
 Set oS=CreateObject("ADODB.Stream")
 oS.Type=2                                 ' ASCII
 oS.Open
 iIndentIndex=0
 For Each sRawLine in Split(sSource,vbCrLf)
  ' Remove all whitespace on the left
  iIndex=1
  If Len(sRawLine)>0 Then
   Do While iIndex<=Len(sRawLine)
    If InStr(sWhiteSpace,Mid(sRawLine,iIndex,1))=0 Then Exit Do
    iIndex=iIndex+1
   Loop
  End If
  If iIndex > Len(sRawLine) Then sLine="" Else sLine=Mid(sRawLine,iIndex)
  ' Remove all whitespace on the right
  iIndex=Len(sLine)
  Do While iIndex > 0
   If InStr(sWhiteSpace,Mid(sLine,iIndex,1))=0 Then Exit Do
   iIndex=iIndex - 1
  Loop
  If iIndex < Len(sLine) Then sLine=Left(sLine,iIndex)
  sTest   =LCase(LTrim(sLine))
  ' Find any in-line comment marker,and truncate the comment if it exists.
  bInQuote=False
  For iIndex=1 To Len(sTest)
   If Not bInQuote And Mid(sTest,iIndex,1)="'" Then Exit For
   If Mid(sTest,iIndex,1)="""" Then bInQuote=Not bInQuote
  Next
  If iIndex < Len(sTest) Then  ' Truncate comment
   sTest =Left(sTest,iIndex-1)
   ' Truncate whitespace again
   iIndex=Len(sTest)
   Do While iIndex>0
    If InStr(sWhiteSpace,Mid(sTest,iIndex,1))=0 Then Exit Do
    iIndex=iIndex-1
   Loop
   If iIndex<Len(sTest) Then sTest=Left(sTest,iIndex)
  End If
  sTest=LCase(LTrim(sTest)) & Space(32)
  ' Adjust Indentation as needed
  bAdjustIndent=False
  For iIndex=0 To UBound(aKey,1)
   If Left(sTest,Len(aKey(iIndex)(INDENT_String)))=aKey(iIndex)(INDENT_String) Then
    If Len(aKey(iIndex)(INDENT_Exeception_String))=0 Or Right(RTrim(sTest),Len(aKey(iIndex)(INDENT_Exeception_String)))=aKey(iIndex)(INDENT_Exeception_String) Then
     bAdjustIndent=True
     Exit For
    End If
   End If
  Next
  If bAdjustIndent Then
   iIndentIndex=iIndentIndex+aKey(iIndex)(INDENT_Pre_Indent)
   If iIndentIndex < 0 Then iIndentIndex=0
  End If
  If nTabSpacing <= 0 Then Sep=vbTab Else Sep=Chr(32)
  oS.WriteText String(iIndentIndex, Sep)&sLine&vbCrLf
  If bAdjustIndent Then
   iIndentIndex=iIndentIndex+aKey(iIndex)(INDENT_Post_Indent)
   If iIndentIndex<0 Then iIndentIndex=0
  End If
 Next
 oS.Position=0
 BeautifyVBS=oS.ReadText(-1)
 oS.Close
 Set oS=Nothing
End Function

Beautify VBS of perl


#!/usr/bin/perl
# vbscript beautifier
# (C)2001 Niek Albers, DaanSystems
# http://www.daansystems.com

use strict;
use Getopt::Std;
my $version  = "1.10";
my $location = "$0/..";

if ( !@ARGV ) {
    print STDERR header();
    print STDERR qq(
Homepage: http://www.daansystems.com
Comments/Bugs: nieka\@daansystems.com
------------------------------------------
Usage: vbsbeaut [options] [files]

options:
 -i         Use standard input (as text filter).
 -s <val>   Uses spaces instead of tabs.
 -u         Make keywords uppercase.
 -l         Make keywords lowercase.
 -n         Don\'t change keywords.
 -d         Don\'t split Dim statements.

files:
 filenames  Wildcards allowed.
------------------------------------------
);
    exit;
}
my %options;
getopts( 'dr:iulns:', \%options );
print STDERR header();
if ( $options{'i'} ) {
    undef $/;
    my $text = <STDIN>;
    $/ = "\n";
    print do_all($text);
}
else {
    foreach my $filestring (@ARGV) {
        beautify($filestring) if ( -T $filestring );
    }
}

sub header {
    return qq(------------------------------------------
VBScript Beautifier v$version
(C)2001-2007 By Niek Albers - DaanSystems
------------------------------------------
);
}

sub beautify {
    my $filename = $_[0];
    my $text = read_file($filename) || die "ERROR: Can\'t open $filename.\n\n";
    my $beautified = do_all($text);
    write_file( "$filename.bak", $text );
    write_file( $filename, $beautified );
}

sub do_all {
    my $input = $_[0];
    my @inputlines = split( /\n/, $input );
    print STDERR "- Searching clientside VBScript delimiters.\n";
    replace_client_vbscript_tags( \@inputlines );
    $input = join( "\n", @inputlines );
    print STDERR "- Searching serverside VBScript delimiters.\n";
    my @html = gethtml( \$input );
    print STDERR "- Searching comments in clientside VBScript.\n";
    my @get_client_comments = getclientcomments( \$input );
    @inputlines = split( /\n/, $input );
    print STDERR "- Searching quoted text.\n";
    my @quoted = getquoted( \@inputlines );
    print STDERR "- Searching VBScript comments.\n";
    my @comments = getcomments( \@inputlines );

    #    print STDERR "- Splitting If..Then..Else on one line.\n";
    #    newline_after_then( \@inputlines );
    $input = join( "\n", @inputlines );

    #    preprocess( \$input );
    get_on_error_resume_next( \$input );
    @inputlines = split( /\n/, $input );
    if ( !$options{'d'} ) {
        print STDERR "- Splitting Dim statements.\n";
        preprocess2( \@inputlines );
    }
    $input = join( "\n", @inputlines );
    @inputlines = split( /\n/, $input );
    print STDERR "- Adjusting spaces around operators.\n";
    fixspaces( \@inputlines );
    if ( !$options{'n'} ) {
        print STDERR "- Modifying keywords.\n";
        replacekeywords( \@inputlines );
    }
    print STDERR "- Processing indent.\n";
    processindent( \@inputlines );
    print STDERR "- Lining out assignment statements.\n";
    lineoutequalsigns( \@inputlines );
    $input = join( "\n", @inputlines );
    put_on_error_resume_next( \$input );
    print STDERR "- Removing redundant newlines.\n";
    removeredundantenters( \$input );
    put_function_comments_to_declaration( \$input );
    putcomments( \$input, \@comments );
    putquoted( \$input, \@quoted );
    putclientcomments( \$input, \@get_client_comments );
    puthtml( \$input, \@html );
    $input =~ s/^\n\n+/\n/;
    replace_client_vbscript_tags_back( \$input );
    print STDERR "- All Done!\n";
    print STDERR "------------------------------------------\n";
    return $input;
}

sub newline_after_then {
    my $lines = $_[0];
    foreach my $line (@$lines) {
        $line =~ s/\s*then\s*/ then\n/gi;       # set enters behind then statements
    }
}

sub preprocess {
    my $text = $_[0];

#    $$text =~ s/\belse\b/\nelse\n/gi;
#    $$text =~ s/(?<!\bcase\b)\selse\b/\nelse\n/gi;
#    $$text =~ s/\belseif\b/\nelseif/gi;
#    $$text =~ s/end if/\nend if\n/gi;          # set enters behind end if statements
#    $$text =~ s/\n\s*\n*/\n/gs;                # remove extra enters
}

# get html for server side vbscript (asp)
sub gethtml {
    my $text = $_[0];
    my ($starthtml) = $$text =~ m/^(.*?<%)/gs;  # find first html part
    $$text =~ s/^(.*?<%)/%[html]%/gs;           # substitute with template variable.
    my ($endhtml) = $$text =~ m/.*(%>.*)$/gs;   # find last html part
    $$text =~ s/(.*)(%>.*)$/$1%[html]%/gs;      # substitute with template variable.
    my @html = $$text =~
      m/(%>.*?<%)/gs; # return array of everythinh between >% and <% (aspswitch)
    $$text =~ s/(%>.*?<%)/%[html]%/gs;          # substitute with template variable.
    unshift( @html, $starthtml );
    push( @html, $endhtml );
    return @html;
}

# place back server side vbscript (asp)
sub puthtml {
    my $text    = $_[0];
    my $html    = $_[1];
    my $counter = 0;
    $$text =~ s/%\[html\]%/$$html[$counter++]/gse;
    $$text =~ s/(\S+)\s*%>/$1 %>/gs;
    $$text =~ s/<%\n/%[extraenter]%/gs;
    $$text =~ s/<%\s*(\S+)/<% $1/gs;
    $$text =~ s/%\[extraenter\]%/<%\n/gs;
}

sub replace_client_vbscript_tags {
    my $lines    = $_[0];
    my $count    = 0;
    my $found    = 0;
    my $endfound = 0;
    foreach my $line (@$lines) {
        if ( $found == 0 ) {
            $found =
              $line =~ s{(<\s*script.*?vbscript.*?>)}{$1 %[clientscript]%<%}i
              if ( $line !~ m{".*?<\s*script.*?vbscript.*?>.*?"}i );
        }
        else {
            $endfound = $line =~ s{(</\s*script\s*>)}{%>%[clientscript]% $1}i
              if ( $line !~ m{".*?</\s*script\s*>.*?"}i )
              ;    # substitute with template variable.
            $found = 0 if ( $endfound != 0 );
        }
    }
}

sub replace_client_vbscript_tags_back {
    my $text = $_[0];
    $$text =~ s/%>%\[clientscript\]%/\n/gs;
    $$text =~ s/%\[clientscript\]%<%/\n/gs;
}

sub getclientcomments {
    my $text     = $_[0];
    my @comments = $$text =~ m{(<!--|-->)}g;    # return all comments
    my $count    = $$text =~
      s{(<!--|-->)}{%[clientcomments]%}g;       # substitute with template variable.
    die "ERROR: Clientside comments not balanced!\n\n"
      if ( ( $count % 2 ) != 0 );
    return @comments;
}

sub putclientcomments {
    my $text    = $_[0];
    my $html    = $_[1];
    my $counter = 0;
    $$text =~ s/%\[clientcomments\]%/$$html[$counter++]/gse;
}

sub getcomments {
    my $lines = $_[0];
    my @allcomments;
    foreach my $line (@$lines) {
        my @comments =
          $line =~ m/(\'.*)/;                   # return array of everything that is a comment
        $line =~ s/(\'.*)/%[comment]%/;         # substitute with template variable.
        push( @allcomments, @comments );
    }
    return @allcomments;
}

sub putcomments {
    my $text     = $_[0];
    my $comments = $_[1];
    my $counter  = 0;
    $$text =~ s/%\[comment\]%/$$comments[$counter++]/gse;
}

sub getquoted {
    my $lines = $_[0];
    my @allquoted;
    foreach my $line (@$lines) {
        my @quoted =
          $line =~ m/(".*?")/g;                 # return array of everythinh between ""
        $line =~ s/(".*?")/%[quoted]%/g;        # substitute with template variable.
        push( @allquoted, @quoted );
    }
    return @allquoted;
}

sub putquoted {
    my $text    = $_[0];
    my $quoted  = $_[1];
    my $counter = 0;
    $$text =~ s/%\[quoted\]%/$$quoted[$counter++]/gse;
}

sub preprocess2 {
    my $lines = $_[0];
    foreach my $line (@$lines) {
        if ( $line =~ m/\bdim\b/i
          ) # replace all occurrances of comma separated dim variables on new lines
        {
            $line =~ s/,\s*/\ndim /g;
        }
    }
}

sub fixspaces {
    my $lines = $_[0];
    foreach my $line (@$lines) {
        $line =~ s/^\s*(.*?)\s*$/$1/;           # strip leading and trailing spaces
        $line =~ s/\s*(=|<|>|-|\+|&)\s*/ $1 /g; # add spaces around signs
        $line =~ s/\s*<\s*>\s*/ <> /g; # remove spaces around and in  <> signs
        $line =~ s/\s*<\s*=\s*/ <= /g; # remove spaces around and in  <= signs
        $line =~ s/\s*=\s*<\s*/ =< /g; # remove spaces around and in  =< signs
        $line =~ s/\s*>\s*=\s*/ >= /g; # remove spaces around and in  >= signs
        $line =~ s/\s*=\s*>\s*/ => /g; # remove spaces around and in  => signs
        $line =~ s/\s*!\s*=\s*/ != /g; # remove spaces around and in  != signs
        $line =~ s/\s*<\s*%\s*/<% /g;  # remove spaces around <% signs
        $line =~ s/\s*%\s*>/ %>/g;     # remove spaces around %> signs
        $line =~ s/\s*_\s*$/ _/;       # add space before _ sign at end of line.
    }
}

sub countdelta {
    my $line     = $_[0];
    my $keywords = $_[1];
    my $indents  = $_[2];
    my $delta    = 0;
    foreach my $keyword (@$keywords) {
        $delta += $$indents{$keyword}
          if ( $$line =~ s/\b$keyword\b//gi );  # subtract closers
    }
    return $delta;
}

sub wordcount {
    my ($line) = @_;
    my $count = () = $line =~ /\w+/g;
    return $count;
}

sub get_keywords_indent {
    my ($section) = @_;
    open( FILE, "$location/vbsbe_01.inc" )
      || die "Can\'t open $location/vbsbe_01.inc";
    my @keywords            = ();
    my @singleline_keywords = ();
    my %indents;
    foreach my $line (<FILE>) {
        chomp($line);
        next if ( $line =~ m/^\s*$/ );
        next if ( $line =~ m/;/ );       # this is a line with comments....
        my ( $indent, $words, $singleline ) = split( /,/, $line );
        $indents{$words} = $indent;
        if ( !$singleline ) {
            push( @keywords, $words );
        }
        else {
            push( @singleline_keywords, $words );
        }
    }
    close(FILE);
    my @keywords_sorted =
      sort { wordcount($main::b) <=> wordcount($main::a) } @keywords;
    my @singleline_keywords_sorted =
      sort { wordcount($main::b) <=> wordcount($main::a) } @singleline_keywords;
    return ( \@keywords_sorted, \@singleline_keywords_sorted, \%indents );
}

sub processindent {
    my $lines  = $_[0];
    my $spaces = "\t";
    $spaces = ' ' x $options{'s'} if ( $options{'s'} );
    my $tabtotal = 0;
    my ( $indentors, $singleline_indentors, $indents ) = get_keywords_indent();
    foreach my $line (@$lines) {
        my $delta       = 0;
        my $singledelta = 0;
        my $linecopy    = $line;
        my $olddelta    = $delta;
        singlelineifthen( \$linecopy );
        $delta += countdelta( \$linecopy, $indentors, $indents );
        $singledelta -=
          countdelta( \$linecopy, $singleline_indentors, $indents );
        $tabtotal +=
          ( $delta < 0 ) ? $delta : 0;    # subtract closing braces/parentheses
        my $i = ( $tabtotal > 0 ) ? $tabtotal : 0;    # create tab index
        $tabtotal +=
          ( $delta > 0 )
          ? $delta
          : 0;    # add opening braces/parentheses for next print
        $line = $spaces x ( $i - $singledelta ) . $line;
        $line = "\n" . $line if ( $delta > $olddelta );
        $line = $line . "\n" if ( $delta < $olddelta );
    }

    #    die "ERROR: Indentation error!\n\n" if ( $tabtotal != 0 );
}

sub replacekeywords {
    my $lines = $_[0];
    undef $/;
    open( FILE, "$location/vbsbe_00.inc" )
      || die "Can\'t open $location/vbsbe_00.inc" . "\n\n";

    #    binmode( FILE, ":crlf" );

    #	s/\015?\012/\n/;
    my $keywordsstring = <FILE>;
    close(FILE);
    $/ = "\n";
    my @keywords = split( /\n/, $keywordsstring );
    foreach my $line (@$lines) {
        foreach my $keyword (@keywords) {
            chomp($keyword);
            $keyword = uc($keyword) if ( $options{'u'} );
            $keyword = lc($keyword) if ( $options{'l'} );
            $line =~
              s/(\b)$keyword(\b)/$1$keyword$2/gi;    # substitute whole keywords
        }
    }
}

sub removeredundantenters {
    my $input = $_[0];
    $$input =~ s/\n\s*\n+/\n\n/gs;
}

sub get_linenumbers_with_statements {
    my $lines = $_[0];
    my @statement_linenumbers;
    my $counter = 0;
    foreach my $line (@$lines) {
        push( @statement_linenumbers, $counter ) if ( is_assignment($line) );
        $counter++;
    }
    return @statement_linenumbers;
}

sub lineoutequalsigns {
    my $lines                 = $_[0];
    my @statement_linenumbers = get_linenumbers_with_statements( \@$lines );
    my $lastlinenumber        = 0;
    my @linenumberlist        = ();
    foreach my $linenumber (@statement_linenumbers) {
        if (
            (
                   $lastlinenumber == $linenumber - 1
                || $lastlinenumber == $linenumber - 2
            )
            && $lastlinenumber != 0
          )
        {
            push( @linenumberlist, $lastlinenumber );
            push( @linenumberlist, $linenumber );
        }
        else {
            if ( scalar(@linenumberlist) >= 2 ) {
                lineout( $lines, \@linenumberlist );
            }
            @linenumberlist = ();
        }
        $lastlinenumber = $linenumber;
    }
}

sub is_assignment {
    my $line = $_[0];
    return 1 if ( $line =~ m/^\s*(set)?\s*\S+\s*=.*$/i );
    return 0;
}

sub lineout {
    my $lines          = $_[0];
    my $linenumbers    = $_[1];
    my $last_equal_pos = get_max_equal_pos_from_lines( $lines, $linenumbers );
    foreach my $linenumber (@$linenumbers) {
        my $equalsign = index( @$lines[$linenumber], '=' );
        my $diff = $equalsign - $last_equal_pos;
        @$lines[$linenumber] =~ s/=/' ' x abs($diff) .'='/e if ( $diff < 0 );
    }
}

sub get_max_equal_pos_from_lines {
    my $lines       = $_[0];
    my $linenumbers = $_[1];
    my @equalpositions;
    foreach my $linenumber (@$linenumbers) {
        push( @equalpositions, index( @$lines[$linenumber], '=' ) );
    }
    return max_from_array(@equalpositions);
}

sub max_from_array {
    my $max;
    foreach (@_) { $max = $_ if $_ > $max }
    return $max;
}

sub read_file {
    my ($file) = @_;
    local (*F);
    my $r;
    my (@r);
    open( F, "<$file" ) || die "ERROR: open $file: $!\n\n";

    #   binmode( F, ":crlf" );
    @r = <F>;
    close(F);
    return @r if wantarray;
    return join( "", @r );
}

sub write_file {
    my ( $f, @data ) = @_;
    local (*F);
    open( F, ">$f" ) || die "ERROR: open >$f: $!\n\n";

    #   binmode( F, ":crlf" );
    ( print F @data ) || die "ERROR: write $f: $!\n\n";
    close(F)          || die "ERROR: close $f: $!\n\n";
    return 1;
}

sub get_on_error_resume_next {
    my $text = $_[0];
    $$text =~ s/on\s+error\s+resume\s+next/%[resumenext]%/gis;
}

sub put_on_error_resume_next {
    my $text = $_[0];
    $$text =~ s/%\[resumenext\]%/On Error Resume Next/gis;
}

sub put_function_comments_to_declaration {
    my $text = $_[0];
    $$text =~ s/%\[comment\]%\n\nFunction/%[comment]%\nFunction/gis;
    $$text =~ s/%\[comment\]%\n\nSub/%[comment]%\nSub/gis;
}

sub singlelineifthen {
    my $line = $_[0];

    $$line =~ s/if.*?then\s+//gi;
}

С наилучшими пожеланиями
XGuest

2 (изменено: XGuest, 2012-05-16 17:55:44)

Re: VBS: Parsing & Beautify & Minify кода JScript & VBScript

Beautify JS of JS

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

 JS Beautifier
---------------


  Written by Einar Lielmanis, <einar@jsbeautifier.org>
      http://jsbeautifier.org/

  Originally converted to javascript by Vital, <vital76@gmail.com>
  "End braces on own line" added by Chris J. Shull, <chrisjshull@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,
    preserve_max_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk,

    jslint_happy (default false) — if true, then jslint-stricter mode is enforced.

            jslint_happy   !jslint_happy
            ---------------------------------
             function ()      function()

    brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "expand-strict"
            put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.

            expand-strict: put brace on own line even in such cases:

                var a =
                {
                    a: 5,
                    b: 6
                }
            This mode may break your scripts - e.g "return { a: 1 }" will be broken into two lines, so beware.

    space_before_conditional: should the space before conditional statement be added, "if(true)" vs "if (true)"

    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 wanted_newline, just_added_newline, n_newlines;
    var preindent_string = '';


    // Some interpreters have unexpected results with foo = baz || bar;
    options = options ? options : {};

    var opt_brace_style;

    // compatibility
    if (options.space_after_anon_function !== undefined && options.jslint_happy === undefined) {
        options.jslint_happy = options.space_after_anon_function;
    }
    if (options.braces_on_own_line !== undefined) { //graceful handling of deprecated option
        opt_brace_style = options.braces_on_own_line ? "expand" : "collapse";
    }
    opt_brace_style = options.brace_style ? options.brace_style : (opt_brace_style ? opt_brace_style : "collapse");


    var opt_indent_size = options.indent_size ? options.indent_size : 4;
    var opt_indent_char = options.indent_char ? options.indent_char : ' ';
    var opt_preserve_newlines = typeof options.preserve_newlines === 'undefined' ? true : options.preserve_newlines;
    var opt_max_preserve_newlines = typeof options.max_preserve_newlines === 'undefined' ? false : options.max_preserve_newlines;
    var opt_jslint_happy = options.jslint_happy === 'undefined' ? false : options.jslint_happy;
    var opt_keep_array_indentation = typeof options.keep_array_indentation === 'undefined' ? false : options.keep_array_indentation;
    var opt_space_before_conditional = typeof options.space_before_conditional === 'undefined' ? true : options.space_before_conditional;
    var opt_indent_case = typeof options.indent_case === 'undefined' ? false : options.indent_case;

    just_added_newline = false;

    // cache the source's length.
    var input_length = js_source_text.length;

    function trim_output(eat_newlines) {
        eat_newlines = typeof eat_newlines === 'undefined' ? false : eat_newlines;
        while (output.length && (output[output.length - 1] === ' '
            || output[output.length - 1] === indent_string
            || output[output.length - 1] === preindent_string
            || (eat_newlines && (output[output.length - 1] === '\n' || output[output.length - 1] === '\r')))) {
            output.pop();
        }
    }

    function trim(s) {
        return s.replace(/^\s\s*|\s\s*$/, '');
    }

    function force_newline()
    {
        var old_keep_array_indentation = opt_keep_array_indentation;
        opt_keep_array_indentation = false;
        print_newline()
        opt_keep_array_indentation = old_keep_array_indentation;
    }

    function print_newline(ignore_repeated) {

        flags.eat_next_space = false;
        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");
        }
        if (preindent_string) {
            output.push(preindent_string);
        }
        for (var i = 0; i < flags.indentation_level; i += 1) {
            output.push(indent_string);
        }
        if (flags.var_line && flags.var_line_reindented) {
            output.push(indent_string); // skip space-stuffing, if indenting with a tab
        }
        if (flags.case_body) {
          output.push(indent_string);
        }
    }



    function print_single_space() {

        if (last_type === 'TK_COMMENT') {
            // no you will not print just a space after a comment
            return print_newline(true);
        }

        if (flags.eat_next_space) {
            flags.eat_next_space = false;
            return;
        }
        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;
        flags.eat_next_space = false;
        output.push(token_text);
    }

    function indent() {
        flags.indentation_level += 1;
    }


    function remove_indent() {
        if (output.length && output[output.length - 1] === indent_string) {
            output.pop();
        }
    }

    function set_mode(mode) {
        if (flags) {
            flag_store.push(flags);
        }
        flags = {
            previous_mode: flags ? flags.mode : 'BLOCK',
            mode: mode,
            var_line: false,
            var_line_tainted: false,
            var_line_reindented: false,
            in_html_comment: false,
            if_line: false,
            in_case: false,
            case_body: false,
            eat_next_space: false,
            indentation_baseline: -1,
            indentation_level: (flags ? flags.indentation_level + (flags.case_body?1:0) + ((flags.var_line && flags.var_line_reindented) ? 1 : 0) : 0),
            ternary_depth: 0
        };
    }

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

    function is_expression(mode) {
        return in_array(mode, ['[EXPRESSION]', '(EXPRESSION)', '(FOR-EXPRESSION)', '(COND-EXPRESSION)']);
    }

    function restore_mode() {
        do_block_just_closed = flags.mode === 'DO_BLOCK';
        if (flag_store.length > 0) {
            var mode = flags.mode;
            flags = flag_store.pop();
            flags.previous_mode = mode;
        }
    }

    function all_lines_start_with(lines, c) {
        for (var i = 0; i < lines.length; i++) {
            if (trim(lines[i])[0] != c) {
                return false;
            }
        }
        return true;
    }

    function is_special_word(word)
    {
        return in_array(word, ['case', 'return', 'do', 'if', 'throw', 'else']);
    }

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

    function look_up(exclude) {
        var local_pos = parser_pos;
        var c = input.charAt(local_pos);
        while (in_array(c, whitespace) && c != exclude) {
            local_pos++;
            if (local_pos >= input_length) return 0;
            c = input.charAt(local_pos);
        }
        return c;
    }

    function get_next_token() {
        n_newlines = 0;

        if (parser_pos >= input_length) {
            return ['', 'TK_EOF'];
        }

        wanted_newline = false;

        var c = input.charAt(parser_pos);
        parser_pos += 1;


        var keep_whitespace = opt_keep_array_indentation && is_array(flags.mode);

        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 if (c === '\r') {
                        // nothing
                    } 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) {
                var i;
                for (i = 0; i < flags.indentation_level + 1; i += 1) {
                    output.push(indent_string);
                }
                if (flags.indentation_baseline !== -1) {
                    for (i = 0; i < whitespace_count - flags.indentation_baseline; i++) {
                        output.push(' ');
                    }
                }
            }

        } else {
            while (in_array(c, whitespace)) {

                if (c === "\n") {
                    n_newlines += ( (opt_max_preserve_newlines) ? (n_newlines <= opt_max_preserve_newlines) ? 1: 0: 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 (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'
                && last_type !== 'TK_EQUALS'
                && !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 /* ... */
            var inline_comment = true;
            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) {
                        c = input.charAt(parser_pos);
                        comment += c;
                        if (c === '\x0d' || c === '\x0a') {
                            inline_comment = false;
                        }
                        parser_pos += 1;
                        if (parser_pos >= input_length) {
                            break;
                        }
                    }
                }
                parser_pos += 2;
                if (inline_comment && n_newlines == 0) {
                    return ['/*' + comment + '*/', 'TK_INLINE_COMMENT'];
                } else {
                    return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT'];
                }
            }
            // peek for comment // ...
            if (input.charAt(parser_pos) === '/') {
                comment = c;
                while (input.charAt(parser_pos) !== '\r' && input.charAt(parser_pos) !== '\n') {
                    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' && is_special_word(last_text)) ||
                (last_text === ')' && in_array(flags.previous_mode, ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) ||
                (last_type === 'TK_COMMENT' || last_type === 'TK_START_EXPR' || last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_OPERATOR' || last_type === 'TK_EQUALS' || 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 === '#') {


            if (output.length === 0 && input.charAt(parser_pos) === '!') {
                // shebang
                resulting_string = c;
                while (parser_pos < input_length && c != '\n') {
                    c = input.charAt(parser_pos);
                    resulting_string += c;
                    parser_pos += 1;
                }
                output.push(trim(resulting_string) + '\n');
                print_newline();
                return get_next_token();
            }



            // 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 === '#') {
                    //
                } else if (input.charAt(parser_pos) === '[' && input.charAt(parser_pos + 1) === ']') {
                    sharp += '[]';
                    parser_pos += 2;
                } else if (input.charAt(parser_pos) === '{' && input.charAt(parser_pos + 1) === '}') {
                    sharp += '{}';
                    parser_pos += 2;
                }
                return [sharp, 'TK_WORD'];
            }
        }

        if (c === '<' && input.substring(parser_pos - 1, parser_pos + 3) === '<!--') {
            parser_pos += 3;
            c = '<!--';
            while (input[parser_pos] != '\n' && parser_pos < input_length) {
                c += input[parser_pos];
                parser_pos++;
            }
            flags.in_html_comment = true;
            return [c, 'TK_COMMENT'];
        }

        if (c === '-' && flags.in_html_comment && input.substring(parser_pos - 1, parser_pos + 2) === '-->') {
            flags.in_html_comment = false;
            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;
                }
            }

            if (c === '=') {
                return [c, 'TK_EQUALS'];
            } else {
                return [c, 'TK_OPERATOR'];
            }
        }

        return [c, 'TK_UNKNOWN'];
    }

    //----------------------------------
    indent_string = '';
    while (opt_indent_size > 0) {
        indent_string += opt_indent_char;
        opt_indent_size -= 1;
    }

    while (js_source_text && (js_source_text[0] === ' ' || js_source_text[0] === '\t')) {
        preindent_string += js_source_text[0];
        js_source_text = js_source_text.substring(1);
    }
    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('');

    punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::';
    punct += ' <%= <% %> <?= <? ?>'; // try to be a good boy and try not to break the markup language identifiers
    punct = 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 (in_array(last_text, line_starters)) {
                        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]') {
                            flags.mode = '[INDENTED-EXPRESSION]';
                            if (!opt_keep_array_indentation) {
                                indent();
                            }
                        }
                        set_mode('[EXPRESSION]');
                        if (!opt_keep_array_indentation) {
                            print_newline();
                        }
                    } else if (last_text === '[') {
                        if (flags.mode === '[EXPRESSION]') {
                            flags.mode = '[INDENTED-EXPRESSION]';
                            if (!opt_keep_array_indentation) {
                                indent();
                            }
                        }
                        set_mode('[EXPRESSION]');

                        if (!opt_keep_array_indentation) {
                            print_newline();
                        }
                    } else {
                        set_mode('[EXPRESSION]');
                    }
                } else {
                    set_mode('[EXPRESSION]');
                }



            } else {
                if (last_word === 'for') {
                    set_mode('(FOR-EXPRESSION)');
                } else if (in_array(last_word, ['if', 'while'])) {
                    set_mode('(COND-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' || last_text === '.') {
                if (wanted_newline) {
                    print_newline();
                }
                // do nothing on (( and )( and ][ and ]( and .(
            } else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') {
                print_single_space();
            } else if (last_word === 'function' || last_word === 'typeof') {
                // function() vs function ()
                if (opt_jslint_happy) {
                    print_single_space();
                }
            } else if (in_array(last_text, line_starters) || last_text === 'catch') {
                if (opt_space_before_conditional) {
                    print_single_space();
                }
            }
            print_token();

            break;

        case 'TK_END_EXPR':
            if (token_text === ']') {
                if (opt_keep_array_indentation) {
                    if (last_text === '}') {
                        // trim_output();
                        // print_newline(true);
                        remove_indent();
                        print_token();
                        restore_mode();
                        break;
                    }
                } else {
                    if (flags.mode === '[INDENTED-EXPRESSION]') {
                        if (last_text === ']') {
                            restore_mode();
                            print_newline();
                            print_token();
                            break;
                        }
                    }
                }
            }
            restore_mode();
            print_token();
            break;

        case 'TK_START_BLOCK':

            if (last_word === 'do') {
                set_mode('DO_BLOCK');
            } else {
                set_mode('BLOCK');
            }
            if (opt_brace_style=="expand" || opt_brace_style=="expand-strict") {
                var empty_braces = false;
                if (opt_brace_style == "expand-strict")
                {
                    empty_braces = (look_up() == '}');
                    if (!empty_braces) {
                        print_newline(true);
                    }
                } else {
                    if (last_type !== 'TK_OPERATOR') {
                        if (last_text === '=' || (is_special_word(last_text) && last_text !== 'else')) {
                            print_single_space();
                        } else {
                            print_newline(true);
                        }
                    }
                }
                print_token();
                if (!empty_braces) indent();
            } else {
                if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') {
                    if (last_type === 'TK_START_BLOCK') {
                        print_newline();
                    } else {
                        print_single_space();
                    }
                } else {
                    // if TK_OPERATOR or TK_START_EXPR
                    if (is_array(flags.previous_mode) && last_text === ',') {
                        if (last_last_text === '}') {
                            // }, { in array context
                            print_single_space();
                        } else {
                            print_newline(); // [a, b, c, {
                        }
                    }
                }
                indent();
                print_token();
            }

            break;

        case 'TK_END_BLOCK':
            restore_mode();
            if (opt_brace_style=="expand" || opt_brace_style == "expand-strict") {
                if (last_text !== '{') {
                    print_newline();
                }
                print_token();
            } else {
                if (last_type === 'TK_START_BLOCK') {
                    // nothing
                    if (just_added_newline) {
                        remove_indent();
                    } else {
                        // {}
                        trim_output();
                    }
                } else {
                    if (is_array(flags.mode) && opt_keep_array_indentation) {
                        // we REALLY need a newline here, but newliner would skip that
                        opt_keep_array_indentation = false;
                        print_newline();
                        opt_keep_array_indentation = true;

                    } else {
                        print_newline();
                    }
                }
                print_token();
            }
            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 (flags.var_line) {
                    flags.var_line_reindented = true;
                }
                if ((just_added_newline || last_text === ';') && last_text !== '{'
                && last_type != 'TK_BLOCK_COMMENT' && last_type != 'TK_COMMENT') {
                    // 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;
                    if ( ! opt_preserve_newlines) {
                        n_newlines = 1;
                    }

                    for (var i = 0; i < 2 - n_newlines; i++) {
                        print_newline(false);
                    }
                }
            }

            if (token_text === 'case' || token_text === 'default') {
                if (last_text === ':' || flags.case_body) {
                    // switch cases following one another
                    remove_indent();
                } else {
                    // case statement starts in the same line where switch
                    if (!opt_indent_case)
                        flags.indentation_level--;
                    print_newline();
                    if (!opt_indent_case)
                        flags.indentation_level++;
                }
                print_token();
                flags.in_case = true;
                flags.case_body = false;
                break;
            }

            prefix = 'NONE';

            if (last_type === 'TK_END_BLOCK') {

                if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
                    prefix = 'NEWLINE';
                } else {
                    if (opt_brace_style=="expand" || opt_brace_style=="end-expand" || opt_brace_style == "expand-strict") {
                        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') {
                if (last_text === 'else') {
                    // eat newlines between ...else *** some_op...
                    // won't preserve extra newlines in this place (if any), but don't care that much
                    trim_output(true);
                }
                prefix = 'SPACE';
            } else if (last_type === 'TK_START_BLOCK') {
                prefix = 'NEWLINE';
            } else if (last_type === 'TK_END_EXPR') {
                print_single_space();
                prefix = 'NEWLINE';
            }

            if (in_array(token_text, line_starters) && last_text !== ')') {
                if (last_text == 'else') {
                    prefix = 'SPACE';
                } else {
                    prefix = 'NEWLINE';
                }

                if (token_text === 'function' && (last_text === 'get' || last_text === 'set')) {
                    prefix = 'SPACE';
                }
            }

            if (flags.if_line && last_type === 'TK_END_EXPR') {
                flags.if_line = false;
            }
            if (in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
                if (last_type !== 'TK_END_BLOCK' || opt_brace_style=="expand" || opt_brace_style=="end-expand" || opt_brace_style == "expand-strict") {
                    print_newline();
                } else {
                    trim_output(true);
                    print_single_space();
                }
            } else if (prefix === 'NEWLINE') {
                if ((last_type === 'TK_START_EXPR' || last_text === '=' || last_text === ',') && token_text === 'function') {
                    // no need to force newline on 'function': (function
                    // DONOTHING
                } else if (token_text === 'function' && last_text == 'new') {
                    print_single_space();
                } else if (is_special_word(last_text)) {
                    // 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 {
                            flags.var_line = false;
                            flags.var_line_reindented = false;
                            print_newline();
                        }
                    }
                } else if (in_array(token_text, line_starters) && last_text != ')') {
                    flags.var_line = false;
                    flags.var_line_reindented = false;
                    print_newline();
                }
            } else if (is_array(flags.mode) && last_text === ',' && last_last_text === '}') {
                print_newline(); // }, in lists get a newline treatment
            } else if (prefix === 'SPACE') {
                print_single_space();
            }
            print_token();
            last_word = token_text;

            if (token_text === 'var') {
                flags.var_line = true;
                flags.var_line_reindented = false;
                flags.var_line_tainted = false;
            }

            if (token_text === 'if') {
                flags.if_line = true;
            }
            if (token_text === 'else') {
                flags.if_line = false;
            }

            break;

        case 'TK_SEMICOLON':

            print_token();
            flags.var_line = false;
            flags.var_line_reindented = false;
            if (flags.mode == 'OBJECT') {
                // OBJECT mode is weird and doesn't get reset too well.
                flags.mode = 'BLOCK';
            }
            break;

        case 'TK_STRING':

            if (last_type === 'TK_END_EXPR' && in_array(flags.previous_mode, ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) {
                print_single_space();
            } else if (last_type == 'TK_STRING' || 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_EQUALS':
            if (flags.var_line) {
                // just got an '=' in a var-line, different formatting/line-breaking, etc will now be done
                flags.var_line_tainted = true;
            }
            print_single_space();
            print_token();
            print_single_space();
            break;

        case 'TK_OPERATOR':

            var space_before = true;
            var space_after = 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();
                        flags.var_line_reindented = true;
                        flags.var_line_tainted = false;
                        print_newline();
                        break;
                    } else {
                        flags.var_line_tainted = false;
                    }
                // } else if (token_text === ':') {
                    // hmm, when does this happen? tests don't catch this
                    // flags.var_line = false;
                }
            }

            if (is_special_word(last_text)) {
                // "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) {
                if (opt_indent_case)
                    flags.case_body = true;
                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' && flags.mode !== "(EXPRESSION)") {
                    print_token();
                    if (flags.mode === 'OBJECT' && last_text === '}') {
                        print_newline();
                    } else {
                        print_single_space();
                    }
                } else {
                    if (flags.mode === 'OBJECT') {
                        print_token();
                        print_newline();
                    } else {
                        // EXPR or DO_BLOCK
                        print_token();
                        print_single_space();
                    }
                }
                break;
            // } else if (in_array(token_text, ['--', '++', '!']) || (in_array(token_text, ['-', '+']) && (in_array(last_type, ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS']) || in_array(last_text, line_starters) || in_array(last_text, ['==', '!=', '+=', '-=', '*=', '/=', '+', '-'])))) {
            } else if (in_array(token_text, ['--', '++', '!']) || (in_array(token_text, ['-', '+']) && (in_array(last_type, ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS', 'TK_OPERATOR']) || in_array(last_text, line_starters)))) {
                // unary operators (and binary +/- pretending to be unary) special cases

                space_before = false;
                space_after = false;

                if (last_text === ';' && is_expression(flags.mode)) {
                    // for (;; ++i)
                    //        ^^^
                    space_before = true;
                }
                if (last_type === 'TK_WORD' && in_array(last_text, line_starters)) {
                    space_before = true;
                }

                if (flags.mode === 'BLOCK' && (last_text === '{' || last_text === ';')) {
                    // { foo; --i }
                    // foo(); --bar;
                    print_newline();
                }
            } else if (token_text === '.') {
                // decimal digits or object.property
                space_before = false;

            } else if (token_text === ':') {
                if (flags.ternary_depth == 0) {
                    flags.mode = 'OBJECT';
                    space_before = false;
                } else {
                    flags.ternary_depth -= 1;
                }
            } else if (token_text === '?') {
                flags.ternary_depth += 1;
            }
            if (space_before) {
                print_single_space();
            }

            print_token();

            if (space_after) {
                print_single_space();
            }

            if (token_text === '!') {
                // flags.eat_next_space = true;
            }

            break;

        case 'TK_BLOCK_COMMENT':

            var lines = token_text.split(/\x0a|\x0d\x0a/);

            if (all_lines_start_with(lines.slice(1), '*')) {
                // javadoc: reformat and reindent
                print_newline();
                output.push(lines[0]);
                for (i = 1; i < lines.length; i++) {
                    print_newline();
                    output.push(' ');
                    output.push(trim(lines[i]));
                }

            } else {

                // simple block comment: leave intact
                if (lines.length > 1) {
                    // multiline comment block starts with a new line
                    print_newline();
                } else {
                    // single-line /* comment */ stays where it is
                    if (last_type === 'TK_END_BLOCK') {
                        print_newline();
                    } else {
                        print_single_space();
                    }

                }

                for (i = 0; i < lines.length; i++) {
                    output.push(lines[i]);
                    output.push('\n');
                }

            }
            if(look_up('\n') != '\n')
                print_newline();
            break;

        case 'TK_INLINE_COMMENT':
            print_single_space();
            print_token();
            if (is_expression(flags.mode)) {
                print_single_space();
            } else {
                force_newline();
            }
            break;

        case 'TK_COMMENT':

            // print_newline();
            if (wanted_newline) {
                print_newline();
            } else {
                print_single_space();
            }
            print_token();
            if(look_up('\n') != '\n')
                force_newline();
            break;

        case 'TK_UNKNOWN':
            if (is_special_word(last_text)) {
                print_single_space();
            }
            print_token();
            break;
        }

        last_last_text = last_text;
        last_type = token_type;
        last_text = token_text;
    }

    var sweet_code = preindent_string + output.join('').replace(/[\n ]+$/, '');
    return sweet_code;

}

// Add support for CommonJS. Just put this file somewhere on your require.paths
// and you will be able to `var js_beautify = require("beautify").js_beautify`.
if (typeof exports !== "undefined")
    exports.js_beautify = js_beautify;

3 (изменено: XGuest, 2012-05-16 18:00:00)

Re: VBS: Parsing & Beautify & Minify кода JScript & VBScript

Minify JS of JS


/*! 
jsmin.js - 2010-01-15
Author: NanaLich (http://www.cnblogs.com/NanaLich)
Another patched version for jsmin.js patched by Billy Hoffman, 
this version will try to keep CR LF pairs inside the important comments
away from being changed into double LF pairs. 

jsmin.js - 2009-11-05
Author: Billy Hoffman
This is a patched version of jsmin.js created by Franck Marcia which
supports important comments denoted with /*! ...
Permission is hereby granted to use the Javascript version under the same
conditions as the jsmin.js on which it is based.

jsmin.js - 2006-08-31
Author: Franck Marcia
This work is an adaptation of jsminc.c published by Douglas Crockford.
Permission is hereby granted to use the Javascript version under the same
conditions as the jsmin.c on which it is based.

jsmin.c
2006-05-04

Copyright (c) 2002 Douglas Crockford  (www.crockford.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

The Software shall be used for Good, not Evil.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Update:
add level:
1: minimal, keep linefeeds if single
2: normal, the standard algorithm
3: agressive, remove any linefeed and doesn't take care of potential
missing semicolons (can be regressive)
store stats
jsmin.oldSize
jsmin.newSize
*/

String.prototype.has = function(c) {
  return this.indexOf(c) > -1;
};

function jsmin(comment, input, level) {

  if(input === undefined) {
    input = comment;
    comment = '';
    level = 2;
  } else if(level === undefined || level < 1 || level > 3) {
    level = 2;
  }

  if(comment.length > 0) {
    comment += '\n';
  }

  var a = '',
		b = '',
		EOF = -1,
		LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
		DIGITS = '0123456789',
		ALNUM = LETTERS + DIGITS + '_$\\',
		theLookahead = EOF;


  /* isAlphanum -- return true if the character is a letter, digit, underscore,
  dollar sign, or non-ASCII character.
  */

  function isAlphanum(c) {
    return c != EOF && (ALNUM.has(c) || c.charCodeAt(0) > 126);
  }


  /* getc(IC) -- return the next character. Watch out for lookahead. If the
  character is a control character, translate it to a space or
  linefeed.
  */

  var iChar = 0, lInput = input.length;
  function getc() {

    var c = theLookahead;
    if(iChar == lInput) {
      return EOF;
    }
    theLookahead = EOF;
    if(c == EOF) {
      c = input.charAt(iChar);
      ++iChar;
    }
    if(c >= ' ' || c == '\n') {
      return c;
    }
    if(c == '\r') {
      return '\n';
    }
    return ' ';
  }
  function getcIC() {
    var c = theLookahead;
    if(iChar == lInput) {
      return EOF;
    }
    theLookahead = EOF;
    if(c == EOF) {
      c = input.charAt(iChar);
      ++iChar;
    }
    if(c >= ' ' || c == '\n' || c == '\r') {
      return c;
    }
    return ' ';
  }


  /* peek -- get the next character without getting it.
  */

  function peek() {
    theLookahead = getc();
    return theLookahead;
  }


  /* next -- get the next character, excluding comments. peek() is used to see
  if a '/' is followed by a '/' or '*'.
  */

  function next() {

    var c = getc();
    if(c == '/') {
      switch(peek()) {
        case '/':
          for(; ; ) {
            c = getc();
            if(c <= '\n') {
              return c;
            }
          }
          break;
        case '*':
          //this is a comment. What kind?
          getc();
          if(peek() == '!') {
            // kill the extra one
            getc();
            //important comment
            var d = '/*!';
            for(; ; ) {
              c = getcIC(); // let it know it's inside an important comment
              switch(c) {
                case '*':
                  if(peek() == '/') {
                    getc();
                    return d + '*/';
                  }
                  break;
                case EOF:
                  throw 'Error: Unterminated comment.';
                default:
                  //modern JS engines handle string concats much better than the 
                  //array+push+join hack.
                  d += c;
              }
            }
          } else {
            //unimportant comment
            for(; ; ) {
              switch(getc()) {
                case '*':
                  if(peek() == '/') {
                    getc();
                    return ' ';
                  }
                  break;
                case EOF:
                  throw 'Error: Unterminated comment.';
              }
            }
          }
          break;
        default:
          return c;
      }
    }
    return c;
  }


  /* action -- do something! What you do is determined by the argument:
  1   Output A. Copy B to A. Get the next B.
  2   Copy B to A. Get the next B. (Delete A).
  3   Get the next B. (Delete B).
  action treats a string as a single character. Wow!
  action recognizes a regular expression if it is preceded by ( or , or =.
  */

  function action(d) {

    var r = [];

    if(d == 1) {
      r.push(a);
    }

    if(d < 3) {
      a = b;
      if(a == '\'' || a == '"') {
        for(; ; ) {
          r.push(a);
          a = getc();
          if(a == b) {
            break;
          }
          if(a <= '\n') {
            throw 'Error: unterminated string literal: ' + a;
          }
          if(a == '\\') {
            r.push(a);
            a = getc();
          }
        }
      }
    }

    b = next();

    if(b == '/' && '(,=:[!&|'.has(a)) {
      r.push(a);
      r.push(b);
      for(; ; ) {
        a = getc();
        if(a == '/') {
          break;
        } else if(a == '\\') {
          r.push(a);
          a = getc();
        } else if(a <= '\n') {
          throw 'Error: unterminated Regular Expression literal';
        }
        r.push(a);
      }
      b = next();
    }

    return r.join('');
  }


  /* m -- Copy the input to the output, deleting the characters which are
  insignificant to JavaScript. Comments will be removed. Tabs will be
  replaced with spaces. Carriage returns will be replaced with
  linefeeds.
  Most spaces and linefeeds will be removed.
  */

  function m() {

    var r = [];
    a = '\n';

    r.push(action(3));

    while(a != EOF) {
      switch(a) {
        case ' ':
          if(isAlphanum(b)) {
            r.push(action(1));
          } else {
            r.push(action(2));
          }
          break;
        case '\n':
          switch(b) {
            case '{':
            case '[':
            case '(':
            case '+':
            case '-':
              r.push(action(1));
              break;
            case ' ':
              r.push(action(3));
              break;
            default:
              if(isAlphanum(b)) {
                r.push(action(1));
              } else {
                if(level == 1 && b != '\n') {
                  r.push(action(1));
                } else {
                  r.push(action(2));
                }
              }
          }
          break;
        default:
          switch(b) {
            case ' ':
              if(isAlphanum(a)) {
                r.push(action(1));
                break;
              }
              r.push(action(3));
              break;
            case '\n':
              if(level == 1 && a != '\n') {
                r.push(action(1));
              } else {
                switch(a) {
                  case '}':
                  case ']':
                  case ')':
                  case '+':
                  case '-':
                  case '"':
                  case '\'':
                    if(level == 3) {
                      r.push(action(3));
                    } else {
                      r.push(action(1));
                    }
                    break;
                  default:
                    if(isAlphanum(a)) {
                      r.push(action(1));
                    } else {
                      r.push(action(3));
                    }
                }
              }
              break;
            default:
              r.push(action(1));
              break;
          }
      }
    }

    return r.join('');
  }

  jsmin.oldSize = input.length;
  ret = m(input);
  jsmin.newSize = ret.length;

  return comment + ret;

}

4

Re: VBS: Parsing & Beautify & Minify кода JScript & VBScript

Packer JS of JS


var VERSION = '1.0.0';
var AUTHOR = 'Rob Seiler'; /* seiler@elr.com.au */

/* Get command line arguments */
function JS_getArgs() {
  var args = [];
  var objArgs = WScript.Arguments;
  if (objArgs.length > 0) {
    for (var i = 0; i < objArgs.length; i++) {
      args[i] = objArgs(i); /* sic - index in "()" - an object, not an array! */
    }
  }
  return (args);
}

/* Read the input file */
function JS_readFile(fname) {
  var s = '';
  var ForReading = 1;
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  var ts = fso.OpenTextFile(fname, ForReading);
  while (!ts.AtEndOfStream) {
    s += ts.ReadLine() + '\n';
  }
  ts.Close();
  return (s);
}

/* Show help if needed - eg 0 command line arguments */
function JS_Help() {
  WScript.Echo('Compress and encode a Javascript source file using Dean Edwards "Packer"');
  WScript.Echo('  Version : ' + VERSION);
  WScript.Echo('  Syntax  : program sourcefile [_encoding] [_fastDecode] [_specialChars]\n');
}

/* Main program: Get arguments; read input file; output packed string */
function main() {
  var params = [];
  params = JS_getArgs();
  params[1] = (typeof(params[1]) == 'undefined') ? 62 : params[1]; // -dean : changed defaults
  params[2] = (typeof(params[2]) == 'undefined') ? 1 : params[2];
  params[3] = (typeof(params[3]) == 'undefined') ? 0 : params[3];
  if (params[0] > '') {
    var $script = JS_readFile(params[0]);
    if ($script > '') {
      $script = pack($script, params[1], params[2], params[3]); /* Returns the Dean Edwards "packed" string */
      WScript.Echo($script);
    } else {
      JS_Help();
    }
  } else {
    JS_Help();
  }
}

/* Do the job */
main();

function ICommon(that) {
  if (that != null) {
    that.inherit = Common.prototype.inherit;
    that.specialize = Common.prototype.specialize
  }
  return that
};
ICommon.specialize = function(p, c) {
  if (!p) p = {};
  if (!c) c = p.constructor;
  if (c == {}.constructor) c = new Function("this.inherit()");
  c.valueOf = new Function("return this");
  c.valueOf.prototype = new this.valueOf;
  c.valueOf.prototype.specialize(p);
  c.prototype = new c.valueOf;
  c.valueOf.prototype.constructor = c.prototype.constructor = c;
  c.ancestor = this;
  c.specialize = arguments.callee;
  c.ancestorOf = this.ancestorOf;
  return c
};
ICommon.valueOf = new Function("return this");
ICommon.valueOf.prototype = {
  constructor: ICommon,
  inherit: function() {
    return arguments.callee.caller.ancestor.apply(this, arguments)
  },
  specialize: function(that) {
    if (this == this.constructor.prototype && this.constructor.specialize) {
      return this.constructor.valueOf.prototype.specialize(that)
    }
    for (var i in that) {
      switch (i) {
      case "constructor":
      case "toString":
      case "valueOf":
        continue
      }
      if (typeof that[i] == "function" && that[i] != this[i]) {
        that[i].ancestor = this[i]
      }
      this[i] = that[i]
    }
    if (that.toString != this.toString && that.toString != {}.toString) {
      that.toString.ancestor = this.toString;
      this.toString = that.toString
    }
    return this
  }
};

function Common() {};
this.Common = ICommon.specialize({
  constructor: Common,
  toString: function() {
    return "[common " + (this.constructor.className || "Object") + "]"
  },
  instanceOf: function(klass) {
    return this.constructor == klass || klass.ancestorOf(this.constructor)
  }
});
Common.className = "Common";
Common.ancestor = null;
Common.ancestorOf = function(klass) {
  while (klass && klass.ancestor != this) klass = klass.ancestor;
  return Boolean(klass)
};
Common.valueOf.ancestor = ICommon;

function ParseMaster() {
  var E = 0,
    R = 1,
    L = 2;
  var G = /\(/g,
    S = /\$\d/,
    I = /^\$\d+$/,
    T = /(['"])\1\+(.*)\+\1\1$/,
    ES = /\\./g,
    Q = /'/,
    DE = /\x01[^\x01]*\x01/g;
  var self = this;
  this.add = function(e, r) {
    if (!r) r = "";
    var l = (_14(String(e)).match(G) || "").length + 1;
    if (S.test(r)) {
      if (I.test(r)) {
        r = parseInt(r.slice(1)) - 1
      } else {
        var i = l;
        var q = Q.test(_14(r)) ? '"' : "'";
        while (i) r = r.split("$" + i--).join(q + "+a[o+" + i + "]+" + q);
        r = new Function("a,o", "return" + q + r.replace(T, "$1") + q)
      }
    }
    _31(e || "/^$/", r, l)
  };
  this.exec = function(s) {
    _3.length = 0;
    return _28(_5(s, this.escapeChar).replace(new RegExp(_1, this.ignoreCase ? "gi" : "g"), _29), this.escapeChar).replace(DE, "")
  };
  this.reset = function() {
    _1.length = 0
  };
  var _3 = [];
  var _1 = [];
  var _30 = function() {
      return "(" + String(this[E]).slice(1, -1) + ")"
    };
  _1.toString = function() {
    return this.join("|")
  };

  function _31() {
    arguments.toString = _30;
    _1[_1.length] = arguments
  }

  function _29() {
    if (!arguments[0]) return "";
    var i = 1,
      j = 0,
      p;
    while (p = _1[j++]) {
      if (arguments[i]) {
        var r = p[R];
        switch (typeof r) {
        case "function":
          return r(arguments, i);
        case "number":
          return arguments[r + i]
        }
        var d = (arguments[i].indexOf(self.escapeChar) == -1) ? "" : "\x01" + arguments[i] + "\x01";
        return d + r
      } else i += p[L]
    }
  };

  function _5(s, e) {
    return e ? s.replace(new RegExp("\\" + e + "(.)", "g"), function(m, c) {
      _3[_3.length] = c;
      return e
    }) : s
  };

  function _28(s, e) {
    var i = 0;
    return e ? s.replace(new RegExp("\\" + e, "g"), function() {
      return e + (_3[i++] || "")
    }) : s
  };

  function _14(s) {
    return s.replace(ES, "")
  }
};
ParseMaster.prototype = {
  constructor: ParseMaster,
  ignoreCase: false,
  escapeChar: ""
};

function pack(_script, _encoding, _fastDecode, _specialChars) {
  var I = "$1";
  _script += "\n";
  _encoding = Math.min(parseInt(_encoding), 95);

  function _15(s) {
    var i, p;
    for (i = 0;
    (p = _6[i]); i++) {
      s = p(s)
    }
    return s
  };
  var _25 = function(p, a, c, k, e, d) {
      while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);
      return p
    };
  var _26 = function() {
      if (!''.replace(/^/, String)) {
        while (c--) d[e(c)] = k[c] || e(c);
        k = [function(e) {
          return d[e]
        }];
        e = function() {
          return '\\w+'
        };
        c = 1
      }
    };
  var _6 = [];

  function _4(p) {
    _6[_6.length] = p
  };

  function _18(s) {
    var p = new ParseMaster;
    p.escapeChar = "\\";
    p.add(/'[^'\n\r]*'/, I);
    p.add(/"[^"\n\r]*"/, I);
    p.add(/\/\/[^\n\r]*[\n\r]/, " ");
    p.add(/\/\*[^*]*\*+([^\/][^*]*\*+)*\//, " ");
    p.add(/\s+(\/[^\/\n\r\*][^\/\n\r]*\/g?i?)/, "$2");
    p.add(/[^\w\x24\/'"*)\?:]\/[^\/\n\r\*][^\/\n\r]*\/g?i?/, I);
    if (_specialChars) p.add(/;;;[^\n\r]+[\n\r]/);
    p.add(/\(;;\)/, I);
    p.add(/;+\s*([};])/, "$2");
    s = p.exec(s);
    p.add(/(\b|\x24)\s+(\b|\x24)/, "$2 $3");
    p.add(/([+\-])\s+([+\-])/, "$2 $3");
    p.add(/\s+/, "");
    return p.exec(s)
  };

  function _17(s) {
    var p = new ParseMaster;
    p.add(/((\x24+)([a-zA-Z_]+))(\d*)/, function(m, o) {
      var l = m[o + 2].length;
      var s = l - Math.max(l - m[o + 3].length, 0);
      return m[o + 1].substr(s, l) + m[o + 4]
    });
    var r = /\b_[A-Za-z\d]\w*/;
    var k = _13(s, _9(r), _21);
    var e = k.e;
    p.add(r, function(m, o) {
      return e[m[o]]
    });
    return p.exec(s)
  };

  function _16(s) {
    if (_encoding > 62) s = _20(s);
    var p = new ParseMaster;
    var e = _12(_encoding);
    var r = (_encoding > 62) ? /\w\w+/ : /\w+/;
    k = _13(s, _9(r), e);
    var e = k.e;
    p.add(r, function(m, o) {
      return e[m[o]]
    });
    return s && _27(p.exec(s), k)
  };

  function _13(s, r, e) {
    var a = s.match(r);
    var so = [];
    var en = {};
    var pr = {};
    if (a) {
      var u = [];
      var p = {};
      var v = {};
      var c = {};
      var i = a.length,
        j = 0,
        w;
      do {
        w = "$" + a[--i];
        if (!c[w]) {
          c[w] = 0;
          u[j] = w;
          p["$" + (v[j] = e(j))] = j++
        }
        c[w]++
      } while (i);
      i = u.length;
      do {
        w = u[--i];
        if (p[w] != null) {
          so[p[w]] = w.slice(1);
          pr[p[w]] = true;
          c[w] = 0
        }
      } while (i);
      u.sort(function(m1, m2) {
        return c[m2] - c[m1]
      });
      j = 0;
      do {
        if (so[i] == null) so[i] = u[j++].slice(1);
        en[so[i]] = v[i]
      } while (++i < u.length)
    }
    return {
      s: so,
      e: en,
      p: pr
    }
  };

  function _27(p, k) {
    var E = _10("e\\(c\\)", "g");
    p = "'" + _5(p) + "'";
    var a = Math.min(k.s.length, _encoding) || 1;
    var c = k.s.length;
    for (var i in k.p) k.s[i] = "";
    k = "'" + k.s.join("|") + "'.split('|')";
    var e = _encoding > 62 ? _11 : _12(a);
    e = String(e).replace(/_encoding/g, "a").replace(/arguments\.callee/g, "e");
    var i = "c" + (a > 10 ? ".toString(a)" : "");
    if (_fastDecode) {
      var d = _19(_26);
      if (_encoding > 62) d = d.replace(/\\\\w/g, "[\\xa1-\\xff]");
      else if (a < 36) d = d.replace(E, i);
      if (!c) d = d.replace(_10("(c)\\s*=\\s*1"), "$1=0")
    }
    var u = String(_25);
    if (_fastDecode) {
      u = u.replace(/\{/, "{" + d + ";")
    }
    u = u.replace(/"/g, "'");
    if (_encoding > 62) {
      u = u.replace(/'\\\\b'\s*\+|\+\s*'\\\\b'/g, "")
    }
    if (a > 36 || _encoding > 62 || _fastDecode) {
      u = u.replace(/\{/, "{e=" + e + ";")
    } else {
      u = u.replace(E, i)
    }
    u = pack(u, 0, false, true);
    var p = [p, a, c, k];
    if (_fastDecode) {
      p = p.concat(0, "{}")
    }
    return "eval(" + u + "(" + p + "))\n"
  };

  function _12(a) {
    return a > 10 ? a > 36 ? a > 62 ? _11 : _22 : _23 : _24
  };
  var _24 = function(c) {
      return c
    };
  var _23 = function(c) {
      return c.toString(36)
    };
  var _22 = function(c) {
      return (c < _encoding ? '' : arguments.callee(parseInt(c / _encoding))) + ((c = c % _encoding) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
    };
  var _11 = function(c) {
      return (c < _encoding ? '' : arguments.callee(c / _encoding)) + String.fromCharCode(c % _encoding + 161)
    };
  var _21 = function(c) {
      return "_" + c
    };

  function _5(s) {
    return s.replace(/([\\'])/g, "\\$1")
  };

  function _20(s) {
    return s.replace(/[\xa1-\xff]/g, function(m) {
      return "\\x" + m.charCodeAt(0).toString(16)
    })
  };

  function _10(s, f) {
    return new RegExp(s.replace(/\$/g, "\\$"), f)
  };

  function _19(f) {
    with(String(f)) return slice(indexOf("{") + 1, lastIndexOf("}"))
  };

  function _9(r) {
    return new RegExp(String(r).slice(1, -1), "g")
  };
  _4(_18);
  if (_specialChars) _4(_17);
  if (_encoding) _4(_16);
  return _15(_script)
};

Unpacker JS of JS


//
// Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
// written by Einar Lielmanis <einar@jsbeautifier.org>
//
// Coincidentally, it can defeat a couple of other eval-based compressors.
//
// usage:
//
// if (P_A_C_K_E_R.detect(some_string)) {
//     var unpacked = P_A_C_K_E_R.unpack(some_string);
// }
// 
//

var P_A_C_K_E_R = {
    detect: function (str) {
        return P_A_C_K_E_R._starts_with(str.toLowerCase().replace(/ +/g, ''), 'eval(function(') ||
               P_A_C_K_E_R._starts_with(str.toLowerCase().replace(/ +/g, ''), 'eval((function(') ;
    },

    unpack: function (str) {
        var unpacked_source = '';
        if (P_A_C_K_E_R.detect(str)) {
            try {
                eval('unpacked_source = ' + str.substring(4) + ';')
                if (typeof unpacked_source == 'string' && unpacked_source) {
                    str = unpacked_source;
                }
            } catch (error) {
                // well, it failed. we'll just return the original, instead of crashing on user.
            }
        }
        return str;
    },

    _starts_with: function (str, what) {
        return str.substr(0, what.length) === what;
    },

    run_tests: function (sanity_test) {
        var t = sanity_test || new SanityTest();
        t.test_function(P_A_C_K_E_R.detect, "P_A_C_K_E_R.detect");
        t.expect('', false);
        t.expect('var a = b', false);
        t.expect('eval(function(p,a,c,k,e,r', true);
        t.expect('eval ( function(p, a, c, k, e, r', true);
        t.test_function(P_A_C_K_E_R.unpack, 'P_A_C_K_E_R.unpack');
        t.expect("eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',3,3,'var||a'.split('|'),0,{}))",
            'var a=1');

        var starts_with_a = function(what) { return P_A_C_K_E_R._starts_with(what, 'a'); }
        t.test_function(starts_with_a, "P_A_C_K_E_R._starts_with(?, a)");
        t.expect('abc', true);
        t.expect('bcd', false);
        t.expect('a', true);
        t.expect('', false);
        return t;
    }
}

5

Re: VBS: Parsing & Beautify & Minify кода JScript & VBScript

Доброго времени суток

Не мог бы кто ткнуть в хорошую (русскую) документацию по Tidy

С наилучшими пожеланиями
XGuest