JavaScript-Packer-2.05/000755 000770 000120 00000000000 13616276755 016220 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.05/README000644 000770 000120 00000007345 13616276425 017103 0ustar00leejohnsonadmin000000 000000 NAME JavaScript::Packer - Perl version of Dean Edwards' Packer.js VERSION Version 2.04 DESCRIPTION A JavaScript Compressor This module is an adaptation of Dean Edwards' Packer.js. Additional information: http://dean.edwards.name/packer/ SYNOPSIS use JavaScript::Packer; my $packer = JavaScript::Packer->init(); $packer->minify( $javascript, $opts ); To return a scalar without changing the input simply use (e.g. example 2): my $ret = $packer->minify( $javascript, $opts ); For backward compatibility it is still possible to call 'minify' as a function: JavaScript::Packer::minify( $javascript, $opts ); The first argument must be a scalarref of javascript-code. Second argument must be a hashref of options. Possible options are: compress Defines compression level. Possible values are 'clean', 'shrink', 'obfuscate' and 'best'. Default value is 'clean'. 'best' uses 'shrink' or 'obfuscate' depending on which result is shorter. This is recommended because especially when compressing short scripts the result will exceed the input if compression level is 'obfuscate'. copyright You can add a copyright notice at the top of the script. remove_copyright If there is a copyright notice in a comment it will only be removed if this option is set to a true value. Otherwise the first comment that contains the word "copyright" will be added at the top of the packed script. A copyright comment will be overwritten by a copyright notice defined with the copyright option. no_compress_comment If not set to a true value it is allowed to set a JavaScript comment that prevents the input being packed or defines a compression level. /* JavaScript::Packer _no_compress_ */ /* JavaScript::Packer shrink */ EXAMPLES Example 1 Common usage. #!/usr/bin/perl use strict; use warnings; use JavaScript::Packer; my $packer = JavaScript::Packer->init(); open( UNCOMPRESSED, 'uncompressed.js' ); open( COMPRESSED, '>compressed.js' ); my $js = join( '', ); $packer->minify( \$js, { compress => 'best' } ); print COMPRESSED $js; close(UNCOMPRESSED); close(COMPRESSED); Example 2 A scalar is requested by the context. The input will remain unchanged. #!/usr/bin/perl use strict; use warnings; use JavaScript::Packer; my $packer = JavaScript::Packer->init(); open( UNCOMPRESSED, 'uncompressed.js' ); open( COMPRESSED, '>compressed.js' ); my $uncompressed = join( '', ); my $compressed = $packer->minify( \$uncompressed, { compress => 'best' } ); print COMPRESSED $compressed; close(UNCOMPRESSED); close(COMPRESSED); AUTHOR Merten Falk, `'. Now maintained by Lee Johnson (LEEJO) BUGS AND CAVEATS This module will break code that relies on ASI, see https://github.com/leejo/javascript-packer-perl/issues/5 for more information. Please report any bugs or feature requests through the web interface at http://github.com/leejo/javascript-packer-perl/issues. SUPPORT You can find documentation for this module with the perldoc command. perldoc JavaScript::Packer COPYRIGHT & LICENSE Copyright 2008 - 2012 Merten Falk, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. JavaScript-Packer-2.05/Changes000644 000770 000120 00000011135 13616276623 017506 0ustar00leejohnsonadmin000000 000000 Revision history for JavaScript-Packer 2.05 2020-02-04 - Fix regex when "best" compression matches ord check equal to 57 (GH #6, thanks to @r3hp1c) 2.04 2018-02-01 - Document that the module breaks code that relies on ASI (GH #5) 2.03 2017-04-18 - Makefile.PL moved to ExtUtils::MakeMaker to fix no . in @INC (perl 5.25.11+) 2.01 2016-06-22 - Fix refrence cycles in ->init method causing memory leaks (GH #1) 2.00 2015-05-27 - New maintainer: LEEJO - Merge PR from dod38fr (nevesenin/javascript-packer-perl:GH #8, nevesenin/javascript-packer-perl:GH #9) - Fix "Redundant argument in sprintf" against perl 5.22 - Repoint issue tracker/repo at leejo's fork - Add .travis.yml for CI goodness - Add Changes test - Add MYMETA.json to .gitignore 1.006003 2012-03-02 - This release fixes issue #1. - Added additional concat tests. - Fixed bug in string concatenation. Thanks to Nigel Horne for reporting this issue. - Tidied up. 1.006002 2012-02-28 - This release fixes issue #2. - Fixed bug in handling regular expressions when shrink is used. Thanks to Colin Kuskie for reporting this issue and writing tests. 1.006001 2012-02-19 - Use gnutar to build distribution. 1.006 2011-09-26 - Raised version number. 1.005_001 2011-07-22 - Replaced some map with foreach. - Some cleanups. - Added concat test. 1.004 2011-06-07 - Raised version number. 1.003_003 2011-05-19 - Some minor changes. - Added tests. 1.003_002 2011-05-15 - Made comment option work in conjunction with all compression options. Suggested by Marc S. Brooks. 1.003_001 2011-04-13 - Compression opts "minify" and "base62" are no longer supported. - Added accessors. - Added tests. - Minor Bugfixes. - Cleanup. 1.002001 2011-03-01 - Changed requirements to Regexp::RegGrp 1.000001 due to "undefined submatches bug" in Regexp::RegGrp. 1.002 2011-01-28 - Bugfix: Added missing testfile. 1.001 2011-01-27 - Bugfix: Removed restore pattern. - Added test. 1.000 2011-01-17 - Changed versioning. - Raised major version due to changes in versioning. - Changed requirements to Regexp::RegGrp 1.000 due to changes in versioning. 0.0601 2011-01-05 - Changed requirements to Regexp::RegGrp 0.04 0.06 2010-12-03 - Raised version number. 0.05_08 2010-10-05 - Removed the ridiculous missing semicolon fix. - Changed required perl version to 5.8.9. 0.05_07 2010-09-28 - Bugfix: Fixed Regexp. 0.05_06 2010-09-28 - Bugfix: Fixed Regexp. 0.05_05 2010-09-28 - Added handling for missing semicolons. THIS WILL BE REMOVED IN FUTURE VERSIONS. - Added handling for functions as arguments. - Added remove_copyright option. - Added copyright comment option. - Added tests. 0.05_04 2010-09-22 - Added option to define compression level via comment. - Added tests. 0.05_03 2010-09-13 - Changed requirements to Regexp::RegGrp 0.0201. 0.05_02 2010-09-07 - Moved regexp grouping stuff to Regexp::RegGrp. - Switched to Module::Install. 0.0402 2010-07-29 - Bugfix: Removed match variable from _process_minify() 0.0401 2010-07-10 - Bugfix: Removed $& from module to increase speed. Thanks to Graham Knop for suggestion - Switched tabs to soft tabs 0.04 2010-01-04 - Changed version number 0.03_02 2009-10-21 - Added support for perl 5.8 - Changed requirements back to perl 5.8 - Bugfix in concat function - Bugfix in shrink function 0.03_01 2009-09-30 - Added object-oriented interface, examples in perldoc, support for prototype.js' $super function - Updated regular expressions based on the original regular expressions in Dean Edwards' javascript libraries - Adapted javascript parts to Dean Edwards' javascript libraries - Replaced evals with subs - The minify method returns a scalar if requested by context. Thanks to Mary Shaw for suggestion - Changed requirements to perl 5.10 to use named capture buffers in regular expressions 0.02 2009-04-10 - Changed version number 0.01_02 2009-03-16 - Bugfix 0.01_01 2009-03-15 - Changed compression level names - Added compression level 'best' - Updated some regular expressions - Added some tests 0.0102 2008-11-24 - Former changes didn't work. Undone these changes. I'm sorry for that. This will not happen again. - Changed requirements to perl 5.8. 0.0101 2008-11-20 Replaced int() by sprintf() for perl 5.6 0.01 2008-11-15 First version, released on an unsuspecting world. JavaScript-Packer-2.05/MANIFEST000644 000770 000120 00000001277 13616276755 017360 0ustar00leejohnsonadmin000000 000000 Changes lib/JavaScript/Packer.pm Makefile.PL MANIFEST README t/00-load.t t/01-interface.t t/02-io.t t/03-leaks.t t/pod.t t/scripts/s1-expected.js t/scripts/s1.js t/scripts/s2-expected.js t/scripts/s2.js t/scripts/s3-expected.js t/scripts/s3.js t/scripts/s4-expected.js t/scripts/s4.js t/scripts/s5-expected.js t/scripts/s5.js t/scripts/s7-expected.js t/scripts/s7.js t/scripts/s8-expected.js t/scripts/s8.js t/scripts/s9-expected.js t/scripts/s9.js t/scripts/s10-expected.js t/scripts/s10.js t/scripts/s11-expected.js t/scripts/s11.js META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) JavaScript-Packer-2.05/t/000755 000770 000120 00000000000 13616276754 016462 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.05/META.yml000644 000770 000120 00000001453 13616276755 017474 0ustar00leejohnsonadmin000000 000000 --- abstract: "Perl version of Dean Edwards' Packer.js" author: - 'Lee Johnson ' build_requires: Test::More: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.36, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: JavaScript-Packer no_index: directory: - t - inc requires: Regexp::RegGrp: 1.001_001 resources: bugtracker: https://github.com/leejo/javascript-packer-perl/issues homepage: https://metacpan.org/module/JavaScript::Packer license: http://dev.perl.org/licenses/ repository: https://github.com/leejo/javascript-packer-perl version: '2.05' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' JavaScript-Packer-2.05/META.json000644 000770 000120 00000002441 13616276755 017642 0ustar00leejohnsonadmin000000 000000 { "abstract" : "Perl version of Dean Edwards' Packer.js", "author" : [ "Lee Johnson " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.36, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "JavaScript-Packer", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "Test::More" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Regexp::RegGrp" : "1.001_001" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/leejo/javascript-packer-perl/issues" }, "homepage" : "https://metacpan.org/module/JavaScript::Packer", "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "url" : "https://github.com/leejo/javascript-packer-perl" } }, "version" : "2.05", "x_serialization_backend" : "JSON::PP version 4.02" } JavaScript-Packer-2.05/lib/000755 000770 000120 00000000000 13616276754 016765 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.05/Makefile.PL000644 000770 000120 00000001415 13616276425 020165 0ustar00leejohnsonadmin000000 000000 #!perl use strict; use warnings; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'JavaScript::Packer', ABSTRACT_FROM => 'lib/JavaScript/Packer.pm', VERSION_FROM => 'lib/JavaScript/Packer.pm', AUTHOR => 'Lee Johnson ', LICENSE => 'perl', PREREQ_PM => { 'Regexp::RegGrp' => '1.001_001', }, BUILD_REQUIRES => { 'Test::More' => 0, }, META_MERGE => { resources => { license => 'http://dev.perl.org/licenses/', homepage => 'https://metacpan.org/module/JavaScript::Packer', bugtracker => 'https://github.com/leejo/javascript-packer-perl/issues', repository => 'https://github.com/leejo/javascript-packer-perl' }, }, test => { TESTS => 't/*.t', }, ); JavaScript-Packer-2.05/lib/JavaScript/000755 000770 000120 00000000000 13616276754 021033 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.05/lib/JavaScript/Packer.pm000644 000770 000120 00000063022 13616276513 022572 0ustar00leejohnsonadmin000000 000000 package JavaScript::Packer; use 5.008009; use warnings; use strict; use Carp; use Regexp::RegGrp; # =========================================================================== # our $VERSION = "2.05"; our @BOOLEAN_ACCESSORS = ( 'no_compress_comment', 'remove_copyright' ); our @COPYRIGHT_ACCESSORS = ( 'copyright', 'copyright_comment' ); our @COMPRESS_OPTS = ( 'clean', 'obfuscate', 'shrink', 'best' ); our $DEFAULT_COMPRESS = 'clean'; our $PACKER_COMMENT = '\/\*\s*JavaScript::Packer\s*(\w+)\s*\*\/'; our $COPYRIGHT_COMMENT = '\/\*((?>[^\*]|\*[^\/])*copyright(?>[^\*]|\*[^\/])*)\*\/'; our $RESTORE_PATTERN = qr~\x01(\d+)\x01~; our $RESTORE_REPLACEMENT = "\x01%d\x01"; our $SHRINK_VARS = { BLOCK => qr/(((catch|do|if|while|with|function)\b[^~{};]*(\(\s*[^{};]*\s*\))\s*)?(\{[^{}]*\}))/, # function ( arg ) { ... } ENCODED_BLOCK => qr/~#?(\d+)~/, CALLER => qr/((?>[a-zA-Z0-9_\x24\.]+)\s*\([^\(\)]*\))(?=[,\)])/, # do_something( arg1, arg2 ) as argument of another function call BRACKETS => qr/\{[^{}]*\}|\[[^\[\]]*\]|\([^\(\)]*\)|~[^~]+~/, IDENTIFIER => qr~[a-zA-Z_\x24][a-zA-Z_0-9\\x24]*~, SCOPED => qr/~#(\d+)~/, VARS => qr~\b(?:var|function)\s+((?>[a-zA-Z0-9_\x24]+))~, # var x, funktion blah PREFIX => qr~\x02~, SHRUNK => qr~\x02\d+\b~ }; our $BASE62_VARS = { WORDS => qr~(\b[0-9a-zA-Z]\b|(?>[a-zA-Z0-9_]{2,}))~, ENCODE10 => 'String', ENCODE36 => 'function(c){return c.toString(36)}', ENCODE62 => q~function(c){return(c<62?'':e(parseInt(c/62)))+((c=c%62)>35?String.fromCharCode(c+29):c.toString(36))}~, UNPACK => q~eval(function(p,a,c,k,e,r){e=%s;if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];k=[function(e){return r[e]||e}];e=function(){return'%s'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('%s',%s,%d,'%s'.split('|'),0,{}))~ }; our $DICTIONARY = { STRING1 => qr~"(?>(?:(?>[^"\\]+)|\\.|\\")*)"~, STRING2 => qr~'(?>(?:(?>[^'\\]+)|\\.|\\')*)'~, REGEXP => qr~\/(\\[\/\\]|[^*\/])(\\.|[^\/\n\\])*\/[gim]*~, OPERATOR => qr'return|typeof|[\[(\^=,{}:;&|!*?]', CONDITIONAL => qr~\/\*\@\w*|\w*\@\*\/|\/\/\@\w*|\@(?>\w+)~, COMMENT1 => qr~\/\/(\@)?([^\n]*)?\n~, COMMENT2 => qr~\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/~ }; our $DATA = [ { regexp => $DICTIONARY->{STRING1} }, { regexp => $DICTIONARY->{STRING2} }, { regexp => $DICTIONARY->{CONDITIONAL} }, { regexp => '(' . $DICTIONARY->{OPERATOR} . ')\s*(' . $DICTIONARY->{REGEXP} . ')', replacement => sub { return sprintf( "%s%s", $_[0]->{submatches}->[0], $_[0]->{submatches}->[1] ); }, } ]; our $COMMENTS = [ { regexp => ';;;[^\n]*\n', replacement => '' }, { regexp => $DICTIONARY->{COMMENT1} . '\s*(' . $DICTIONARY->{REGEXP} . ')?' }, { regexp => '(' . $DICTIONARY->{COMMENT2} . ')\s*(' . $DICTIONARY->{REGEXP} . ')?' } ]; our $CLEAN = [ { regexp => '\(\s*([^;)]*)\s*;\s*([^;)]*)\s*;\s*([^;)]*)\)', replacement => sub { return sprintf( "(%s;%s;%s)", @{ $_[0]->{submatches} } ); } }, { regexp => 'throw[^};]+[};]' }, { regexp => ';+\s*([};])', replacement => sub { return $_[0]->{submatches}->[0]; } } ]; our $WHITESPACE = [ { regexp => '\/\/@[^\n]*\n' }, { regexp => '@\s+\b', replacement => '@ ' }, { regexp => '\b\s+@', replacement => ' @' }, { regexp => '(\d)\s+(\.\s*[a-z\x24_\[(])', replacement => sub { return sprintf( "%s %s", @{ $_[0]->{submatches} } ); } }, { regexp => '([+-])\s+([+-])', replacement => sub { return sprintf( "%s %s", @{ $_[0]->{submatches} } ); } }, { regexp => '(?>\s+)(\x24)(?>\s+)', replacement => sub { return sprintf( " %s ", $_[0]->{submatches}->[0] ); } }, { regexp => '(\x24)(?>\s+)(?!=)', replacement => sub { return sprintf( "%s ", $_[0]->{submatches}->[0] ); } }, { regexp => '(?\s+)(\x24)', replacement => sub { return sprintf( " %s", $_[0]->{submatches}->[0] ); } }, { regexp => '\b\s+\b', replacement => ' ' }, { regexp => '\s+', replacement => '' } ]; our $TRIM = [ { regexp => '(\d)(?:\|\d)+\|(\d)', replacement => sub { return sprintf( "%d-%d", $_[0]->{submatches}->[0] || 0, $_[0]->{submatches}->[1] || 0 ); } }, { regexp => '([a-z])(?:\|[a-z])+\|([a-z])', replacement => sub { return sprintf( "%s-%s", $_[0]->{submatches}->[0], $_[0]->{submatches}->[1] ); } }, { regexp => '([A-Z])(?:\|[A-Z])+\|([A-Z])', replacement => sub { return sprintf( "%s-%s", $_[0]->{submatches}->[0], $_[0]->{submatches}->[1] ); } }, { regexp => '\|', replacement => '' } ]; our @REGGRPS = ( 'comments', 'clean', 'whitespace', 'concat', 'trim', 'data_store', 'concat_store' ); # --------------------------------------------------------------------------- # { no strict 'refs'; foreach my $field ( @BOOLEAN_ACCESSORS ) { next if defined *{ __PACKAGE__ . '::' . $field }{CODE}; *{ __PACKAGE__ . '::' . $field } = sub { my ( $self, $value ) = @_; $self->{ '_' . $field } = $value ? 1 : undef if ( defined( $value ) ); return $self->{ '_' . $field }; }; } foreach my $field ( @COPYRIGHT_ACCESSORS ) { $field = '_' . $field if ( $field eq 'copyright_comment' ); next if defined *{ __PACKAGE__ . '::' . $field }{CODE}; *{ __PACKAGE__ . '::' . $field } = sub { my ( $self, $value ) = @_; if ( defined( $value ) and not ref( $value ) ) { $value =~ s/^\s*|\s*$//gs; $self->{ '_' . $field } = $value; } my $ret = ''; if ( $self->{ '_' . $field } ) { $ret = '/* ' . $self->{ '_' . $field } . ' */' . "\n"; } return $ret; }; } foreach my $reggrp ( @REGGRPS ) { next if defined *{ __PACKAGE__ . '::reggrp_' . $reggrp }{CODE}; *{ __PACKAGE__ . '::reggrp_' . $reggrp } = sub { my ( $self ) = shift; return $self->{ '_reggrp_' . $reggrp }; }; } } sub compress { my ( $self, $value ) = @_; if ( defined( $value ) ) { if ( grep( $value eq $_, @COMPRESS_OPTS ) ) { $self->{_compress} = $value; } elsif ( !$value ) { $self->{_compress} = undef; } } $self->{_compress} ||= $DEFAULT_COMPRESS; return $self->{_compress}; } # these variables are used in the closures defined in the init function # below - we have to use globals as using $self within the closures leads # to a reference cycle and thus memory leak, and we can't scope them to # the init method as they may change. they are set by the minify sub our $reggrp_comments; our $reggrp_clean; our $reggrp_whitespace; sub init { my $class = shift; my $self = {}; bless( $self, $class ); @{ $self->{clean}->{reggrp_data} } = ( @$DATA, @$CLEAN ); @{ $self->{whitespace}->{reggrp_data} } = ( @$DATA[ 0, 1, 3 ], @$WHITESPACE ); $self->{trim}->{reggrp_data} = $TRIM; @{ $self->{data_store}->{reggrp_data} } = map { { regexp => $_->{regexp}, store => sub { return sprintf( "%s", $_[0]->{match} ); }, replacement => sub { return sprintf( $RESTORE_REPLACEMENT, $_[0]->{store_index} ); }, } } @$DATA; $self->{data_store}->{reggrp_data}->[-1]->{replacement} = sub { return sprintf( "%s$RESTORE_REPLACEMENT", $_[0]->{submatches}->[0], $_[0]->{store_index} ); }; $self->{data_store}->{reggrp_data}->[-1]->{store} = sub { return $_[0]->{submatches}->[1]; }; @{ $self->{concat_store}->{reggrp_data} } = map { my $data = $_; { regexp => $data->{regexp}, store => sub { my ( $quote, $string ) = $_[0]->{match} =~ /^(['"])(.*)(['"])$/; return $string; }, replacement => sub { my ( $quote, $string ) = $_[0]->{match} =~ /^(['"])(.*)(['"])$/; return sprintf( "%s$RESTORE_REPLACEMENT%s", $quote, $_[0]->{store_index}, $quote ); }, }; } @$DATA[ 0, 1 ]; @{ $self->{concat}->{reggrp_data} } = map { my $quote = $_; my $restore_pattern = $RESTORE_PATTERN; $restore_pattern =~ s/\(\\d\+\)/\\d\+/g; my $regexp = '(' . $quote . $restore_pattern . $quote . ')((?:\+' . $quote . $restore_pattern . $quote . ')+)'; $regexp = qr/$regexp/; { regexp => $regexp, replacement => sub { my $submatches = $_[0]->{submatches}; my $ret = $submatches->[0]; my $next_str = '^\+(' . $quote . $restore_pattern . $quote . ')'; while ( my ( $next ) = $submatches->[1] =~ /$next_str/ ) { chop( $ret ); $ret .= substr( $next, 1 ); $submatches->[1] =~ s/$next_str//; } return $ret; }, }; } ( '"', '\'' ); @{ $self->{comments}->{reggrp_data} } = ( @$DATA[ 0, 1, 3 ], @$COMMENTS ); $self->{comments}->{reggrp_data}->[-2]->{replacement} = sub { my $submatches = $_[0]->{submatches}; if ( $submatches->[0] eq '@' ) { $reggrp_comments->exec( \$submatches->[1] ); $reggrp_clean->exec( \$submatches->[1] ); $reggrp_whitespace->exec( \$submatches->[1] ); return sprintf( "//%s%s\n%s", @{$submatches}[0 .. 2] ); } return sprintf( "\n%s", $submatches->[2] ); }; $self->{comments}->{reggrp_data}->[-1]->{replacement} = sub { my $submatches = $_[0]->{submatches}; if ( $submatches->[0] =~ /^\/\*\@(.*)\@\*\/$/sm ) { my $cmnt = $1; $reggrp_comments->exec( \$cmnt ); $reggrp_clean->exec( \$cmnt ); $reggrp_whitespace->exec( \$cmnt ); return sprintf( '/*@%s@*/ %s', $cmnt, $submatches->[1] ); } return sprintf( " %s", $submatches->[1] ); }; foreach my $reggrp ( @REGGRPS ) { my $reggrp_args = { reggrp => $self->{$reggrp}->{reggrp_data} }; $reggrp_args->{restore_pattern} = $RESTORE_PATTERN if ( $reggrp eq 'data_store' or $reggrp eq 'concat_store' ); $self->{ '_reggrp_' . $reggrp } = Regexp::RegGrp->new( $reggrp_args ); } $self->{block_data} = []; return $self; } sub minify { my ( $self, $input, $opts ); unless (ref( $_[0] ) and ref( $_[0] ) eq __PACKAGE__ ) { $self = __PACKAGE__->init(); shift( @_ ) unless ( ref( $_[0] ) ); ( $input, $opts ) = @_; } else { ( $self, $input, $opts ) = @_; } if ( ref( $input ) ne 'SCALAR' ) { carp( 'First argument must be a scalarref!' ); return undef; } my $javascript = \''; my $cont = 'void'; if ( defined( wantarray ) ) { my $tmp_input = ref( $input ) ? ${$input} : $input; $javascript = \$tmp_input; $cont = 'scalar'; } else { $javascript = ref( $input ) ? $input : \$input; } if ( ref( $opts ) eq 'HASH' ) { foreach my $field ( @BOOLEAN_ACCESSORS ) { $self->$field( $opts->{$field} ) if ( defined( $opts->{$field} ) ); } foreach my $field ( 'compress', 'copyright' ) { $self->$field( $opts->{$field} ) if ( defined( $opts->{$field} ) ); } } # (re)initialize variables used in the closures $reggrp_comments = $self->reggrp_comments; $reggrp_clean = $self->reggrp_clean; $reggrp_whitespace = $self->reggrp_whitespace; my $copyright_comment = ''; if ( ${$javascript} =~ /$COPYRIGHT_COMMENT/ism ) { $copyright_comment = $1; } # Resets copyright_comment() if there is no copyright comment $self->_copyright_comment( $copyright_comment ); if ( not $self->no_compress_comment() and ${$javascript} =~ /$PACKER_COMMENT/ ) { my $compress = $1; if ( $compress eq '_no_compress_' ) { return ${$javascript} if ( $cont eq 'scalar' ); return; } $self->compress( $compress ); } ${$javascript} =~ s/\r//gsm; ${$javascript} .= "\n"; $self->reggrp_comments()->exec( $javascript ); $self->reggrp_clean()->exec( $javascript ); $self->reggrp_whitespace()->exec( $javascript ); $self->reggrp_concat_store()->exec( $javascript ); $self->reggrp_concat()->exec( $javascript ); $self->reggrp_concat_store()->restore_stored( $javascript ); if ( $self->compress() ne 'clean' ) { $self->reggrp_data_store()->exec( $javascript ); while ( ${$javascript} =~ /$SHRINK_VARS->{BLOCK}/ ) { ${$javascript} =~ s/$SHRINK_VARS->{BLOCK}/$self->_store_block_data( $1 )/egsm; } $self->_restore_data( $javascript, 'block_data', $SHRINK_VARS->{ENCODED_BLOCK} ); my %shrunk_vars = map { $_ => 1 } ( ${$javascript} =~ /$SHRINK_VARS->{SHRUNK}/g ); my $cnt = 0; foreach my $shrunk_var ( sort keys( %shrunk_vars ) ) { my $short_id; do { $short_id = $self->_encode52( $cnt++ ); } while ( ${$javascript} =~ /[^a-zA-Z0-9_\\x24\.]\Q$short_id\E[^a-zA-Z0-9_\\x24:]/ ); ${$javascript} =~ s/$shrunk_var/$short_id/g; } $self->reggrp_data_store()->restore_stored( $javascript ); $self->{block_data} = []; } if ( $self->compress() eq 'obfuscate' or $self->compress() eq 'best' ) { my $words = {}; my @words = ${$javascript} =~ /$BASE62_VARS->{WORDS}/g; my $idx = 0; foreach ( @words ) { $words->{$_}->{count}++; } WORD: foreach my $word ( sort { $words->{$b}->{count} <=> $words->{$a}->{count} } sort keys( %{$words} ) ) { if ( exists( $words->{$word}->{encoded} ) and $words->{$word}->{encoded} eq $word ) { next WORD; } my $encoded = $self->_encode62( $idx ); if ( exists( $words->{$encoded} ) ) { my $next = 0; if ( exists( $words->{$encoded}->{encoded} ) ) { $words->{$word}->{encoded} = $words->{$encoded}->{encoded}; $words->{$word}->{index} = $words->{$encoded}->{index}; $words->{$word}->{minus} = length( $word ) - length( $words->{$word}->{encoded} ); $next = 1; } $words->{$encoded}->{encoded} = $encoded; $words->{$encoded}->{index} = $idx; $words->{$encoded}->{minus} = 0; $idx++; next WORD if ( $next ); redo WORD; } $words->{$word}->{encoded} = $encoded; $words->{$word}->{index} = $idx; $words->{$word}->{minus} = length( $word ) - length( $encoded ); $idx++; } my $packed_length = length( ${$javascript} ); my ( @pk, @pattern ) = ( (), () ); foreach ( sort { $words->{$a}->{index} <=> $words->{$b}->{index} } sort keys( %{$words} ) ) { $packed_length -= ( $words->{$_}->{count} * $words->{$_}->{minus} ); if ( $words->{$_}->{encoded} ne $_ ) { push( @pk, $_ ); push( @pattern, $words->{$_}->{encoded} ); } else { push( @pk, '' ); push( @pattern, '' ); } } my $size = scalar( @pattern ); splice( @pattern, 62 ) if ( scalar( @pattern ) > 62 ); my $pd = join( '|', @pattern ); $self->reggrp_trim()->exec( \$pd ); unless ( $pd ) { $pd = '^$'; } else { $pd = '[' . $pd . ']'; if ( $size > 62 ) { $pd = '(' . $pd . '|'; my $enc = $self->_encode62( $size ); my ( $c ) = $enc =~ /(^.)/; my $ord = ord( $c ); my $mul = length( $enc ) - 1; my $is62 = 0; if ( $ord >= 65 ) { if ( $c eq 'Z' ) { $mul += 1; $is62 = 1; } else { $pd .= '[0-9a'; if ( $ord > 97 ) { $pd .= '-' . $c; } elsif ( $ord > 65 ) { $pd .= '-zA-' . $c; } $pd .= ']'; } } elsif ( $ord == 57 ) { $pd .= '[0-9]'; } elsif ( $ord == 50 ) { $pd .= '[12]'; } elsif ( $ord == 49 ) { $pd .= '1'; } else { $pd .= '[0-' . ( $ord - 48 ) . ']'; } $pd .= '[0-9a-zA-Z]' . ( ( $mul > 1 ) ? '{' . $mul . '}' : '' ); $mul-- if ( $is62 ); if ( $mul > 1 ) { for ( my $i = $mul; $i >= 2; $i-- ) { $pd .= '|[0-9a-zA-Z]{' . $i . '}'; } } $pd .= ')'; } } $packed_length += length( $pd ); my $pk = join( '|', @pk ); $pk =~ s/(?>\|+)$//; $packed_length += length( $pk ); my $pc = length( $pk ) ? ( ( $pk =~ tr/|/|/ ) + 1 ) : 0; $packed_length += length( $pc ); my $pa = '[]'; $packed_length += length( $pa ); my $pe = $BASE62_VARS->{ 'ENCODE' . ( $pc > 10 ? $pc > 36 ? 62 : 36 : 10 ) }; $packed_length += length( $pe ); $packed_length += length( $BASE62_VARS->{UNPACK} ); $packed_length -= ( $BASE62_VARS->{UNPACK} =~ s/(%s|%d)/$1/g ) * 2; my ( @length_matches ) = ${$javascript} =~ s/((?>[\r\n]+))/$1/g; foreach ( @length_matches ) { $packed_length -= length( $_ ) - 3; } $packed_length += ${$javascript} =~ tr/\\\'/\\\'/; if ( $self->compress() eq 'obfuscate' or $packed_length <= length( ${$javascript} ) ) { ${$javascript} =~ s/$BASE62_VARS->{WORDS}/sprintf( "%s", $words->{$1}->{encoded} )/eg; ${$javascript} =~ s/([\\'])/\\$1/g; ${$javascript} =~ s/[\r\n]+/\\n/g; my $pp = ${$javascript}; ${$javascript} = sprintf( $BASE62_VARS->{UNPACK}, $pe, $pd, $pp, $pa, $pc, $pk ); } } if ( not $self->remove_copyright() ) { ${$javascript} = ( $self->copyright() || $self->_copyright_comment() ) . ${$javascript}; } return ${$javascript} if ( $cont eq 'scalar' ); } sub _restore_data { my ( $self, $string_ref, $data_name, $pattern ) = @_; while ( ${$string_ref} =~ /$pattern/ ) { ${$string_ref} =~ s/$pattern/$self->{$data_name}->[$1]/egsm; } } sub _store_block_data { my ( $self, $match ) = @_; my ( undef, $prefix, $blocktype, $args, $block ) = $match =~ /$SHRINK_VARS->{BLOCK}/; $prefix ||= ''; $blocktype ||= ''; $args ||= ''; my $replacement = ''; if ( $blocktype eq 'function' ) { $self->_restore_data( \$block, 'block_data', $SHRINK_VARS->{SCOPED} ); $args =~ s/\s*//g; $block = $args . $block; $prefix =~ s/$SHRINK_VARS->{BRACKETS}//; $args =~ s/^\(|\)$//g; while ( $args =~ /$SHRINK_VARS->{CALLER}/ ) { $args =~ s/$SHRINK_VARS->{CALLER}//gsm; } my @vars = grep( $_, split( /\s*,\s*/, $args ) ); my $do_shrink = grep( $_ eq '_no_shrink_', @vars ) ? 0 : 1; my %block_vars = (); if ( $do_shrink ) { %block_vars = map { $_ => 1 } ( $block =~ /$SHRINK_VARS->{VARS}/g ), grep( $_ ne '$super', @vars ); } $self->_restore_data( \$block, 'block_data', $SHRINK_VARS->{ENCODED_BLOCK} ); if ( $do_shrink ) { my $cnt = 0; foreach my $block_var ( sort keys( %block_vars ) ) { if ( length( $block_var ) ) { while ( $block =~ /$SHRINK_VARS->{PREFIX}\Q$cnt\E\b/ ) { $cnt++; } while ( $block =~ /[^a-zA-Z0-9_\\x24\.]\Q$block_var\E[^a-zA-Z0-9_\\x24:]/ ) { $block =~ s/([^a-zA-Z0-9_\\x24\.])\Q$block_var\E([^a-zA-Z0-9_\\x24:])/sprintf( "%s\x02%d%s", $1, $cnt, $2 )/eg; } $block =~ s/([^{,a-zA-Z0-9_\\x24\.])\Q$block_var\E:/sprintf( "%s\x02%d:", $1, $cnt )/eg; $cnt++; } } } $replacement = sprintf( "%s~%d~", $prefix, scalar( @{ $self->{block_data} } ) ); push( @{ $self->{block_data} }, $block ); } else { $replacement = sprintf( "~#%d~", scalar( @{ $self->{block_data} } ) ); push( @{ $self->{block_data} }, $prefix . $block ); } return $replacement; } sub _encode52 { my ( $self, $c ) = @_; my $m = $c % 52; my $ret = $m > 25 ? chr( $m + 39 ) : chr( $m + 97 ); if ( $c >= 52 ) { $ret = $self->_encode52( int( $c / 52 ) ) . $ret; } $ret = substr( $ret, 1 ) . '0' if ( $ret =~ /^(do|if|in)$/ ); return $ret; } sub _encode62 { my ( $self, $c ) = @_; my $m = $c % 62; my $ret = $m > 35 ? chr( $m + 29 ) : $m > 9 ? chr( $m + 87 ) : $m; if ( $c >= 62 ) { $ret = $self->_encode62( int( $c / 62 ) ) . $ret; } return $ret; } 1; __END__ =head1 NAME JavaScript::Packer - Perl version of Dean Edwards' Packer.js =for html Build Status Coverage Status =head1 VERSION Version 2.05 =head1 DESCRIPTION A JavaScript Compressor This module is an adaptation of Dean Edwards' Packer.js. Additional information: http://dean.edwards.name/packer/ =head1 SYNOPSIS use JavaScript::Packer; my $packer = JavaScript::Packer->init(); $packer->minify( $javascript, $opts ); To return a scalar without changing the input simply use (e.g. example 2): my $ret = $packer->minify( $javascript, $opts ); For backward compatibility it is still possible to call 'minify' as a function: JavaScript::Packer::minify( $javascript, $opts ); The first argument must be a scalarref of javascript-code. Second argument must be a hashref of options. Possible options are: =over 4 =item compress Defines compression level. Possible values are 'clean', 'shrink', 'obfuscate' and 'best'. Default value is 'clean'. 'best' uses 'shrink' or 'obfuscate' depending on which result is shorter. This is recommended because especially when compressing short scripts the result will exceed the input if compression level is 'obfuscate'. =item copyright You can add a copyright notice at the top of the script. =item remove_copyright If there is a copyright notice in a comment it will only be removed if this option is set to a true value. Otherwise the first comment that contains the word "copyright" will be added at the top of the packed script. A copyright comment will be overwritten by a copyright notice defined with the copyright option. =item no_compress_comment If not set to a true value it is allowed to set a JavaScript comment that prevents the input being packed or defines a compression level. /* JavaScript::Packer _no_compress_ */ /* JavaScript::Packer shrink */ =back =head1 EXAMPLES =over 4 =item Example 1 Common usage. #!/usr/bin/perl use strict; use warnings; use JavaScript::Packer; my $packer = JavaScript::Packer->init(); open( UNCOMPRESSED, 'uncompressed.js' ); open( COMPRESSED, '>compressed.js' ); my $js = join( '', ); $packer->minify( \$js, { compress => 'best' } ); print COMPRESSED $js; close(UNCOMPRESSED); close(COMPRESSED); =item Example 2 A scalar is requested by the context. The input will remain unchanged. #!/usr/bin/perl use strict; use warnings; use JavaScript::Packer; my $packer = JavaScript::Packer->init(); open( UNCOMPRESSED, 'uncompressed.js' ); open( COMPRESSED, '>compressed.js' ); my $uncompressed = join( '', ); my $compressed = $packer->minify( \$uncompressed, { compress => 'best' } ); print COMPRESSED $compressed; close(UNCOMPRESSED); close(COMPRESSED); =back =head1 AUTHOR Merten Falk, C<< >>. Now maintained by Lee Johnson (LEEJO) =head1 BUGS AND CAVEATS This module will break code that relies on ASI, see L for more information. Please report any bugs or feature requests through the web interface at L. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc JavaScript::Packer =head1 COPYRIGHT & LICENSE Copyright 2008 - 2012 Merten Falk, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut JavaScript-Packer-2.05/t/pod.t000644 000770 000120 00000000350 13616276425 017422 0ustar00leejohnsonadmin000000 000000 #!perl -T use strict; use warnings; use Test::More; # Ensure a recent version of Test::Pod my $min_tp = 1.22; eval "use Test::Pod $min_tp"; plan skip_all => "Test::Pod $min_tp required for testing POD" if $@; all_pod_files_ok(); JavaScript-Packer-2.05/t/01-interface.t000644 000770 000120 00000004161 13616276425 021022 0ustar00leejohnsonadmin000000 000000 #!perl -T use Test::More; my $not = 18; SKIP: { eval { use JavaScript::Packer; }; skip( 'JavaScript::Packer not installed!', $not ) if ( $@ ); plan tests => $not; my $packer = JavaScript::Packer->init(); ok( !$packer->no_compress_comment(), 'Default value for no_compress_comment' ); ok( !$packer->remove_copyright(), 'Default value for remove_copyright' ); is( $packer->compress(), 'clean', 'Default value for compress' ); is( $packer->copyright(), '', 'Default value for copyright' ); $packer->no_compress_comment( 1 ); ok( $packer->no_compress_comment(), 'Set no_compress_comment.' ); $packer->no_compress_comment( 0 ); ok( !$packer->no_compress_comment(), 'Unset no_compress_comment.' ); $packer->remove_copyright( 1 ); ok( $packer->remove_copyright(), 'Set remove_copyright.' ); $packer->remove_copyright( 0 ); ok( !$packer->remove_copyright(), 'Unset remove_copyright.' ); $packer->compress( 'shrink' ); is( $packer->compress(), 'shrink', 'Set compress to "shrink".' ); $packer->compress( 'foo' ); is( $packer->compress(), 'shrink', 'Set compress to "foo" failed.' ); $packer->compress( 'clean' ); is( $packer->compress(), 'clean', 'Setting compress back to "clean".' ); $packer->copyright( 'Ich war\'s!' ); is( $packer->copyright(), "/* Ich war's! */\n", 'Set copyright' ); $packer->copyright( 'Ich war\'s' . "\n" . 'nochmal!' ); is( $packer->copyright(), "/* Ich war's\nnochmal! */\n", 'Set copyright' ); $packer->copyright( '' ); is( $packer->copyright(), '', 'Reset copyright' ); my $str = ''; $packer->minify( \$str, {} ); ok( !$packer->no_compress_comment(), 'Default value for no_compress_comment is still set.' ); is( $packer->compress(), 'clean', 'Default value for compress is still set.' ); $packer->minify( \$str, { compress => 'shrink', no_compress_comment => 1, } ); ok( $packer->no_compress_comment(), 'Set no_compress_comment again.' ); is( $packer->compress(), 'shrink', 'Set compress to "minify" again.' ); } JavaScript-Packer-2.05/t/00-load.t000644 000770 000120 00000000247 13616276425 020001 0ustar00leejohnsonadmin000000 000000 #!perl -T use Test::More tests => 1; BEGIN { use_ok( 'JavaScript::Packer' ); } diag( "Testing JavaScript::Packer $JavaScript::Packer::VERSION, Perl $], $^X" ); JavaScript-Packer-2.05/t/scripts/000755 000770 000120 00000000000 13616276754 020151 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.05/t/03-leaks.t000644 000770 000120 00000001217 13616276425 020162 0ustar00leejohnsonadmin000000 000000 #!perl use strict; use warnings; use Test::More; use JavaScript::Packer; if (! eval "use Test::Memory::Cycle; 1;" ) { plan skip_all => 'Test::Memory::Cycle required for this test'; } my $packer = JavaScript::Packer->init; memory_cycle_ok( $packer ); my $js = ' $(document).ready(function(e) { try { // $("body select").msDropDown(); $("#payin").msDropdown({visibleRows:3,rowHeight:30}); $("#payout").msDropdown({visibleRows:8,rowHeight:30}); $("#lang").msDropdown({visibleRows:2,rowHeight:16}); } catch(e) { alert(e.message); } }); '; for ( 1 .. 5 ) { ok( $packer->minify( \$js,{} ),'minify' ); } memory_cycle_ok( $packer ); done_testing(); JavaScript-Packer-2.05/t/02-io.t000644 000770 000120 00000015170 13616276425 017474 0ustar00leejohnsonadmin000000 000000 #!perl -T # =========================================================================== # # # Most of these tests are stolen from JavaScript::Minifier # # =========================================================================== # use Test::More; my $not = 31; SKIP: { eval( 'use JavaScript::Packer' ); skip( 'JavaScript::Packer not installed!', $not ) if ( $@ ); plan tests => $not; fileTest( 's1', 'clean', 'compression level "clean"' ); fileTest( 's2', 'shrink', 'compression level "shrink"' ); fileTest( 's3', 'obfuscate', 'compression level "obfuscate"' ); fileTest( 's4', 'best', 'compression level "best" whith short javascript' ); fileTest( 's5', 'best', 'compression level "best" whith long javascript' ); fileTest( 's7', 'clean', 'compression level "clean" function as argument' ); fileTest( 's8', 'shrink', 'compression level "shrink" function as argument' ); fileTest( 's9', 'shrink', 'compression level "shrink" with _no_shrink_ argument' ); fileTest( 's10', 'shrink', 'compression level "shrink" with quoted args' ); fileTest( 's11', 'best', 'compression level "best" with long javascript matching _encode62 ord match 57' ); my $packer = JavaScript::Packer->init(); my $var = 'var x = 2;'; $packer->minify( \$var ); is( $var, 'var x=2;', 'string literal input and ouput' ); $var = "var x = 2;\n;;;alert('hi');\nvar x = 2;"; $packer->minify( \$var ); is( $var, 'var x=2;var x=2;', 'scriptDebug option' ); $var = "var x = 2;"; $packer->copyright( 'BSD' ); $packer->minify( \$var ); is( $var, '/* BSD */' . "\n" . 'var x=2;', 'copyright option compression level "clean"' ); $packer->compress( 'shrink' ); $packer->minify( \$var ); is( $var, '/* BSD */' . "\n" . 'var x=2;', 'copyright option compression level "shrink"' ); $packer->compress( 'best' ); $packer->minify( \$var ); is( $var, '/* BSD */' . "\n" . 'var x=2;', 'copyright option compression level "best"' ); $packer->compress( 'obfuscate' ); $packer->minify( \$var ); is( $var, '/* BSD */' . "\neval(function(p,a,c,k,e,r){e=String;if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];k=[function(e){return r[e]||e}];e=function(){return'[01]'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('1 0=2;',[],2,'x|var'.split('|'),0,{}))", 'copyright option compression level "obfuscate"' ); $packer = JavaScript::Packer->init(); $var = "/* Copyright BSD */var x = 2;"; $packer->minify( \$var, { remove_copyright => 1 } ); is( $var, 'var x=2;', 'copyright comment with remove_copyright option' ); $var = "/* Copyright BSD */var x = 2;"; $packer->minify( \$var, { remove_copyright => 0 } ); is( $var, '/* Copyright BSD */' . "\n" . 'var x=2;', 'copyright comment without remove_copyright option' ); $packer = JavaScript::Packer->init(); $var = "/* JavaScript::Packer _no_compress_ */\n\nvar x = 1;\n\n\nvar y = 2;"; $packer->minify( \$var ); is( $var, "/* JavaScript::Packer _no_compress_ */\n\nvar x = 1;\n\n\nvar y = 2;", '_no_compress_ comment' ); $var = "/* JavaScript::Packer _no_compress_ */\n\nvar x = 1;\n\n\nvar y = 2;"; $packer->minify( \$var, { no_compress_comment => 1 } ); is( $var, "var x=1;var y=2;", '_no_compress_ comment with no_compress_comment option' ); $var = "var foo = \"foo\" + \"bar\" + \"baz\" + 'foo' + 'bar' + 'baz' + \"foo\" + \"bar\" + \"baz\";"; $packer->minify( \$var ); is( $var, "var foo=\"foobarbaz\"+'foobarbaz'+\"foobarbaz\";", 'concat' ); $var = "var foo = \" \"; var bar = \"+\";"; JavaScript::Packer::minify( \$var ); is( $var, "var foo=\" \";var bar=\"+\";", 'concat with plus' ); $var = "var foo = \" \"; var bar = \"+\"; var baz = \"-\";"; JavaScript::Packer::minify( \$var ); is( $var, "var foo=\" \";var bar=\"+\";var baz=\"-\";", 'concat with plus and three strings' ); $var = "!/foo/"; $packer->minify( \$var ); is( $var, "!/foo/", 'regexp preceeded by negation' ); $var = "!/foo/"; JavaScript::Packer::minify( \$var ); is( $var, "!/foo/", 'regexp preceeded by negation, subroutine invocation' ); $var = "!/foo/"; $packer->minify( \$var, { compress => 'shrink', } ); is( $var, "!/foo/", 'regexp preceeded by negation, with shrink' ); $var = "!/foo/"; JavaScript::Packer::minify( \$var, { compress => 'shrink', } ); is( $var, "!/foo/", 'regexp preceeded by negation, with shrink, subroutine invocation' ); $var = "var foo = /bar/;"; JavaScript::Packer::minify( \$var ); is( $var, "var foo=/bar/;", 'building Regexp object implictly' ); $var = "var foo = /bar/;"; JavaScript::Packer::minify( \$var, { compress => 'shrink', } ); is( $var, "var foo=/bar/;", 'building Regexp object implictly with shrink' ); $var = q~var foo = new RegExp("bar");~; JavaScript::Packer::minify( \$var ); is( $var, q~var foo=new RegExp("bar");~, 'building Regexp object explictly' ); $var = q~var foo = new RegExp("bar");~; JavaScript::Packer::minify( \$var ); JavaScript::Packer::minify( \$var, { compress => 'shrink', } ); is( $var, q~var foo=new RegExp("bar");~, 'building Regexp object explictly with shrink' ); } sub filesMatch { my $file1 = shift; my $file2 = shift; my $a; my $b; while ( 1 ) { $a = getc( $file1 ); $b = getc( $file2 ); if ( !defined( $a ) && !defined( $b ) ) { # both files end at same place return 1; } elsif ( !defined( $b ) || # file2 ends first !defined( $a ) || # file1 ends first $a ne $b ) { # a and b not the same return 0; } } } sub fileTest { my $filename = shift; my $compress = shift || 'minify'; my $comment = shift || ''; open( INFILE, 't/scripts/' . $filename . '.js' ) or die( "couldn't open file" ); open( GOTFILE, '>t/scripts/' . $filename . '-got.js' ) or die( "couldn't open file" ); my $js = join( '', ); my $packer = JavaScript::Packer->init(); $packer->minify( \$js, { compress => $compress } ); print GOTFILE $js; close( INFILE ); close( GOTFILE ); open( EXPECTEDFILE, 't/scripts/' . $filename . '-expected.js' ) or die( "couldn't open file" ); open( GOTFILE, 't/scripts/' . $filename . '-got.js' ) or die( "couldn't open file" ); ok( filesMatch( GOTFILE, EXPECTEDFILE ), $comment ); close( EXPECTEDFILE ); close( GOTFILE ); } JavaScript-Packer-2.05/t/scripts/s2-expected.js000644 000770 000120 00000000174 13616276425 022627 0ustar00leejohnsonadmin000000 000000 function(c){var a='blah blubb';var e=3;alert(a);var d=1;//@a var b=c;/*@abcd var d=1;@*/abcd var f=$H()};/*@abcd var x=1;@*/JavaScript-Packer-2.05/t/scripts/s11-expected.js000644 000770 000120 00000032566 13616276425 022721 0ustar00leejohnsonadmin000000 000000 eval(function(p,a,c,k,e,r){e=function(c){return(c<62?'':e(parseInt(c/62)))+((c=c%62)>35?String.fromCharCode(c+29):c.toString(36))};if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];k=[function(e){return r[e]||e}];e=function(){return'([wyEHKLQW-Z]|[0-9][0-9a-zA-Z])'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('w 1s=4z("3L 3d 1s 17 1J 4v 1r?");w 2i=4z("3L 3d 6X 17 1J 4v 1r?");E(1s==""||1s==3h)1s=10;E(2i==""||2i==3h)2i=10;47(1s,2i);K 47(l,e){w f=1;w k="<1r 3X=\'1\' 96=\'56\' 41=\'0\'40=\'5\'>";17(i=1;i<=l;i++){k=k+"<2v>";5b(f<=e){k=k+"<2a>"+i*f+"";f=f+1}k=k+"";f=1}k=k+"";y.1I(k)}w 1C=16 1f();1C[0]="7o";1C[1]="7p";1C[2]="4b";1C[3]="7r";1C[4]="7q";1C[5]="4a";K 93(){w o=16 1f();o[0]=y.L(\'4j\').H;o[1]=y.L(\'4s\').H;o[2]=y.L(\'32\').H;o[3]=y.L(\'90\').H;o[4]=y.L(\'2L\').H;o[5]=y.L(\'30\').H;w m=16 1f();m[0]="<1b 18=\'1v:1y\'>1G 1V 1J 4j 4x!";m[1]="<1b 18=\'1v:1y\'>1G 1V 1J 4s 4x!";m[2]="<1b 18=\'1v:1y\'>1G 1V 1J 32!";m[3]="<1b 18=\'1v:1y\'>1G 1V 1J 91 4q!";m[4]="<1b 18=\'1v:1y\'>1G 1V 1J 2L!";m[5]="<1b 18=\'1v:1y\'>1G 30 1J 2L!";17(i 3a o){w l=m[i];w f=1C[i];E(o[i]=="")y.L(f).1o=l;W E(i==2){w e=o[i].1X("@");w k=o[i].7Y(".");E(e<1||k=o[i].1k)y.L(\'4b\').1o="<1b 18=\'1v: 1y\'>5w a 3v 32 6C!";W y.L(f).1o="2z!"}W E(i==5){w n=y.L(\'2L\').H;w p=y.L(\'30\').H;E(p!=n)y.L(\'4a\').1o="<1b 18=\'1v: 1y\'>6w 8o 7l\'t 2I!";W y.L(f).1o="2z!"}W y.L(f).1o="2z!"}}K 7v(){w e=0;17(i=0;i<6;i++){w f=1C[i];E(y.L(f).1o=="2z!")e=e+1}E(e==6)y.L("7n").1o="5d 2c 79 3x 49 1Q 70!!!"}K 8X(){y.L("7L").6A("85",e);K e(){1g("6u 2u 87 6s!!!")}}K 4C(){y.L(‘3U’).1F=’7X.1O’}2d.2N("4C()",57);w 2o="";2o["2h"]="62 2h 1Z

