Skip to content

Commit

Permalink
Initial commit of customizr
Browse files Browse the repository at this point in the history
  • Loading branch information
kevingorski committed Sep 20, 2011
1 parent 2ae4833 commit 90bccc1
Show file tree
Hide file tree
Showing 8 changed files with 2,268 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1 +1,2 @@
modernizr.min.js
customizr/node_modules
54 changes: 54 additions & 0 deletions customizr/Readme.md
@@ -0,0 +1,54 @@
# Customizr

Modernizr custom build tool utility written with nodejs.

## Installation

$ npm install -g customizr

## Usage

```bash

Usage: customizr [options]

Options:

-h, --help Output usage information
-v, --version Output the version number
-c, --config [fileName] The name of a conifguration file containing a JSON object that has properties for any of the following options. If no name is provided, uses modernizr-config.json
-o, --output <fileName> Write generated Modernizr build to this output file
-a, --all Include all tests
-e, --extras <items> Include extras
-g, --groups <groups> Include tests by group (html5, css3, misc)
-t, --tests <tests> Include tests explicitly
-n, --not <groups|tests|extras> Exclude specific groups, tests, or extras

```

## Examples

All (except .load + .respond)
customizr --all -o output.js

All + extras
customizr --all --extras load,respond

Groups
customizr --groups html5,css3 >> output.js

Explicit
customizr --tests svg,fontface -o output.js

Subtractive
customizr --all --not svg,css3 >> output.js

Config
customizr --config modernizr-config.json

Where `modernizr-config.json` contains:
{
"tests": [ "svg", "websockets" ],
"extras": [ "load" ],
"output": "./output.js"
}
333 changes: 333 additions & 0 deletions customizr/bin/customizr
@@ -0,0 +1,333 @@
#!/usr/bin/env node

/**
* Customizr
* Modernizr Custom Build Tool
* Command-line tool for building custom Modernizr
*
* @Author Kevin Gorski - kevin.gorski@gmail.com
*/

// Modules
var fs = require('fs')
, path = require('path')
, program = require('commander')
, Modulizr = require('../modulizr')
, parser = require('uglify-js').parser
, uglify = require('uglify-js').uglify

// Constants
, ModernizrVersion = '2.0.6'
, groups = [
{
name: "css3",
tests: [
"fontface"
, "backgroundsize"
, "borderimage"
, "borderradius"
, "boxshadow"
, "flexbox"
, "hsla"
, "multiplebgs"
, "opacity"
, "rgba"
, "textshadow"
, "cssanimations"
, "csscolumns"
, "cssgradients"
, "cssreflections"
, "csstransforms"
, "csstransforms3d"
, "csstransitions"
]
}, {
name: "html5",
tests: [
"applicationcache"
, "canvas"
, "canvastext"
, "draganddrop"
, "hashchange"
, "history"
, "audio"
, "video"
, "indexeddb"
, "localstorage"
, "postmessage"
, "sessionstorage"
, "websockets"
, "websqldatabase"
, "webworkers"
]
}, {
name: "misc",
tests: [
"geolocation"
, "inlinesvg"
, "smil"
, "svg"
, "svgclippaths"
, "touch"
, "webgl"
]
}]
, extras = [
"iepp",
"load",
"respond",
"mq",
"cssclasses"]
, defaultExtras = [
"iepp",
"mq",
"cssclasses"]
, validConfigNames = ['output', 'all', 'extras', 'groups', 'tests', 'not'];

function list(val) {
return val.split(',');
}

program
.version('0.0.1, Modernizr ' + ModernizrVersion)
.option('-c, --config [fileName]', 'The name of a conifguration file containing a JSON object that has properties for any of the following options. If no name is provided, uses modernizr-config.json')
.option('-o, --output <fileName>', 'Write generated Modernizr build to this output file')
.option('-a, --all', 'Include all tests')
.option('-e, --extras <items>', 'Include extras', list)
.option('-g, --groups <groups>', 'Include tests by group (html5, css3, misc)', list)
.option('-t, --tests <tests>', 'Include tests explicitly', list)
.option('-n, --not <groups|tests|extras>', 'Exclude specific groups, tests, or extras')
.parse(process.argv);


// Input: customizr || customizr -h|--help

if (program.rawArgs.length < 3) {
process.stdout.write(program.helpInformation());
process.exit();
}


// Input: customizr -v|--version
// Version handled by commander


// Clean up the console on exit if not running the default options above

process.on('exit', function() { console.log(); });


// Finally, generate the file and write it out

var fileContents
, selectedExtras;


// Input: customizr -c|--config <filename>
// filename defaults to modernizr-config.json

