Skip to content

Commit

Permalink
Moving JS API to a synchronous model.
Browse files Browse the repository at this point in the history
  • Loading branch information
7sempra committed Nov 23, 2013
1 parent 9326996 commit 0744fce
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 154 deletions.
40 changes: 33 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Rosetta

**NOTE**: The JS API has changed in v0.3, see "Javascript API", below.

Rosetta is a CSS *pre-* preprocessor that allows you to share variables between your Javascript code and a CSS preprocessor such as [Stylus](http://learnboost.github.com/stylus/), [Sass](http://sass-lang.com/), or [LESS](http://lesscss.org/).

It works like this:
Expand All @@ -11,7 +13,7 @@ Rosetta supports the following export formats:
* **Javascript:** CommonJS module, RequireJS module, or flat JS file.
* **CSS:** Stylus, Sass/Scss, or LESS syntax.

Rosetta's export system is easily extensible; it is straightforward to add new export formats as desired.
You can also add your own export formats; see the command-line documentation for more information.

## Example

Expand Down Expand Up @@ -136,9 +138,14 @@ All your variables will be exported to the format you specified, e.g.
@highlight: #2211CC // Sass format
```

However, all variables declared inside of a namespace will also be exported with a fully-qualified name:
In addition, all variables declared inside of a namespace will also be exported with a fully-qualified name:

```
colors.dialog:
$highlight = #2211CC
```
...becomes...
```
// defined in colors.dialog.$highlight
@highlight: #2211CC
@colors-dialog-highlight: #2211CC
```
Expand Down Expand Up @@ -246,19 +253,38 @@ rosetta.compile(['foo.rose', 'bar.rose'], {
}
}
});


try {
var outfiles = rosetta.compile(['foo.rose', 'bar.rose'], {
jsFormat: 'flat',
cssFormat: 'less',
jsOut: 'lib/rosetta.js',
cssOut: 'less/rosetta.less'
});
rosetta.writeFiles(outfiles);
} catch (e) {
if (e instanceof rosetta.RosettaError) {
console.error(rosetta.formatError(e));
} else {
throw e;
}
}


```
Rosetta exposes two functions: `compile` and `writeFiles`:
Rosetta exposes three functions:
```js
rosetta.compile(sources, options, callback(err, outfiles));
rosetta.compile(sources, options);
```
...where `sources` is an array of paths and `options` is an hashmap of options (see below). `outfiles` will be an array of `{path, text}` objects, which you can pass directly to `rosetta.writeFile()`.
...where `sources` is an array of paths and `options` is an hashmap of options (see below). Returns `outfiles`, which will be an array of `{path, text}` objects. You can pass this directly to `rosetta.writeFile()`.
`options` are the same as those for the command-line API.
```js
rosetta.writeFiles([{path, text}], callback(err));
rosetta.writeFiles([{path, text}]);
```
`writeFiles` will actually write all of the compiled files to disk, creating directories as necessary.
Expand Down
18 changes: 9 additions & 9 deletions bin/rosetta
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,17 @@ for (var a = 0; a < globs.length; a++) {
}
}

