diff --git a/CHANGES.txt b/CHANGES.txt index f58d74a..5377adb 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,8 @@ NEXT RELEASE web, those will be handled independently). - Better error messaging across the board (no more "..." errors). - Lots of adjustments to reduce the minified size by several kilobytes. + - Created several utilities in the bin directory for creating combined + and minified versions of o.js. Classes: - Renamed o.Constructor to o.Class, because that is what it is and it is less to type. diff --git a/bin/combine b/bin/combine new file mode 100755 index 0000000..38c0ab4 --- /dev/null +++ b/bin/combine @@ -0,0 +1,197 @@ +#!/usr/bin/env perl +use strict; +use warnings FATAL => 'all'; + +use autodie; +use FindBin qw( $Bin ); +use Getopt::Long; +use Pod::Usage qw( pod2usage ); + +GetOptions( + 'help' => \my $help, + 'lib-dir=s' => \my $lib_dir, + 'out-file=s' => \my $out_file, + 'require=s' => \my @requires, + 'version=s' => \my $version, +) or die "Unable to process options.\n"; + +if ($help) { + pod2usage( -verbose => 2 ); + exit 0; +} + +$lib_dir ||= "$Bin/../lib"; +$out_file ||= "$Bin/../o.js"; +@requires = map { split(/,/, $_) } @requires; + +print "# lib-dir: $lib_dir\n"; +print "# out-file: $out_file\n"; +print "# version: $version\n" if $version; + +if (!@requires) { + open(my $fh, '<', "$lib_dir/o.js"); + my $js = do { local $/; <$fh> }; + + $js =~ s{ + (\S+): \s* require\( + }{ + push @requires, $1; + ''; + }sxeg; +} + +print '# require: ' . join(', ', @requires) . "\n"; + +my $files = {}; +load_file( $_ ) for @requires; + +print "Generating version header...\n"; +my $version_command = "$Bin/version-header"; +$version_command .= " --version=$version" if $version; +my $version_header = `$version_command`; +die "Version header doesn't look right!" if $version_header !~ m{^//.*v\d}s; +$version_header =~ s{\s*$}{}s; +print "Version header generated.\n"; + +print "Generating combined JavaScript...\n"; + +my $names_added = {}; +my @names_sorted; +my @names_left = sort keys %$files; + +while (@names_left) { + my $name = shift @names_left; + my $file = $files->{$name}; + my $resolved = 1; + + foreach my $require (@{ $file->{requires} }) { + $resolved = 0 if !$names_added->{$require}; + } + + if ($resolved) { + push @names_sorted, $name; + $names_added->{$name} = 1; + } + else { + push @names_left, $name; + } +} + +print "Done generating.\nWriting combined JavaScript to '$out_file'...\n"; + +open(my $fh, '>', $out_file); + +print $fh <{$name}->{js}; +} + +print $fh "\n}).call(this);\n"; + +print "All done!\n"; + +sub load_file { + my ($name) = @_; + return if $files->{$name}; + my $file = $files->{$name} = {}; + + print "Loading o-$name module.\n"; + + open(my $fh, '<', "$lib_dir/o-$name.js"); + my $js = do { local $/; <$fh> }; + + my @requires; + $js =~ s{ + var \s+ o_(\S+) \s* = \s* require\( '\./.*?' \); + }{ + push @requires, $1; + ''; + }sxeg; + + load_file( $_ ) for @requires; + + $js =~ s{module.exports =}{var o_$name =}s; + $js =~ s{var o_$name = o_$name;}{}s; + $js =~ s{^\s*(.*?)\s*$}{$1}s; + $js .= "\no.$name = o_$name;"; + + $file->{requires} = \@requires; + $file->{js} = "$js\n"; + + return; +} + +__END__ + +=head1 NAME + +combine - Combine the source o.js modules into a single file. + +=head1 SYNOPSIS + + cd o-js + bin/combine + git add o.js + +=head1 DESCRIPTION + +This script takes the various o.js source CommonJS/NPM style modules +and creates a single JavaScript file ready for inclusion in a website. + +=head1 ARGUMENTS + +=head2 help + + bin/combine --help + +Shows this documentation. + +=head2 lib-dir + + bin/combine --lib-dir= + +The directory where the source o.js modules reside. Defaults to +C<$script_dir/../lib>. + +=head2 out-file + + bin/combine --out-file= + +The filename to write the resulting, combined, JavaScript to. Defaults +to C<$script_dir/../o.js>. + +=head2 require + + bin/combine --require=, + +A list of required o.js modules that you would like included in the +resulting combined JavaScript. If a module specified has dependencies +that are not specified then the dependencies will automatically be +included. + +Defaults to all modules required by the main C module found in +the lib directory. + +=head2 version + + bin/combine --version= + +Override the default version that will included in the version header +in the combined JavaScript. diff --git a/bin/minify b/bin/minify new file mode 100755 index 0000000..4909170 --- /dev/null +++ b/bin/minify @@ -0,0 +1,126 @@ +#!/usr/bin/env perl +use strict; +use warnings FATAL => 'all'; + +use autodie; +use FindBin qw( $Bin ); +use Getopt::Long; +use Pod::Usage qw( pod2usage ); +use LWP::UserAgent; + +GetOptions( + 'help' => \my $help, + 'src-file=s' => \my $src_file, + 'min-file=s' => \my $min_file, + 'version=s' => \my $version, +) or die "Unable to process options.\n"; + +if ($help) { + pod2usage( -verbose => 2 ); + exit 0; +} + +$src_file ||= "$Bin/../o.js"; +$min_file ||= "$Bin/../o-min.js"; + +print "# src-file: $src_file\n"; +print "# min-file: $min_file\n"; +print "# version: $version\n" if $version; + +open(my $src_fh, '<', $src_file); +my $src_js = do { local $/; <$src_fh> }; + +my $url = 'http://closure-compiler.appspot.com/compile'; +my $ua = LWP::UserAgent->new(); + +print "Checking '$src_file' for errors...\n"; + +my $check_res = $ua->post( + $url, + { + js_code => $src_js, + compilation_level => 'SIMPLE_OPTIMIZATIONS', + output_format => 'text', + output_info => 'errors', + }, +); + +my $errors = $check_res->decoded_content(); +die "You've got some errors, aborting minification!\n$errors" if $errors =~ m{\S}; + +print "No errors.\nGenerating version header...\n"; + +my $version_command = "$Bin/version-header"; +$version_command .= " --version=$version" if $version; +my $version_header = `$version_command`; +die "Version header doesn't look right!" if $version_header !~ m{^//.*v\d}s; +$version_header =~ s{\s*$}{}s; + +print "Version header generated.\nMinifying...\n"; + +my $compile_res = $ua->post( + $url, + { + js_code => $src_js, + compilation_level => 'SIMPLE_OPTIMIZATIONS', + output_format => 'text', + output_info => 'compiled_code', + }, +); + +my $min_js = $compile_res->decoded_content(); + +print "Minification done.\nWriting JavaScript to '$min_file'...\n"; + +$min_js = "$version_header\n$min_js"; +open(my $min_fh, '>', $min_file); +print $min_fh $min_js; + +print "All done!\n"; + +__END__ + +=head1 NAME + +minify - Minify a combined o.js file. + +=head1 SYNOPSIS + + cd o-js + bin/minify + git add o-min.js + +=head1 DESCRIPTION + +This script takes the combined o.js produced by C and +produces a minified form of that JavaScript ready for inclusion in +a production web site. + +=head1 ARGUMENTS + +=head2 help + + bin/minify --help + +Shows this documentation. + +=head2 src-file + + bin/minify --src-file= + +The source, unminified, C as produced by C. +Defaults to C<$script_dir/../o.js>. + +=head2 min-file + + bin/minify --min-file= + +The file to write the minified JavaScript to. Defaults to +C<$script_dir/../o-min.js>. + +=head2 version + + bin/minify --version= + +Override the default version that will included in the version header +in the minified JavaScript. diff --git a/bin/version-header b/bin/version-header new file mode 100755 index 0000000..18ba31c --- /dev/null +++ b/bin/version-header @@ -0,0 +1,80 @@ +#!/usr/bin/env perl +use strict; +use warnings FATAL => 'all'; + +use autodie; +use FindBin qw( $Bin ); +use Getopt::Long; +use Pod::Usage qw( pod2usage ); + +GetOptions( + 'help' => \my $help, + 'repo-dir=s' => \my $repo_dir, + 'version=s' => \my $version, +) or die "Unable to process options.\n"; + +if ($help) { + pod2usage( -verbose => 2 ); + exit 0; +} + +$repo_dir ||= "$Bin/.."; + +if (!$version) { + my $string = `cd $repo_dir && git tag`; + my @versions = ( + map { $_->[1] } + sort { $b->[0] <=> $a->[0] } + map { [ ($_->[0]*1000000)+($_->[1]*1000)+$_->[2], $_->[3] ] } + map { my $v=$_; ($v =~ m{^v(\d+)\.(\d+)\.(\d+)$}s) ? [$1,$2,$3,$v] : () } + split(/\s+/s, $string) + ); + $version = shift( @versions ); + die "Unable to find the most recent version using 'git tag'!\n" if !$version; +} + +die "Invalid version $version!\n" if $version !~ m{^v\d+\.\d+\.\d+$}s; + +print "// o.js : $version : http://o-js.com : MIT License\n"; + +__END__ + +=head1 NAME + +version-header - Prints out the version header to be included in combined files. + +=head1 SYNOPSIS + + bin/version-header + +=head1 DESCRIPTION + +The combined C and C files have a version header at +the top that includes the version of o.js, the URL to the website, +and the license declaration. This script print this version header +and is used by both the combine and minify scripts. + +=head1 ARGUMENTS + +=head2 help + + bin/version-header --help + +Shows this documentation. + +=head2 repo-dir + + bin/version-header --repo-dir= + +The directory where the o-js repo is which will be used for +finding the most recent version tag if none is specified. +Defaults to C<$script_dir/..>. + +=head2 version + + bin/version-header --version= + +The version of o.js to incude in the version header. Defaults to +the most recent version tag. Must be in the format of C where +C is a positive integer. +