JavaScript-Packer-2.03/000755 000765 000120 00000000000 13075336617 016213 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.03/Changes000644 000765 000120 00000010610 13075336607 017503 0ustar00leejohnsonadmin000000 000000 Revision history for JavaScript-Packer 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.03/MANIFEST000644 000765 000120 00000001224 13075336617 017343 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 META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) JavaScript-Packer-2.03/META.json000644 000765 000120 00000002451 13075336617 017636 0ustar00leejohnsonadmin000000 000000 { "abstract" : "Perl version of Dean Edwards' Packer.js", "author" : [ "Lee Johnson " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.24, 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.03", "x_serialization_backend" : "JSON::PP version 2.27400_02" } JavaScript-Packer-2.03/META.yml000644 000765 000120 00000001453 13075336616 017466 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.24, 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.03' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' JavaScript-Packer-2.03/Makefile.PL000644 000765 000120 00000001415 13075336546 020167 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.03/README000644 000765 000120 00000007111 13075335754 017074 0ustar00leejohnsonadmin000000 000000 NAME JavaScript::Packer - Perl version of Dean Edwards' Packer.js VERSION Version 2.00 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 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.03/lib/000755 000765 000120 00000000000 13075336616 016760 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.03/t/000755 000765 000120 00000000000 13075336616 016455 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.03/t/00-load.t000644 000765 000120 00000000247 13075335754 020003 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.03/t/01-interface.t000644 000765 000120 00000004161 13075335754 021024 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.03/t/02-io.t000644 000765 000120 00000015003 13075335754 017471 0ustar00leejohnsonadmin000000 000000 #!perl -T # =========================================================================== # # # Most of these tests are stolen from JavaScript::Minifier # # =========================================================================== # use Test::More; my $not = 30; 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' ); 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.03/t/03-leaks.t000644 000765 000120 00000001217 13075335754 020164 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.03/t/pod.t000644 000765 000120 00000000350 13075335754 017424 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.03/t/scripts/000755 000765 000120 00000000000 13075336616 020144 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.03/t/scripts/s1-expected.js000644 000765 000120 00000000210 13075335754 022617 0ustar00leejohnsonadmin000000 000000 function(hmpf){var argh='blah blubb';var y=3;alert(argh);var x=1;//@a var x=hmpf;/*@abcd var x=1;@*/abcd var z=$H()};/*@abcd var x=1;@*/JavaScript-Packer-2.03/t/scripts/s1.js000644 000765 000120 00000000341 13075335754 021025 0ustar00leejohnsonadmin000000 000000 function ( hmpf ) { var argh = 'blah blubb'; var y = 3; alert( argh ); var x = 1;//@a var x = hmpf;/*@ abcd var x = 1;@*/ abcd /*a*/ /* blah */ var z = $H(); // comment }; // another comment /*@ abcd var x = 1;@*/ JavaScript-Packer-2.03/t/scripts/s10-expected.js000644 000765 000120 00000000326 13075335754 022707 0ustar00leejohnsonadmin000000 000000 function initScript(){var c=parseXML("config.xml").getElementsByTagName("config");var e=parseXML('konfig.xml').getElementsByTagName('konfig');var b='conf.xml';var a='conf';var d=parseXML(b).getElementsByTagName(a)}JavaScript-Packer-2.03/t/scripts/s10.js000644 000765 000120 00000000440 13075335754 021105 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.03/t/scripts/s2-expected.js000644 000765 000120 00000000174 13075335754 022631 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.03/t/scripts/s2.js000644 000765 000120 00000000341 13075335754 021026 0ustar00leejohnsonadmin000000 000000 function ( hmpf ) { var argh = 'blah blubb'; var y = 3; alert( argh ); var x = 1;//@a var b = hmpf;/*@ abcd var x = 1;@*/ abcd /*a*/ /* blah */ var z = $H(); // comment }; // another comment /*@ abcd var x = 1;@*/ JavaScript-Packer-2.03/t/scripts/s3-expected.js000644 000765 000120 00000000562 13075335754 022633 0ustar00leejohnsonadmin000000 000000 eval(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'[024-9]'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5(c){0 a=\'2 9\';0 e=3;8(a);0 d=1;//@a\n0 b=c;/*@4 0 d=1;@*/4 0 6=$7()};',[],10,'var||blah||abcd|function|f|H|alert|blubb'.split('|'),0,{}))JavaScript-Packer-2.03/t/scripts/s3.js000644 000765 000120 00000000312 13075335754 021025 0ustar00leejohnsonadmin000000 000000 function ( hmpf ) { var argh = 'blah blubb'; var y = 3; alert( argh ); var x = 1;//@a var b = hmpf;/*@ abcd var x = 1;@*/ abcd /*a*/ /* blah */ var z = $H(); // comment }; // another comment JavaScript-Packer-2.03/t/scripts/s4-expected.js000644 000765 000120 00000000174 13075335754 022633 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.03/t/scripts/s4.js000644 000765 000120 00000000341 13075335754 021030 0ustar00leejohnsonadmin000000 000000 function ( hmpf ) { var argh = 'blah blubb'; var y = 3; alert( argh ); var x = 1;//@a var b = hmpf;/*@ abcd var x = 1;@*/ abcd /*a*/ /* blah */ var z = $H(); // comment }; // another comment /*@ abcd var x = 1;@*/ JavaScript-Packer-2.03/t/scripts/s5-expected.js000644 000765 000120 00000003604 13075335754 022635 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,{}))JavaScript-Packer-2.03/t/scripts/s5.js000644 000765 000120 00000007037 13075335754 021042 0ustar00leejohnsonadmin000000 000000 var image = new function() { var preloaded_images = new Array(); var check_content = function( item ) { if ( ! item.get( 'loc' ) ) return; new Ajax.Request( '/content' + item.get( 'loc' ) + 'index.htm?' + Math.round( Math.random() * 99999 ) + '=' + Math.round( Math.random() * 99999 ), { method: 'get', onComplete : function( req ) { var div = new Element( 'div' ).update( req.responseText.stripScripts() ); div.select( 'img' ).each( function( img ) { var bild = new Image(); bild.src = img.readAttribute('src'); preloaded_images[preloaded_images.length] = bild; //alert( bild.src ); } ) } } ); if ( item.get( 'subs' ) ) { item.get( 'subs' ).each( function( sub_item ) { check_content( sub_item ); } ); } } return { preload : function() { var menu_hash = menu.get_menu_hash(); menu_hash.each( function( item ) { check_content( item ); } ); } } } var content = new function() { return { process : function() { var args = $A( content.process.arguments ); var loc = args.shift(); if ( ! loc ) { return; } var inner_div = new Element( 'div' ); inner_div.setStyle( { 'padding' : '0px', 'margin' : '0px' } ); if ( $( 'div_content' ).visible() ) { new Effect.Fade( 'div_content', { afterFinish : function() { new Ajax.Request( '/content' + loc + 'index.htm?' + Math.round( Math.random() * 99999 ) + '=' + Math.round( Math.random() * 99999 ), { method: 'get', onComplete : function( req ) { var the_content = inner_div.update( req.responseText ); $( 'div_content' ).update( the_content ); new Effect.Appear( 'div_content', { from : 0.01 } ); } } ) }, to : 0.01 } ); } else { new Ajax.Request( '/content' + loc + 'index.htm?' + Math.round( Math.random() * 99999 ) + '=' + Math.round( Math.random() * 99999 ), { method: 'get', onComplete : function( req ) { $( 'div_content' ).update( inner_div.update( req.responseText ) ); new Effect.Appear( 'div_content', { from : 0.00 } ); } } ) } } } } // ---------------------------------------------------------------------------- var wait = 0; window.dhtmlHistory.create( { toJSON: function(o) { return Object.toJSON(o); }, fromJSON: function(s) { return s.evalJSON(); } } ); function handle_location( newLocation, historyData ) { newLocation = newLocation ? newLocation : '/'; if ( ! wait && newLocation ) { wait = 1; content.process( newLocation ); menu.process( newLocation ); reset_wait(); } } function handle_click( newLocation, historyData ) { if ( ! wait ) { dhtmlHistory.add( newLocation, historyData ); } handle_location( newLocation, historyData ); } function reset_wait() { var queue = $A(Effect.Queue); if ( queue.length > 0 ) { setTimeout( "reset_wait();", 1000 ); } else { wait = 0; } } window.onload = function() { dhtmlHistory.initialize(); dhtmlHistory.addListener(handle_location); menu.init(); initialLocation = dhtmlHistory.getCurrentLocation(); initialLocation = initialLocation ? initialLocation : '/'; if ( dhtmlHistory.isFirstLoad() ) { if ( ! wait ) { dhtmlHistory.add( initialLocation, null ); } handle_location( initialLocation, null ); } image.preload(); //alert( 'onload' ); }JavaScript-Packer-2.03/t/scripts/s7-expected.js000644 000765 000120 00000000307 13075335754 022634 0ustar00leejohnsonadmin000000 000000 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),arg1));if(CONCAT_ARGUMENTS_BUGGY)arrayProto.concat=concat;JavaScript-Packer-2.03/t/scripts/s7.js000644 000765 000120 00000000357 13075335754 021042 0ustar00leejohnsonadmin000000 000000 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 ), arg1) ); if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;JavaScript-Packer-2.03/t/scripts/s8-expected.js000644 000765 000120 00000000234 13075335754 022634 0ustar00leejohnsonadmin000000 000000 function(d){var b=x;var c=y;var a=(function(){return[].concat(arguments)[0][0]!==1})(1,do_somthing(do_something_else(b,c),b));if(a)arrayProto.concat=concat}JavaScript-Packer-2.03/t/scripts/s8.js000644 000765 000120 00000000434 13075335754 021037 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.03/t/scripts/s9-expected.js000644 000765 000120 00000000341 13075335754 022634 0ustar00leejohnsonadmin000000 000000 function(blah,_no_shrink_){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.03/t/scripts/s9.js000644 000765 000120 00000000451 13075335754 021037 0ustar00leejohnsonadmin000000 000000 function ( blah, _no_shrink_ ) { 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.03/lib/JavaScript/000755 000765 000120 00000000000 13075336616 021026 5ustar00leejohnsonadmin000000 000000 JavaScript-Packer-2.03/lib/JavaScript/Packer.pm000644 000765 000120 00000062575 13075336555 022612 0ustar00leejohnsonadmin000000 000000 package JavaScript::Packer; use 5.008009; use warnings; use strict; use Carp; use Regexp::RegGrp; # =========================================================================== # our $VERSION = "2.03"; 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.02 =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 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