6c 2h 1Z";2o["2s"]="6a 2s 1Z

5x 2s 1Z";2o["7s"]="63 1Z

3N 1Z";K 4n(){4M=2o[6S];4N="<3Q>5t 5Y<3K>"+y.m.8p.H+", 4o 3T 8K 17 3x

"+4M}K 4W(){2E=2d.2J();2E.y.2J();2E.y.1I(4N);2E.y.6V()}K 7h(){4n();4W()}2b="6v 1Q 2U 3t?";y.2J();y.1I(2b.6P()+"

");y.1I(2b.4l(7)+"

");y.1I(2b.4k("1y")+"

");y.1I(2b.8W()+"

");y.1I(2b.7U().4l(6).4k("7I")+"

");y.2J();w 3l="2A 1Q a 7d 21 a 3U 86 7B 2c 2G 2u 8C. 5H 82 4U 21 2c 27 8u 21 5T 2u 81 6F 7R 7f"w 4I=3l.1k w 4H=25 w a=-3,b=0 w 2P="x"K 4u(e,f){2P=3l.27(e,f);Z 2P}K 3f(){a=a+3;b=a+4H 4u(a,b);Z 2P}K 7i(){17(w e=1;e<=4I;e++){2N("y.z.8S.H = 3f()",e*3z);2N("2d.8N = 3f()",e*3z)}}K 3M(){2l 4R=y.L("59");2l 2m=4R.7E("2m");2l x=y.L("88");Z K(){Z x.8j=K(){17(2l i=0;i<2m.1k;i++){2m[i].18.1v="1y";2m[i].18.80="8e"}}}}2l 4p=16 3M();4p();K 7C(p,q,o,e,f){w m=q/1e;w l=p;w k=o;E(e=="2x"){m/=1;k*=1}W E(e=="2t-2g"){m/=2;k*=2}W E(e=="2r"){m/=3;k*=3}W E(e=="2n"){m/=12;k*=12}W E(e=="2w"){m/=52;k*=52}W E(e=="2j"){m/=1t;k*=1t}m+=1;w n=Y.2q(m,k);y.L(f).H=l*n}K 8G(l,m,k,e){w f=m/1e;y.L(e).H=l*f*k}K 8I(e,o,n,f,k){w l=e;w m=o/1e;E(f=="2x"){m/=1;n*=1}W E(f=="2t-2g"){m/=2;n*=2}W E(f=="2r"){m/=3;n*=3}W E(f=="2n"){m/=12;n*=12}W E(f=="2w"){m/=52;n*=52}W E(f=="2j"){m/=1t;n*=1t}l*=m;m+=1;w p=Y.2q(m,n);p-=1;y.L(k).H=l/p}K 5e(f,r,q,k,l){w m=f;w o=r/1e;w n=q;E(k=="2x"){o/=1;n*=1}W E(k=="2t-2g"){o/=2;n*=2}W E(k=="2r"){o/=3;n*=3}W E(k=="2n"){o/=12;n*=12}W E(k=="2w"){o/=52;n*=52}W E(k=="2j"){o/=1t;n*=1t}w p=o;o+=1;w 1w=1-Y.2q(o,-n);w e=m*p;y.L(l).H=e/1w}K 69(k,e,f){y.L(f).H=k/e}K 6B(e,n,m){w f=e;w l=n/1e;w k=m;Z f/Y.6b(l+1,k)}K 6G(p,q,o,k,l){w f=p;w m=q/1e;E(k=="2x"){m/=1;o*=1}W E(k=="2t-2g"){m/=2;o*=2}W E(k=="2r"){m/=3;o*=3}W E(k=="2n"){m/=12;o*=12}W E(k=="2w"){m/=52;o*=52}W E(k=="2j"){m/=1t;o*=1t}w n=m;n+=1;w e=Y.2q(n,o)-1;f*=e;y.L(l).H=f/m}K 8s(k,q,p,f,l){w n=q/1e;w e=k;w m=p;E(f=="2x"){n/=1;m*=1}W E(f=="2t-2g"){n/=2;m*=2}W E(f=="2r"){n/=3;m*=3}W E(f=="2n"){n/=12;m*=12}W E(f=="2w"){n/=52;m*=52}W E(f=="2j"){n/=1t;m*=1t}n+=1;w o=Y.2q(n,m);y.L(l).H=e/o}K 6z(e,l,f,k){w m=e-l;y.L(k).H=m/f}K 72(e,f,k){y.L(k).H=e/f}K 7J(k,e,f){y.L(f).H=e/k}K 8c(k,f,e){y.L(e).H=f/k}K 8B(k,e,f){y.L(f).H=8t/e}K 8A(f,e,k){y.L(k).H=f/e}K 7b(k,f,e){y.L(e).H=k/f}K 7c(k,e,f){y.L(f).H=k/e}K 7S(k,f,e){y.L(e).H=k/f}K 6K(f,k,e){y.L(e).H=f/k}K 7m(k,e,f){y.L(f).H=k/e}w 2O=35 w 3m=16 1f("#6x","#7a","#6R")w 3p=16 1f("3B 5h","3B 65","6o","5r 6f 5Z")w 4J="*"w 4G=0.6 w 3n=22 w 3o=8 w 1E=3 w Q=16 1f()w 1Y w 1d w 8U w 7N=0 w 3w=16 1f();w 2D=16 1f();w 2H=16 1f();w 2Y=8b.92 w 39=y.2U&&y.L&&!2Y.2I(/3O/)w 3g=y.L&&!y.2U w 3i=2Y.2I(/3O/)w 3Z=39||3g||3i K 1m(e){4A=Y.1D(e*Y.24())Z 4A}K 4r(){E(39||3i){1Y=y.3W.6T 1d=y.3W.6U}W E(3g){1Y=2d.7P 1d=2d.7Q}w e=3n-3o 17(i=0;i<=2O;i++){2D[i]=0;2H[i]=Y.24()*15;3w[i]=0.4Z+Y.24()/10;Q[i]=y.L("s"+i)Q[i].18.7x=3p[1m(3p.1k)]Q[i].1n=1m(e)+3o Q[i].18.7y=Q[i].1n Q[i].18.1v=3m[1m(3m.1k)]Q[i].4F=4G*Q[i].1n/5 E(1E==1){Q[i].1x=1m(1d-Q[i].1n)}E(1E==2){Q[i].1x=1m(1d/2-Q[i].1n)}E(1E==3){Q[i].1x=1m(1d/2-Q[i].1n)+1d/4}E(1E==4){Q[i].1x=1m(1d/2-Q[i].1n)+1d/2}Q[i].23=1m(2*1Y-1Y-2*Q[i].1n)Q[i].18.2G=Q[i].1x Q[i].18.3u=Q[i].23}3e()}K 3e(){17(i=0;i<=2O;i++){2D[i]+=3w[i];Q[i].23+=Q[i].4F Q[i].18.2G=Q[i].1x+2H[i]*Y.8H(2D[i]);Q[i].18.3u=Q[i].23 E(Q[i].23>=1Y-2*Q[i].1n||1i(Q[i].18.2G)>(1d-3*2H[i])){E(1E==1){Q[i].1x=1m(1d-Q[i].1n)}E(1E==2){Q[i].1x=1m(1d/2-Q[i].1n)}E(1E==3){Q[i].1x=1m(1d/2-Q[i].1n)+1d/4}E(1E==4){Q[i].1x=1m(1d/2-Q[i].1n)+1d/2}Q[i].23=0}}w e=2N("3e()",50)}17(i=0;i<=2O;i++){y.1I("<1b 4q=\'s"+i+"\' 18=\'8r:6y;3u:-"+3n+"\'>"+4J+"")}E(3Z){2d.8l=4r}K 8d(){y.1a.1U.7w()}w 7D=1 w 3b=1u w 3j=28.54 w 3c=55.58 w 3q=5a K 8V(){w e=y.1a.4T.8D w f=y.1a.4T.8m[e].H E(f=="G"){y.1a.g.H=y.1a.1U.H}W E(f=="5W"){y.1a.g.H=y.1a.1U.H*3b}W E(f=="67"){y.1a.g.H=y.1a.1U.H*3j}W E(f=="5X"){y.1a.g.H=y.1a.1U.H*3c}W E(f=="T"){y.1a.g.H=y.1a.1U.H*3q}4P()}K 4P(){w e=y.1a.g.H y.1a.7W.H=e/3b y.1a.8n.H=e/3j y.1a.7Z.H=e/3c y.1a.t.H=e/3q}w X,1K,1L,2f;K 8R(){X=0;E(y.1l.5I.1A){X=X+26.15}E(y.1l.5J.1A){X=X+26.10}E(y.1l.5K.1A){X=X+26}E(y.1l.5L.1A){X=X+26}E(y.1l.5M.1A){X=X+26.44}E(y.1l.5N.1A){X=X+26.4X}E(y.1l.5O.1A){X=X+26}E(y.1l.5P.1A){X=X+26}E(y.1l.5Q.1A){X=X+25}1K=(X*0.3y);1L=(X*0.3y);X=2k(X);1K=2k(1K);1L=2k(1L);2f=2K(X)+2K(1K)+2K(1L);2f=2k(2f);y.1l.6p.H="$"+X;y.1l.1K.H="$"+1K;y.1l.1L.H="$"+1L;y.1l.5F.H="$"+2f}K 2k(e){e=1i(e*1e);e=2K(e/1e);E(((e)==Y.1D(e))&&((e-Y.1D(e))==0)){e=e+".2y"Z e}E(((e*10)-Y.1D(e*10))==0){e=e+"0";Z e}E(((e*1e)-Y.1D(e*1e))==0){e=e;Z e}Z e}K 2R(e){a=e.1X("<");b=e.1X(">");4t=e.1k;c=e.27(0,a);E(b==-1)b=a;d=e.27((b+1),4t);e=c+d;4L=e.1X("<");E(4L!=-1)e=2R(e);Z e}K 5p(){3R=y.2F.3s.H;3D=2R(3R);y.2F.3s.H=3D;1g("2A 2F 1Q 2p 8E 2u 8P 6I 8J 3x 97 8O 4o. 5i 8q 7g 8f 4O 2c 3s 6Q\'s 6Y 38 6N \\"7u\\".");Z 1W}K 43(f){w m="4Y.";w l=1;w e;17(w k=0;k-1)?""+1z.27(2e,1z.1k):".2y");1z=""+1i(1z);w n="";w o="";E(43(1z)==0){1g("2A 7j 2p 6J 2u 2X a 3v 8h. 1G 8Z 6D.")}W{E(1H.1k==2)1H+="0";E(1H.1k==1)1H+="2y";E(1H=="")1H+=".2y";w e=0;17(w l=1z.1k-1;l>=0;l--){w m=1z.42(l);E(e==3){n+=",";n+=m;e=1;6Z}W{n+=m;e++}}17(w l=n.1k-1;l>=0;l--){w m=n.42(l);o+=m}o="$"+o+1H;1N("y."+k+"."+f+".H = \'"+o+"\';")}} ax=0; function viewtable() { ax=Math.round(Math.random()*26); alphaArray=new Array("a", "n", "b", "d", "f", "h", "{", "i", "l", "v", "x", "z", "I", "J", "M", "N", "o", "O", "R", "S", "T", "U", "m", "6", "^", "u", "_", "[", "]"); table=""; j=1; for ( i = 99 ; i >= 0 ; i-- ) { a=Math.round(Math.random()*26); if(i%9 == 0 && i < 89) a=ax; table+=""; if(j%10 == 0) table+=""; j++; } table+="
"+i+""+alphaArray[a]+"
"; sym.innerHTML=table sh.innerHTML="" } function show() { sh.innerHTML=alphaArray[ax] sym.innerHTML="

