mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-12-05 16:24:21 +01:00
212 lines
6.7 KiB
JavaScript
212 lines
6.7 KiB
JavaScript
|
#!/usr/bin/env node
|
||
|
|
||
|
var nopt = require("nopt")
|
||
|
fs = require('fs'),
|
||
|
vm = require('vm'),
|
||
|
coffee = require('coffee-script'), /* only for watchr */
|
||
|
watch = require('watchr').watch,
|
||
|
Path = require('path'),
|
||
|
join = Path.join,
|
||
|
glob = require("glob"),
|
||
|
async = require('async'),
|
||
|
MessageFormat = require('../'),
|
||
|
_ = require('underscore'),
|
||
|
knownOpts = {
|
||
|
"locale" : String,
|
||
|
"inputdir" : Path,
|
||
|
"output" : Path,
|
||
|
"combine" : String,
|
||
|
"watch" : Boolean,
|
||
|
"namespace" : String,
|
||
|
"include" : String,
|
||
|
"stdout" : Boolean,
|
||
|
"verbose" : Boolean
|
||
|
},
|
||
|
description = {
|
||
|
"locale" : "locale to use [mandatory]",
|
||
|
"inputdir" : "directory containing messageformat files to compile",
|
||
|
"output" : "output where messageformat will be compiled",
|
||
|
"combine" : "combines multiple input files to the provided namespace array element",
|
||
|
"watch" : "watch `inputdir` for change",
|
||
|
"namespace" : "object in the browser containing the templates",
|
||
|
"include" : "Glob patterns for files to include in `inputdir`",
|
||
|
"stdout" : "Print the result in stdout instead of writing in a file",
|
||
|
"verbose" : "Print logs for debug"
|
||
|
},
|
||
|
defaults = {
|
||
|
"inputdir" : process.cwd(),
|
||
|
"output" : process.cwd(),
|
||
|
"combine" : undefined,
|
||
|
"watch" : false,
|
||
|
"namespace" : 'window.i18n',
|
||
|
"include" : '**/*.json',
|
||
|
"stdout" : false,
|
||
|
"verbose" : false
|
||
|
},
|
||
|
shortHands = {
|
||
|
"l" : "--locale",
|
||
|
"i" : "--inputdir",
|
||
|
"o" : "--output",
|
||
|
"c" : "--combine",
|
||
|
"w" : "--watch",
|
||
|
"ns" : "--namespace",
|
||
|
"I" : "--include",
|
||
|
"s" : "--stdout",
|
||
|
"v" : "--verbose"
|
||
|
},
|
||
|
options = nopt(knownOpts, shortHands, process.argv, 2),
|
||
|
argvRemain = options.argv.remain,
|
||
|
inputdir;
|
||
|
|
||
|
// defaults value
|
||
|
_(defaults).forEach(function(value, key){
|
||
|
options[key] = options[key] || value;
|
||
|
})
|
||
|
|
||
|
|
||
|
if(argvRemain && argvRemain.length >=1 ) options.inputdir = argvRemain[0];
|
||
|
if(argvRemain && argvRemain.length >=2 ) options.output = argvRemain[1];
|
||
|
|
||
|
if(!options.locale) {
|
||
|
console.error('Usage: messageformat -l [locale] [INPUT_DIR] [OUTPUT_DIR]')
|
||
|
console.error('')
|
||
|
//console.error(nopt(knownOpts, shortHands, description, defaults));
|
||
|
process.exit(-1);
|
||
|
}
|
||
|
|
||
|
var inputdir = options.inputdir;
|
||
|
|
||
|
compile();
|
||
|
if(options.watch){
|
||
|
return watch(options.inputdir, _.debounce(compile, 100));
|
||
|
}
|
||
|
|
||
|
|
||
|
function handleError( err, data ){
|
||
|
if(err){
|
||
|
err = err.message ? err.message : err;
|
||
|
return console.error('--->\t'+ err);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function compile(){
|
||
|
build(inputdir, options, function(err, data){
|
||
|
if( err ) return handleError( err );
|
||
|
write(data, function(err, output){
|
||
|
if( err ) return handleError( err );
|
||
|
if( options.verbose ) console.log(output + " written.");
|
||
|
})
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function write( data, callback ){
|
||
|
data = data.join('\n');
|
||
|
if(options.stdout) {
|
||
|
return console.log(data);
|
||
|
}
|
||
|
var output = options.output;
|
||
|
fs.stat(output, function(err, stat){
|
||
|
if(err){
|
||
|
// do nothing
|
||
|
}else if(stat.isFile()){
|
||
|
// do nothing
|
||
|
}else if(stat.isDirectory()){
|
||
|
// if `output` is a directory, create a new file called `i18n.js` in this directory.
|
||
|
output = join(output, 'i18n.js');
|
||
|
}else{
|
||
|
return engines.handleError(ouput, 'is not a file nor a directory');
|
||
|
}
|
||
|
|
||
|
fs.writeFile( output, data, 'utf8', function( err ){
|
||
|
if( typeof callback == "function" ) callback(err, output);
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
function build(inputdir, options, callback){
|
||
|
// arrays of compiled templates
|
||
|
var compiledMessageFormat = [];
|
||
|
|
||
|
// read shared include file
|
||
|
var inclFile = join(__dirname, '..', 'lib', 'messageformat.include.js');
|
||
|
if(options.verbose) console.log('Load include file: ' + inclFile);
|
||
|
fs.readFile(inclFile, function(err, inclStr){
|
||
|
if(err) handleError(new Error('Could not read shared include file.' ));
|
||
|
|
||
|
// read locale file
|
||
|
var localeFile = join(__dirname, '..', 'locale', options.locale + '.js');
|
||
|
if(options.verbose) console.log('Load locale file: ' + localeFile);
|
||
|
fs.readFile(localeFile, function(err, localeStr){
|
||
|
if(err) handleError(new Error('locale ' + options.locale + ' not supported.' ));
|
||
|
var script = vm.createScript(localeStr);
|
||
|
// needed for runInThisContext
|
||
|
global.MessageFormat = MessageFormat;
|
||
|
script.runInThisContext();
|
||
|
|
||
|
if( options.verbose ) { console.log('Read dir: ' + inputdir); }
|
||
|
// list each file in inputdir folder and subfolders
|
||
|
glob(options.include, {cwd: inputdir}, function(err, files){
|
||
|
files = files.map(function(file){
|
||
|
// normalize the file name
|
||
|
return file.replace(inputdir, '').replace(/^\//, '');
|
||
|
})
|
||
|
|
||
|
async.forEach(files, readFile, function(err){
|
||
|
// errors are logged in readFile. No need to print them here.
|
||
|
var fileData = [
|
||
|
'(function(){ ' + options.namespace + ' || (' + options.namespace + ' = {}) ',
|
||
|
'var MessageFormat = { locale: {} };',
|
||
|
localeStr.toString().trim(),
|
||
|
inclStr.toString().trim(),
|
||
|
].concat(compiledMessageFormat)
|
||
|
.concat(['})();']);
|
||
|
return callback(null, _.flatten(fileData));
|
||
|
});
|
||
|
|
||
|
// Read each file, compile them, and append the result in the `compiledI18n` array
|
||
|
function readFile(file, cb){
|
||
|
var path = join(inputdir, file);
|
||
|
fs.stat(path, function(err, stat){
|
||
|
if(err) { handleError(err); return cb(); }
|
||
|
if(!stat.isFile()) {
|
||
|
if( options.verbose ) { handleError('Skip ' + file); }
|
||
|
return cb();
|
||
|
}
|
||
|
|
||
|
fs.readFile(path, 'utf8', function(err, text){
|
||
|
if(err) { handleError(err); return cb() }
|
||
|
|
||
|
var nm = join(file).split('.')[0].replace(/\\/g, '/'); // windows users should have the same key.
|
||
|
|
||
|
if(options.combine !== undefined) {
|
||
|
nm = options.combine;
|
||
|
if( options.verbose ) console.log('Adding to ' + options.namespace + '["' + nm + '"]');
|
||
|
}
|
||
|
else {
|
||
|
if( options.verbose ) console.log('Building ' + options.namespace + '["' + nm + '"]');
|
||
|
}
|
||
|
|
||
|
compiledMessageFormat.push(compiler( options, nm, JSON.parse(text) ));
|
||
|
cb();
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function compiler(options, nm, obj){
|
||
|
var mf = new MessageFormat(options.locale),
|
||
|
cmf = [options.namespace + '["' + nm + '"] = {'];
|
||
|
|
||
|
_(obj).forEach(function(value, key){
|
||
|
var str = mf.precompile( mf.parse(value) );
|
||
|
cmf.push('"' + key + '":' + str + ',');
|
||
|
});
|
||
|
cmf[cmf.length-1] = cmf[cmf.length-1].replace(/,$/, '}');
|
||
|
return cmf;
|
||
|
}
|