rosetta.compile(_.keys(sources), opts, function(err, files) {
if (err) {
die(rosetta.formatError(err));
try {
rosetta.writeFiles(rosetta.compile(_.keys(sources), opts));
} catch (e) {
if (e instanceof rosetta.RosettaError) {
die(rosetta.formatError(e));
} else {
rosetta.writeFiles(files, function(err) {
if (err) {
throw err;
}
});
throw e;
}
});
}



function printUsage() {
fs.createReadStream(__dirname + '/usage.txt')
Expand Down
23 changes: 11 additions & 12 deletions lib/errors.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
var classdef = require('classdef');

var CompileError = exports.CompileError = classdef(Error, {
name: 'CompileError',

constructor: function(type, message, token) {
Error.call(this);
Error.captureStackTrace(this, CompileError);
this.type = type;
this.message = message;
this.token = token;
}
});

var RosettaError = exports.RosettaError = classdef(Error, {
name: 'RosettaError',

Expand All @@ -20,4 +8,15 @@ var RosettaError = exports.RosettaError = classdef(Error, {
Error.captureStackTrace(this, RosettaError);
this.message = message;
}
});

var CompileError = exports.CompileError = classdef(RosettaError, {
name: 'CompileError',

constructor: function(type, message, token) {
RosettaError.call(this, message);

this.type = type;
this.token = token;
}
});
46 changes: 15 additions & 31 deletions lib/output/js.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var fs = require('fs'),
path = require('path'),
_ = require('underscore'),
classdef = require('classdef');

Expand All @@ -10,41 +11,24 @@ var _templates = {
'flat': __dirname + '/jstemplates/flat.txt'
};

module.exports.compile = function(root, options, callback) {
var template = options.jsTemplate;
if (template) {
_readPreamble(root, options, template, callback);
} else {
var templatePath = _templates[options.jsFormat];
if (!templatePath) {
callback('Unrecognized JS output format: ' + options.jsFormat);
return;
}
function _error(message) {
throw new errors.RosettaError(message);
}

_readTemplate(templatePath, root, options, callback);
}
};
module.exports.compile = function(root, options) {

function _readTemplate(templatePath, root, options, callback) {
fs.readFile(templatePath, 'utf8', function(err, templateData) {
if (err) {
throw err;
}
var preamble = fs.readFileSync(
path.join(__dirname, 'jstemplates', 'preamble.js'), 'utf8');

_readPreamble(root, options, templateData, callback);
});
}

function _readPreamble(root, options, template, callback) {
fs.readFile(__dirname + '/jstemplates/preamble.js', 'utf8',
function(err, preambleData) {
if (err) {
throw err; // TODO
}
var template = options.jsTemplate;
if (!template) {
var templatePath = _templates[options.jsFormat] ||
_error('Unrecognized JS output format: ' + options.jsFormat);
template = fs.readFileSync(templatePath, 'utf8');
}

callback(null, _compile(root, options, preambleData, template));
});
}
return _compile(root, options, preamble, template);
};

function _compile(root, options, preamble, templateStr) {
var formatter = new JsFormatter();
Expand Down
101 changes: 33 additions & 68 deletions lib/rosetta.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var css = require('./output/css'),
* variable).
* debug If true, print tons of stuff to the console.
*/
exports.compile = function(sources, options, callback) {
exports.compile = function(sources, options) {

_.defaults(options, {
jsFormat: 'commonjs',
Expand All @@ -45,81 +45,46 @@ exports.compile = function(sources, options, callback) {
});

var resolver = new Resolver();
var outfiles = [];

try {
for (var a = 0; a < sources.length; a++) {
var ast = parseFile(path.resolve(sources[a]), options);
resolver.addAst(ast);
}

if (options.debug) {
console.log('\nParse complete. Scope tree:')
resolver.printScopeTree();
}
var resolvedScope = resolver.resolve();

outfiles = css.compile(resolvedScope, options);
if (options.debug) {
outfiles.forEach(function(outFile) {
console.log(util.formatHeading(outFile.path + ':'));
console.log(outFile.text);
});
}

js.compile(resolvedScope, options, function(err, result) {
// TODO: catch this error?

if (options.debug) {
_printHeading(result.path + ':');
console.log(result.text);
}

outfiles.push(result);

callback(null, outfiles);

for (var a = 0; a < sources.length; a++) {
var ast = parseFile(path.resolve(sources[a]), options);
resolver.addAst(ast);
}

if (options.debug) {
console.log('\nParse complete. Scope tree:')
resolver.printScopeTree();
}
var resolvedScope = resolver.resolve();

var outfiles = css.compile(resolvedScope, options);
if (options.debug) {
outfiles.forEach(function(outFile) {
console.log(util.formatHeading(outFile.path + ':'));
console.log(outFile.text);
});
} catch (e) {
if (e instanceof errors.CompileError) {
callback(e);
} else {
throw e;
}
}

var jsFile = js.compile(resolvedScope, options);
if (options.debug) {
_printHeading(result.path + ':');
console.log(result.text);
}
outfiles.push(jsFile);

return outfiles;
}

exports.writeFiles = function(outfiles, callback) {

writeFile(0);

function writeFile(a) {
if (a >= outfiles.length) {
callback();
return;
}

var file = outfiles[a];
fs.writeFile(file.path, file.text, 'utf8', function(err) {
if (err) {
if (err.code == 'ENOENT') {
mkdirp(path.dirname(file.path), function(err) {
if (err) {
callback(err);
} else {
writeFile(a);
}
});
} else {
callback(err);
}
} else {
writeFile(a + 1);
}
});
exports.writeFiles = function(outfiles) {
for (var a = 0; a < outfiles.length; a++) {
var outfile = outfiles[a];
mkdirp.sync(path.dirname(outfile.path))
fs.writeFileSync(outfile.path, outfile.text, 'utf8');
}
}

exports.formatError = util.formatError;
exports.RosettaError = errors.RosettaError;

function parseFile(path, options) {
var fileStr = fs.readFileSync(path, 'utf8');
Expand Down
26 changes: 19 additions & 7 deletions lib/util.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
var errors = require('./errors');

exports.formatError = function(e) {
if (e instanceof errors.CompileError) {
return _formatCompileError(e);
} else if (e instanceof errors.RosettaError) {
return e.message;
} else {
return e.toString();
}
}

exports.formatHeading = function(message, maxLen) {
maxLen = maxLen || 80;
message = _ellipsize(message, maxLen);

return message + '\n' + _getRepeatedChar(message.length, '-') + '\n';
}

function _formatCompileError(e) {
var msg = '';

var token = e.token;
Expand All @@ -20,13 +39,6 @@ exports.formatError = function(e) {
return msg;
}

exports.formatHeading = function(message, maxLen) {
maxLen = maxLen || 80;
message = _ellipsize(message, maxLen);

return message + '\n' + _getRepeatedChar(message.length, '-') + '\n';
}

function _getLine(lineNum, source) {
var start = 0;

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rosetta",
"version": "0.2.0",
"version": "0.3.0",
"description": "Shared variables between CSS and Javascript.",
"author": {
"name": "Ned Burns",
Expand Down
Loading

0 comments on commit 0744fce

Please sign in to comment.