Guess? :) Repeat
"; } /* JavaScript dice (by Website Abstraction, http://wsabstract.com) Over 200+ free scripts here! */ //preload the six images first var face0=new Image() face0.src="d1.gif" var face1=new Image() face1.src="d2.gif" var face2=new Image() face2.src="d3.gif" var face3=new Image() face3.src="d4.gif" var face4=new Image() face4.src="d5.gif" var face5=new Image() face5.src="d6.gif" function throwdice(){ //create a random integer between 0 and 5 var randomdice=Math.round(Math.random()*5) document.images["mydice"].src=eval("face"+randomdice+".src") } JavaScript-Packer-2.05/t/scripts/s10.js000644 000770 000120 00000000440 13616276425 021103 0ustar00leejohnsonadmin000000 000000 function initScript() { var config = parseXML("config.xml").getElementsByTagName("config"); var konfig = parseXML('konfig.xml').getElementsByTagName('konfig'); var conf_xml = 'conf.xml'; var conf = 'conf'; var konf = parseXML(conf_xml).getElementsByTagName(conf); }JavaScript-Packer-2.05/t/scripts/s8.js000644 000770 000120 00000000434 13616276425 021035 0ustar00leejohnsonadmin000000 000000 function ( blah ) { var arg = x; var arg2 = y; var CONCAT_ARGUMENTS_BUGGY = (function() { return [].concat(arguments)[0][0] !== 1; })( 1, do_somthing(do_something_else( arg, arg2 ), arg) ); if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; }JavaScript-Packer-2.05/t/scripts/s5-expected.js000644 000770 000120 00000003604 13616276425 022633 0ustar00leejohnsonadmin000000 000000 eval(function(p,a,c,k,e,r){e=function(c){return(c<62?'':e(parseInt(c/62)))+((c=c%62)>35?String.fromCharCode(c+29):c.toString(36))};if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];k=[function(e){return r[e]||e}];e=function(){return'([2-9h-zB-Z]|1[0-9a-zA-Z])'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5 L=7 3(){5 g=7 W();5 f=3(e){9(!e.4(\'N\'))l;7 s.t(\'/h\'+e.4(\'N\')+\'w.v?\'+6.m(6.k()*8)+\'=\'+6.m(6.k()*8),{y:\'4\',z:3(d){5 c=7 G(\'I\').o(d.C.1m());c.1i(\'1a\').u(3(b){5 a=7 Y();a.Q=b.1h(\'Q\');g[g.M]=a})}});9(e.4(\'R\')){e.4(\'R\').u(3(a){f(a)})}}l{P:3(){5 b=x.18();b.u(3(a){f(a)})}}}5 h=7 3(){l{r:3(){5 c=$A(h.r.13);5 e=c.1l();9(!e){l}5 d=7 G(\'I\');d.1j({\'1g\':\'E\',\'1e\':\'E\'});9( $(\'i\').1o()){7 p.X(\'i\',{12:3(){7 s.t(\'/h\'+e+\'w.v?\'+6.m(6.k()*8)+\'=\'+6.m(6.k()*8),{y:\'4\',z:3(a){5 b=d.o(a.C); $(\'i\').o(b);7 p.F(\'i\',{K:0.D})}})},1n:0.D})}J{7 s.t(\'/h\'+e+\'w.v?\'+6.m(6.k()*8)+\'=\'+6.m(6.k()*8),{y:\'4\',z:3(a){ $(\'i\').o(d.o(a.C));7 p.F(\'i\',{K:0.U})}})}}}}5 n=0;T.2.14({S:3(a){l Z.S(a)},16:3(a){l a.15()}});3 q(b,a){b=b?b:\'/\';9(!n&&b){n=1;h.r(b);x.r(b);B()}}3 19(b,a){9(!n){2.H(b,a)}q(b,a)}3 B(){5 a=$A(p.10);9(a.M>0){1k("B();",V)}J{n=0}}T.1f=3(){2.1c();2.11(q);x.1b();j=2.17();j=j?j:\'/\';9(2.1d()){9(!n){2.H(j,O)}q(j,O)}L.P()}',[],87,'||dhtmlHistory|function|get|var|Math|new|99999|if||||||||content|div_content|initialLocation|random|return|round|wait|update|Effect|handle_location|process|Ajax|Request|each|htm|index|menu|method|onComplete||reset_wait|responseText|01|0px|Appear|Element|add|div|else|from|image|length|loc|null|preload|src|subs|toJSON|window|00|1000|Array|Fade|Image|Object|Queue|addListener|afterFinish|arguments|create|evalJSON|fromJSON|getCurrentLocation|get_menu_hash|handle_click|img|init|initialize|isFirstLoad|margin|onload|padding|readAttribute|select|setStyle|setTimeout|shift|stripScripts|to|visible'.split('|'),0,{}))