if(program.config) {
var configFileName = (String(program.config) === program.config)
? program.config
: 'modernizr-config.json',
config;

try {
fileContents = fs.readFileSync(path.join(process.cwd(), configFileName), 'utf8');

config = JSON.parse(fileContents);
} catch(err) {
process.stderr.write(err);
process.exit(1);
}

for(prop in config) {
if(validConfigNames.indexOf(prop) === -1) {
console.error('Property "%s" in "%s" is not a known configuration value. Try one of these: %s', prop, configFileName, validConfigNames.join(', '));

process.exit(1);
}

program[prop] = config[prop];
}
}


try {
if(program.extras)
selectedExtras = program.extras.filter(function(el) {
return defaultExtras.every(function(ex) { return el !== ex; });
});

fileContents = generateFile(buildTestsArray(), selectedExtras);
} catch(err) {
process.stderr.write(err);
process.exit(1);
}


// Input: customizr -o|--output <filename>

if(program.output) {
console.log('Writing to %s', program.output);

fs.writeFile(program.output, fileContents, function(err) {
if(err) throw err;

process.exit();
});
} else {
process.stdout.write(fileContents);
process.exit();
}


function buildTestsArray() {
var tests = [];

// -a|--all
if(program.all) {
groups.forEach(function(group) {
tests = tests.concat(group.tests);
});
}


// -g|--groups
if(program.groups) {
program.groups.forEach(function(input) {
var group = groups.filter(function(el) {
return input === el.name;
});

if(group.length === 0) {
console.error('Group "%s" not found. Try these: %s', input, groups.map(function(el) { return el.name; }).join(', '));

process.exit(1);
}
});

groups.forEach(function(group) {
if(program.groups.indexOf(group.name) === -1) return;

tests = tests.concat(group.tests);
});
}


// -e|--extras
if(program.extras) {
program.extras.forEach(function(el) {
if(extras.indexOf(el) === -1) {
console.error('Extra "%s" not found. Try these: %s', el, extras.join(', '));

process.exit(1);
}
});

var selectedExtras = program.extras.filter(
function(el){ return defaultExtras.some(
function(ex) { return el === ex; }); });

tests = tests.concat(selectedExtras);
} else {
tests = tests.concat(defaultExtras);
}


// -t|--tests
if(program.tests) {
var allTests = [];

groups.forEach(function(group) {
allTests = allTests.concat(group.tests);
});

program.tests.forEach(function(test) {
if(allTests.indexOf(test) === -1) {
console.error('Test "%s" not found.', test);

process.exit(1);
}
});

tests = tests.concat(program.tests);
}


// -n|--not
if(program.not) {
// Filter groups
groups.forEach(function(group) {
if(program.not.indexOf(group.name) > -1) {
tests = tests.filter(function(el) { return group.tests.indexOf(el) === -1; });
}
});

// Filter explicit tests/extras
tests = tests.filter(function(el) { return program.not.indexOf(el) === -1; });
}


// Dependencies
tests.forEach(function(el) {
var dependencies = Modulizr._dependencies[el];

if(!dependencies) return;

dependencies.forEach(function(dep) {
if(tests.indexOf(dep)===-1) tests.push(dep);
});
});

return tests;
}

function generateFile(tests, selectedExtras) {
if(!tests.length) throw 'No tests selected!';

if(!selectedExtras) selectedExtras = [];

function compress(script) {
// Compressing code
var ast = parser.parse(script); // parse code and get the initial AST
ast = uglify.ast_mangle(ast); // get a new AST with mangled names
ast = uglify.ast_squeeze(ast); // get an AST with compression optimizations

return uglify.gen_code(ast); // compressed code here
};

function fixUglifyBugs(modularBuild) {
// !! needs to be there, unfortch.
return modularBuild.replace("return a.history&&history.pushState", "return !!(a.history&&history.pushState)");
}

function addExtras (modularBuild) {
modularBuild = ';'+modularBuild+';';

return "\/* Modernizr custom build of " + ModernizrVersion + ": " + tests.concat(selectedExtras).join(' | ') + " *\/\n" + modularBuild;
}

function buildFile(modularBuild, appended) {
var uglifiedModularBuild = compress(modularBuild + (appended || ''), ['--extra', '--unsafe']);

return fixUglifyBugs(addExtras(uglifiedModularBuild));
}

// Grab the modernizr source and run it through modulizr
var script = fs.readFileSync(path.join(__dirname, '../modernizr.' + ModernizrVersion + '-prebuild.js'), 'utf8');

// Call the modulr function to create a modular build
var modularBuild = Modulizr.ize(script, [].slice.call(tests,0));
var toAppend;

if(selectedExtras.some(function(el){ return el == 'load' })) {
toAppend = fs.readFileSync(path.join(__dirname, '../modernizr.load.js'));
}

if(selectedExtras.some(function(el){ return el == 'respond' })) {
toAppend = (toAppend || '') + fs.readFileSync(path.join(__dirname, '../respond.js'), 'utf8');
}

return buildFile(modularBuild, toAppend);
}

0 comments on commit 90bccc1

Please sign in to comment.