node_modules

This commit is contained in:
saeid
2019-07-15 13:07:31 +04:30
parent d3735c6d30
commit ce1a3ebf9c
35713 changed files with 3639219 additions and 1 deletions
+1398
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) Automattic <developer.wordpress.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+178
View File
@@ -0,0 +1,178 @@
# Stylus [![Build Status](https://travis-ci.org/stylus/stylus.svg?branch=master)](https://travis-ci.org/stylus/stylus)
Stylus is a revolutionary new language, providing an efficient, dynamic, and expressive way to generate CSS. Supporting both an indented syntax and regular CSS style.
## Installation
```bash
$ npm install stylus -g
```
## Basic Usage
Watch and compile a stylus file from command line with
```bash
stylus -w style.styl -o style.css
```
You can also [try all stylus features on stylus-lang.com](http://stylus-lang.com/try.html), build something with stylus on [codepen](http://codepen.io) or integrate stylus with [gulp](http://gulpjs.com/) using [gulp-stylus](https://www.npmjs.com/package/gulp-stylus) or [gulp-accord](https://www.npmjs.com/package/gulp-accord).
### Example
```stylus
border-radius()
-webkit-border-radius: arguments
-moz-border-radius: arguments
border-radius: arguments
body a
font: 12px/1.4 "Lucida Grande", Arial, sans-serif
background: black
color: #ccc
form input
padding: 5px
border: 1px solid
border-radius: 5px
```
compiles to:
```css
body a {
font: 12px/1.4 "Lucida Grande", Arial, sans-serif;
background: #000;
color: #ccc;
}
form input {
padding: 5px;
border: 1px solid;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
```
the following is equivalent to the indented version of Stylus source, using the CSS syntax instead:
```stylus
border-radius() {
-webkit-border-radius: arguments
-moz-border-radius: arguments
border-radius: arguments
}
body a {
font: 12px/1.4 "Lucida Grande", Arial, sans-serif;
background: black;
color: #ccc;
}
form input {
padding: 5px;
border: 1px solid;
border-radius: 5px;
}
```
### Features
Stylus has _many_ features. Detailed documentation links follow:
- [css syntax](docs/css-style.md) support
- [mixins](docs/mixins.md)
- [keyword arguments](docs/kwargs.md)
- [variables](docs/variables.md)
- [interpolation](docs/interpolation.md)
- arithmetic, logical, and equality [operators](docs/operators.md)
- [importing](docs/import.md) of other stylus sheets
- [introspection api](docs/introspection.md)
- type coercion
- [@extend](docs/extend.md)
- [conditionals](docs/conditionals.md)
- [iteration](docs/iteration.md)
- nested [selectors](docs/selectors.md)
- parent reference
- in-language [functions](docs/functions.md)
- [variable arguments](docs/vargs.md)
- built-in [functions](docs/bifs.md) (over 60)
- optional [image inlining](docs/functions.url.md)
- optional compression
- JavaScript [API](docs/js.md)
- extremely terse syntax
- stylus [executable](docs/executable.md)
- [error reporting](docs/error-reporting.md)
- single-line and multi-line [comments](docs/comments.md)
- css [literal](docs/literal.md)
- character [escaping](docs/escape.md)
- [@keyframes](docs/keyframes.md) support & expansion
- [@font-face](docs/font-face.md) support
- [@media](docs/media.md) support
- Connect [Middleware](docs/middleware.md)
- TextMate [bundle](docs/textmate.md)
- Coda/SubEtha Edit [Syntax mode](https://github.com/atljeremy/Stylus.mode)
- gedit [language-spec](docs/gedit.md)
- VIM [Syntax](https://github.com/wavded/vim-stylus)
- Espresso [Sugar](https://github.com/aljs/Stylus.sugar)
- [Firebug extension](docs/firebug.md)
- heroku [web service](http://styl.herokuapp.com/) for compiling stylus
- [style guide](https://github.com/lepture/ganam) parser and generator
- transparent vendor-specific function expansion
### Community modules
- https://github.com/stylus/stylus/wiki
### Framework Support
- [Connect](docs/middleware.md)
- [Play! 2.0](https://github.com/patiencelabs/play-stylus)
- [Ruby On Rails](https://github.com/forgecrafted/ruby-stylus-source)
- [Meteor](http://docs.meteor.com/#stylus)
- [Grails](http://grails.org/plugin/stylus-asset-pipeline)
- [Derby](https://github.com/derbyjs/derby-stylus)
### CMS Support
- [DocPad](https://github.com/docpad/docpad)
- [Punch](https://github.com/laktek/punch-stylus-compiler)
### Screencasts
- [Stylus Intro](http://www.screenr.com/bNY)
- [CSS Syntax & Postfix Conditionals](http://www.screenr.com/A8v)
### Authors
- [TJ Holowaychuk (tj)](https://github.com/tj)
### More Information
- Language [comparisons](docs/compare.md)
## Code of Conduct
Please note that this project is released with a [Contributor Code of Conduct](Code_of_Conduct.md). By participating in this project you agree to abide by its terms.
## License
(The MIT License)
Copyright (c) Automattic &lt;developer.wordpress.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+817
View File
@@ -0,0 +1,817 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var fs = require('fs')
, stylus = require('../lib/stylus')
, basename = require('path').basename
, dirname = require('path').dirname
, extname = require('path').extname
, resolve = require('path').resolve
, join = require('path').join
, isWindows = process.platform === 'win32';
/**
* Arguments.
*/
var args = process.argv.slice(2);
/**
* Compare flag.
*/
var compare = false;
/**
* Compress flag.
*/
var compress = false;
/**
* CSS conversion flag.
*/
var convertCSS = false;
/**
* Line numbers flag.
*/
var linenos = false;
/**
* CSS class prefix.
*/
var prefix = '';
/**
* Print to stdout flag.
*/
var print = false;
/**
* Firebug flag
*/
var firebug = false;
/**
* Sourcemap flag
*/
var sourcemap = false;
/**
* Files to processes.
*/
var files = [];
/**
* Import paths.
*/
var paths = [];
/**
* Destination directory.
*/
var dest;
/**
* Watcher hash.
*/
var watchers;
/**
* Enable REPL.
*/
var interactive;
/**
* Plugins.
*/
var plugins = [];
/**
* Optional url() function.
*/
var urlFunction = false;
/**
* Include CSS on import.
*/
var includeCSS = false;
/**
* Set file imports.
*/
var imports = [];
/**
* Resolve relative urls
*/
var resolveURL = false;
/**
* Disable cache.
*/
var disableCache = false;
/**
* Display dependencies flag.
*/
var deps = false;
/**
* Hoist at-rules.
*/
var hoist = false;
/**
* Usage docs.
*/
var usage = [
''
, ' Usage: stylus [options] [command] [< in [> out]]'
, ' [file|dir ...]'
, ''
, ' Commands:'
, ''
, ' help [<type>:]<prop> Opens help info at MDN for <prop> in'
, ' your default browser. Optionally'
, ' searches other resources of <type>:'
, ' safari opera w3c ms caniuse quirksmode'
, ''
, ' Options:'
, ''
, ' -i, --interactive Start interactive REPL'
, ' -u, --use <path> Utilize the Stylus plugin at <path>'
, ' -U, --inline Utilize image inlining via data URI support'
, ' -w, --watch Watch file(s) for changes and re-compile'
, ' -o, --out <dir> Output to <dir> when passing files'
, ' -C, --css <src> [dest] Convert CSS input to Stylus'
, ' -I, --include <path> Add <path> to lookup paths'
, ' -c, --compress Compress CSS output'
, ' -d, --compare Display input along with output'
, ' -f, --firebug Emits debug infos in the generated CSS that'
, ' can be used by the FireStylus Firebug plugin'
, ' -l, --line-numbers Emits comments in the generated CSS'
, ' indicating the corresponding Stylus line'
, ' -m, --sourcemap Generates a sourcemap in sourcemaps v3 format'
, ' --sourcemap-inline Inlines sourcemap with full source text in base64 format'
, ' --sourcemap-root <url> "sourceRoot" property of the generated sourcemap'
, ' --sourcemap-base <path> Base <path> from which sourcemap and all sources are relative'
, ' -P, --prefix [prefix] prefix all css classes'
, ' -p, --print Print out the compiled CSS'
, ' --import <file> Import stylus <file>'
, ' --include-css Include regular CSS on @import'
, ' -D, --deps Display dependencies of the compiled file'
, ' --disable-cache Disable caching'
, ' --hoist-atrules Move @import and @charset to the top'
, ' -r, --resolve-url Resolve relative urls inside imports'
, ' --resolve-url-nocheck Like --resolve-url but without file existence check'
, ' -V, --version Display the version of Stylus'
, ' -h, --help Display help information'
, ''
].join('\n');
/**
* Handle arguments.
*/
var arg;
while (args.length) {
arg = args.shift();
switch (arg) {
case '-h':
case '--help':
console.error(usage);
return;
case '-d':
case '--compare':
compare = true;
break;
case '-c':
case '--compress':
compress = true;
break;
case '-C':
case '--css':
convertCSS = true;
break;
case '-f':
case '--firebug':
firebug = true;
break;
case '-l':
case '--line-numbers':
linenos = true;
break;
case '-m':
case '--sourcemap':
sourcemap = {};
break;
case '--sourcemap-inline':
sourcemap = sourcemap || {};
sourcemap.inline = true;
break;
case '--sourcemap-root':
var url = args.shift();
if (!url) throw new Error('--sourcemap-root <url> required');
sourcemap = sourcemap || {};
sourcemap.sourceRoot = url;
break;
case '--sourcemap-base':
var path = args.shift();
if (!path) throw new Error('--sourcemap-base <path> required');
sourcemap = sourcemap || {};
sourcemap.basePath = path;
break;
case '-P':
case '--prefix':
prefix = args.shift();
if (!prefix) throw new Error('--prefix <prefix> required');
break;
case '-p':
case '--print':
print = true;
break;
case '-V':
case '--version':
console.log(stylus.version);
return;
case '-o':
case '--out':
dest = args.shift();
if (!dest) throw new Error('--out <dir> required');
break;
case 'help':
var name = args.shift()
, browser = name.split(':');
if (browser.length > 1) {
name = [].slice.call(browser, 1).join(':');
browser = browser[0];
} else {
name = browser[0];
browser = '';
}
if (!name) throw new Error('help <property> required');
help(name);
break;
case '--include-css':
includeCSS = true;
break;
case '--disable-cache':
disableCache = true;
break;
case '--hoist-atrules':
hoist = true;
break;
case '-i':
case '--repl':
case '--interactive':
interactive = true;
break;
case '-I':
case '--include':
var path = args.shift();
if (!path) throw new Error('--include <path> required');
paths.push(path);
break;
case '-w':
case '--watch':
watchers = {};
break;
case '-U':
case '--inline':
args.unshift('--use', 'url');
break;
case '-u':
case '--use':
var options;
var path = args.shift();
if (!path) throw new Error('--use <path> required');
// options
if ('--with' == args[0]) {
args.shift();
options = args.shift();
if (!options) throw new Error('--with <options> required');
options = eval('(' + options + ')');
}
// url support
if ('url' == path) {
urlFunction = options || {};
} else {
paths.push(dirname(path));
plugins.push({ path: path, options: options });
}
break;
case '--import':
var file = args.shift();
if (!file) throw new Error('--import <file> required');
imports.push(file);
break;
case '-r':
case '--resolve-url':
resolveURL = {};
break;
case '--resolve-url-nocheck':
resolveURL = { nocheck: true };
break;
case '-D':
case '--deps':
deps = true;
break;
default:
files.push(arg);
}
}
// if --watch is used, assume we are
// not working with stdio
if (watchers && !files.length) {
files = fs.readdirSync(process.cwd())
.filter(function(file){
return file.match(/\.styl$/);
});
}
// --sourcemap flag is not working with stdio
if (sourcemap && !files.length) sourcemap = false;
/**
* Open the default browser to the CSS property `name`.
*
* @param {String} name
*/
function help(name) {
var url
, exec = require('child_process').exec
, command;
name = encodeURIComponent(name);
switch (browser) {
case 'safari':
case 'webkit':
url = 'https://developer.apple.com/library/safari/search/?q=' + name;
break;
case 'opera':
url = 'http://dev.opera.com/search/?term=' + name;
break;
case 'w3c':
url = 'http://www.google.com/search?q=site%3Awww.w3.org%2FTR+' + name;
break;
case 'ms':
url = 'http://social.msdn.microsoft.com/search/en-US/ie?query=' + name + '&refinement=59%2c61';
break;
case 'caniuse':
url = 'http://caniuse.com/#search=' + name;
break;
case 'quirksmode':
url = 'http://www.google.com/search?q=site%3Awww.quirksmode.org+' + name;
break;
default:
url = 'https://developer.mozilla.org/en/CSS/' + name;
}
switch (process.platform) {
case 'linux': command = 'x-www-browser'; break;
default: command = 'open';
}
exec(command + ' "' + url + '"', function(){
process.exit(0);
});
}
// Compilation options
if (files.length > 1 && isCSS(dest)) {
dest = dirname(dest);
}
var options = {
filename: 'stdin'
, compress: compress
, firebug: firebug
, linenos: linenos
, sourcemap: sourcemap
, paths: [process.cwd()].concat(paths)
, prefix: prefix
, dest: dest
, 'hoist atrules': hoist
};
// Buffer stdin
var str = '';
// Convert CSS to Stylus
if (convertCSS) {
switch (files.length) {
case 2:
compileCSSFile(files[0], files[1]);
break;
case 1:
var file = files[0];
compileCSSFile(file, join(dirname(file), basename(file, extname(file))) + '.styl');
break;
default:
var stdin = process.openStdin();
stdin.setEncoding('utf8');
stdin.on('data', function(chunk){ str += chunk; });
stdin.on('end', function(){
var out = stylus.convertCSS(str);
console.log(out);
});
}
} else if (interactive) {
repl();
} else if (deps) {
// if --deps is used, just display list of the dependencies
// not working with stdio and dirs
displayDeps();
} else {
if (files.length) {
compileFiles(files);
} else {
compileStdio();
}
}
/**
* Start Stylus REPL.
*/
function repl() {
var options = { cache: false, filename: 'stdin', imports: [join(__dirname, '..', 'lib', 'functions')] }
, parser = new stylus.Parser('', options)
, evaluator = new stylus.Evaluator(parser.parse(), options)
, rl = require('readline')
, repl = rl.createInterface(process.stdin, process.stdout, autocomplete)
, global = evaluator.global.scope;
// expose BIFs
evaluator.evaluate();
// readline
repl.setPrompt('> ');
repl.prompt();
// HACK: flat-list auto-complete
function autocomplete(line){
var out = process.stdout
, keys = Object.keys(global.locals)
, len = keys.length
, words = line.split(/\s+/)
, word = words.pop()
, names = []
, name
, node
, key;
// find words that match
for (var i = 0; i < len; ++i) {
key = keys[i];
if (0 == key.indexOf(word)) {
node = global.lookup(key);
switch (node.nodeName) {
case 'function':
names.push(node.toString());
break;
default:
names.push(key);
}
}
}
return [names, line];
};
repl.on('line', function(line){
if (!line.trim().length) return repl.prompt();
parser = new stylus.Parser(line, options);
parser.state.push('expression');
evaluator.return = true;
try {
var expr = parser.parse();
evaluator.root = expr;
var ret = evaluator.evaluate();
var node;
while (node = ret.nodes.pop()) {
if (!node.suppress) {
var str = node.toString();
if ('(' == str[0]) str = str.replace(/^\(|\)$/g, '');
console.log('\033[90m=> \033[0m' + highlight(str));
break;
}
}
repl.prompt();
} catch (err) {
console.error('\033[31merror: %s\033[0m', err.message || err.stack);
repl.prompt();
}
});
repl.on('SIGINT', function(){
console.log();
process.exit(0);
});
}
/**
* Highlight the given string of Stylus.
*/
function highlight(str) {
return str
.replace(/(#)?(\d+(\.\d+)?)/g, function($0, $1, $2){
return $1 ? $0 : '\033[36m' + $2 + '\033[0m';
})
.replace(/(#[\da-fA-F]+)/g, '\033[33m$1\033[0m')
.replace(/('.*?'|".*?")/g, '\033[32m$1\033[0m');
}
/**
* Convert a CSS file to a Styl file
*/
function compileCSSFile(file, fileOut) {
fs.stat(file, function(err, stat){
if (err) throw err;
if (stat.isFile()) {
fs.readFile(file, 'utf8', function(err, str){
if (err) throw err;
var styl = stylus.convertCSS(str);
fs.writeFile(fileOut, styl, function(err){
if (err) throw err;
});
});
}
});
}
/**
* Compile with stdio.
*/
function compileStdio() {
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(chunk){ str += chunk; });
process.stdin.on('end', function(){
// Compile to css
var style = stylus(str, options);
if (includeCSS) style.set('include css', true);
if (disableCache) style.set('cache', false);
usePlugins(style);
importFiles(style);
style.render(function(err, css){
if (err) throw err;
if (compare) {
console.log('\n\x1b[1mInput:\x1b[0m');
console.log(str);
console.log('\n\x1b[1mOutput:\x1b[0m');
}
console.log(css);
if (compare) console.log();
});
}).resume();
}
/**
* Compile the given files.
*/
function compileFiles(files) {
files.forEach(compileFile);
}
/**
* Display dependencies of the compiled files.
*/
function displayDeps() {
files.forEach(function(file){
// ensure file exists
fs.stat(file, function(err, stat){
if (err) throw err;
fs.readFile(file, 'utf8', function(err, str){
if (err) throw err;
options.filename = file;
var style = stylus(str, options);
usePlugins(style);
importFiles(style);
console.log(style.deps().join('\n'));
});
});
});
}
/**
* Compile the given file.
*/
function compileFile(file) {
// ensure file exists
fs.stat(file, function(err, stat){
if (err) throw err;
// file
if (stat.isFile()) {
fs.readFile(file, 'utf8', function(err, str){
if (err) throw err;
options.filename = file;
options._imports = [];
var style = stylus(str, options);
if (includeCSS) style.set('include css', true);
if (disableCache) style.set('cache', false);
if (sourcemap) style.set('sourcemap', sourcemap);
usePlugins(style);
importFiles(style);
style.render(function(err, css){
watchImports(file, options._imports);
if (err) {
if (watchers) {
console.error(err.stack || err.message);
} else {
throw err;
}
} else {
writeFile(file, css);
// write sourcemap
if (sourcemap && !sourcemap.inline) {
writeSourcemap(file, style.sourcemap);
}
}
});
});
// directory
} else if (stat.isDirectory()) {
fs.readdir(file, function(err, files){
if (err) throw err;
files.filter(function(path){
return path.match(/\.styl$/);
}).map(function(path){
return join(file, path);
}).forEach(compileFile);
});
}
});
}
/**
* Write the given CSS output.
*/
function createPath(file, sourceMap) {
var out;
if (files.length === 1 && isCSS(dest)) {
return [dest, sourceMap ? '.map' : ''].join('');
}
// --out support
out = [basename(file, extname(file)), sourceMap ? '.css.map' : '.css'].join('');
return dest
? join(dest, out)
: join(dirname(file), out);
}
/**
* Check if the given path is a CSS file.
*/
function isCSS(file) {
return file && '.css' === extname(file);
}
function writeFile(file, css) {
// --print support
if (print) return process.stdout.write(css);
var path = createPath(file);
fs.writeFile(path, css, function(err){
if (err) throw err;
console.log(' \033[90mcompiled\033[0m %s', path);
// --watch support
watch(file, file);
});
}
/**
* Write the given sourcemap.
*/
function writeSourcemap(file, sourcemap) {
var path = createPath(file, true);
fs.writeFile(path, JSON.stringify(sourcemap), function(err){
if (err) throw err;
// don't output log message if --print is present
if (!print) console.log(' \033[90mgenerated\033[0m %s', path);
});
}
/**
* Watch the given `file` and recompiling `rootFile` when modified.
*/
function watch(file, rootFile) {
// not watching
if (!watchers) return;
// already watched
if (watchers[file]) {
watchers[file][rootFile] = true;
return;
}
// watch the file itself
watchers[file] = {};
watchers[file][rootFile] = true;
if (print) {
console.error('Stylus CLI Error: Watch and print cannot be used together');
process.exit(1);
}
console.log(' \033[90mwatching\033[0m %s', file);
// if is windows use fs.watch api instead
// TODO: remove watchFile when fs.watch() works on osx etc
if (isWindows) {
fs.watch(file, function(event) {
if (event === 'change') compile();
});
} else {
fs.watchFile(file, { interval: 300 }, function(curr, prev) {
if (curr.mtime > prev.mtime) compile();
});
}
function compile() {
for (var rootFile in watchers[file]) {
compileFile(rootFile);
}
}
}
/**
* Watch `imports`, re-compiling `file` when they change.
*/
function watchImports(file, imports) {
imports.forEach(function(imported){
if (!imported.path) return;
watch(imported.path, file);
});
}
/**
* Utilize plugins.
*/
function usePlugins(style) {
plugins.forEach(function(plugin){
var path = plugin.path;
var options = plugin.options;
fn = require(/^\.+\//.test(path) ? resolve(path) : path);
if ('function' != typeof fn) {
throw new Error('plugin ' + path + ' does not export a function');
}
style.use(fn(options));
});
if (urlFunction) {
style.define('url', stylus.url(urlFunction));
} else if (resolveURL) {
style.define('url', stylus.resolver(resolveURL));
}
}
/**
* Imports the indicated files.
*/
function importFiles(style) {
imports.forEach(function(file) {
style.import(file);
});
}
+4
View File
@@ -0,0 +1,4 @@
module.exports = process.env.STYLUS_COV
? require('./lib-cov/stylus')
: require('./lib/stylus');
+2
View File
@@ -0,0 +1,2 @@
module.exports = require('./stylus');
+80
View File
@@ -0,0 +1,80 @@
/**
* Module dependencies.
*/
var crypto = require('crypto')
, fs = require('fs')
, join = require('path').join
, version = require('../../package').version
, nodes = require('../nodes');
var FSCache = module.exports = function(options) {
options = options || {};
this._location = options['cache location'] || '.styl-cache';
if (!fs.existsSync(this._location)) fs.mkdirSync(this._location);
};
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
FSCache.prototype.set = function(key, value) {
fs.writeFileSync(join(this._location, key), JSON.stringify(value));
};
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
FSCache.prototype.get = function(key) {
var data = fs.readFileSync(join(this._location, key), 'utf-8');
return JSON.parse(data, FSCache.fromJSON);
};
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
FSCache.prototype.has = function(key) {
return fs.existsSync(join(this._location, key));
};
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
FSCache.prototype.key = function(str, options) {
var hash = crypto.createHash('sha1');
hash.update(str + version + options.prefix);
return hash.digest('hex');
};
/**
* JSON to Stylus nodes converter.
*
* @api private
*/
FSCache.fromJSON = function(key, val) {
if (val && val.__type) {
val.__proto__ = nodes[val.__type].prototype;
}
return val;
};
+25
View File
@@ -0,0 +1,25 @@
/**
* Get cache object by `name`.
*
* @param {String|Function} name
* @param {Object} options
* @return {Object}
* @api private
*/
var getCache = module.exports = function(name, options){
if ('function' == typeof name) return new name(options);
var cache;
switch (name){
// case 'fs':
// cache = require('./fs')
// break;
case 'memory':
cache = require('./memory');
break;
default:
cache = require('./null');
}
return new cache(options);
};
+116
View File
@@ -0,0 +1,116 @@
/**
* Module dependencies.
*/
var crypto = require('crypto')
, nodes = require('../nodes');
var MemoryCache = module.exports = function(options) {
options = options || {};
this.limit = options['cache limit'] || 256;
this._cache = {};
this.length = 0;
this.head = this.tail = null;
};
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
MemoryCache.prototype.set = function(key, value) {
var clone = value.clone()
, item;
clone.filename = nodes.filename;
clone.lineno = nodes.lineno;
clone.column = nodes.column;
item = { key: key, value: clone };
this._cache[key] = item;
if (this.tail) {
this.tail.next = item;
item.prev = this.tail;
} else {
this.head = item;
}
this.tail = item;
if (this.length++ == this.limit) this.purge();
};
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
MemoryCache.prototype.get = function(key) {
var item = this._cache[key]
, val = item.value.clone();
if (item == this.tail) return val;
if (item.next) {
if (item == this.head) this.head = item.next;
item.next.prev = item.prev;
}
if (item.prev) item.prev.next = item.next;
item.next = null;
item.prev = this.tail;
if (this.tail) this.tail.next = item;
this.tail = item;
return val;
};
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
MemoryCache.prototype.has = function(key) {
return !!this._cache[key];
};
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
MemoryCache.prototype.key = function(str, options) {
var hash = crypto.createHash('sha1');
hash.update(str + options.prefix);
return hash.digest('hex');
};
/**
* Remove the oldest item from the cache.
*
* @api private
*/
MemoryCache.prototype.purge = function() {
var item = this.head;
if (this.head.next) {
this.head = this.head.next;
this.head.prev = null;
}
this._cache[item.key] = item.prev = item.next = null;
this.length--;
};
+50
View File
@@ -0,0 +1,50 @@
/**
* Module dependencies.
*/
var NullCache = module.exports = function() {};
/**
* Set cache item with given `key` to `value`.
*
* @param {String} key
* @param {Object} value
* @api private
*/
NullCache.prototype.set = function(key, value) {};
/**
* Get cache item with given `key`.
*
* @param {String} key
* @return {Object}
* @api private
*/
NullCache.prototype.get = function(key) {};
/**
* Check if cache has given `key`.
*
* @param {String} key
* @return {Boolean}
* @api private
*/
NullCache.prototype.has = function(key) {
return false;
};
/**
* Generate key for the source `str` with `options`.
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api private
*/
NullCache.prototype.key = function(str, options) {
return '';
};
+158
View File
@@ -0,0 +1,158 @@
/*!
* Stylus - colors
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
module.exports = {
aliceblue: [240, 248, 255, 1]
, antiquewhite: [250, 235, 215, 1]
, aqua: [0, 255, 255, 1]
, aquamarine: [127, 255, 212, 1]
, azure: [240, 255, 255, 1]
, beige: [245, 245, 220, 1]
, bisque: [255, 228, 196, 1]
, black: [0, 0, 0, 1]
, blanchedalmond: [255, 235, 205, 1]
, blue: [0, 0, 255, 1]
, blueviolet: [138, 43, 226, 1]
, brown: [165, 42, 42, 1]
, burlywood: [222, 184, 135, 1]
, cadetblue: [95, 158, 160, 1]
, chartreuse: [127, 255, 0, 1]
, chocolate: [210, 105, 30, 1]
, coral: [255, 127, 80, 1]
, cornflowerblue: [100, 149, 237, 1]
, cornsilk: [255, 248, 220, 1]
, crimson: [220, 20, 60, 1]
, cyan: [0, 255, 255, 1]
, darkblue: [0, 0, 139, 1]
, darkcyan: [0, 139, 139, 1]
, darkgoldenrod: [184, 134, 11, 1]
, darkgray: [169, 169, 169, 1]
, darkgreen: [0, 100, 0, 1]
, darkgrey: [169, 169, 169, 1]
, darkkhaki: [189, 183, 107, 1]
, darkmagenta: [139, 0, 139, 1]
, darkolivegreen: [85, 107, 47, 1]
, darkorange: [255, 140, 0, 1]
, darkorchid: [153, 50, 204, 1]
, darkred: [139, 0, 0, 1]
, darksalmon: [233, 150, 122, 1]
, darkseagreen: [143, 188, 143, 1]
, darkslateblue: [72, 61, 139, 1]
, darkslategray: [47, 79, 79, 1]
, darkslategrey: [47, 79, 79, 1]
, darkturquoise: [0, 206, 209, 1]
, darkviolet: [148, 0, 211, 1]
, deeppink: [255, 20, 147, 1]
, deepskyblue: [0, 191, 255, 1]
, dimgray: [105, 105, 105, 1]
, dimgrey: [105, 105, 105, 1]
, dodgerblue: [30, 144, 255, 1]
, firebrick: [178, 34, 34, 1]
, floralwhite: [255, 250, 240, 1]
, forestgreen: [34, 139, 34, 1]
, fuchsia: [255, 0, 255, 1]
, gainsboro: [220, 220, 220, 1]
, ghostwhite: [248, 248, 255, 1]
, gold: [255, 215, 0, 1]
, goldenrod: [218, 165, 32, 1]
, gray: [128, 128, 128, 1]
, green: [0, 128, 0, 1]
, greenyellow: [173, 255, 47, 1]
, grey: [128, 128, 128, 1]
, honeydew: [240, 255, 240, 1]
, hotpink: [255, 105, 180, 1]
, indianred: [205, 92, 92, 1]
, indigo: [75, 0, 130, 1]
, ivory: [255, 255, 240, 1]
, khaki: [240, 230, 140, 1]
, lavender: [230, 230, 250, 1]
, lavenderblush: [255, 240, 245, 1]
, lawngreen: [124, 252, 0, 1]
, lemonchiffon: [255, 250, 205, 1]
, lightblue: [173, 216, 230, 1]
, lightcoral: [240, 128, 128, 1]
, lightcyan: [224, 255, 255, 1]
, lightgoldenrodyellow: [250, 250, 210, 1]
, lightgray: [211, 211, 211, 1]
, lightgreen: [144, 238, 144, 1]
, lightgrey: [211, 211, 211, 1]
, lightpink: [255, 182, 193, 1]
, lightsalmon: [255, 160, 122, 1]
, lightseagreen: [32, 178, 170, 1]
, lightskyblue: [135, 206, 250, 1]
, lightslategray: [119, 136, 153, 1]
, lightslategrey: [119, 136, 153, 1]
, lightsteelblue: [176, 196, 222, 1]
, lightyellow: [255, 255, 224, 1]
, lime: [0, 255, 0, 1]
, limegreen: [50, 205, 50, 1]
, linen: [250, 240, 230, 1]
, magenta: [255, 0, 255, 1]
, maroon: [128, 0, 0, 1]
, mediumaquamarine: [102, 205, 170, 1]
, mediumblue: [0, 0, 205, 1]
, mediumorchid: [186, 85, 211, 1]
, mediumpurple: [147, 112, 219, 1]
, mediumseagreen: [60, 179, 113, 1]
, mediumslateblue: [123, 104, 238, 1]
, mediumspringgreen: [0, 250, 154, 1]
, mediumturquoise: [72, 209, 204, 1]
, mediumvioletred: [199, 21, 133, 1]
, midnightblue: [25, 25, 112, 1]
, mintcream: [245, 255, 250, 1]
, mistyrose: [255, 228, 225, 1]
, moccasin: [255, 228, 181, 1]
, navajowhite: [255, 222, 173, 1]
, navy: [0, 0, 128, 1]
, oldlace: [253, 245, 230, 1]
, olive: [128, 128, 0, 1]
, olivedrab: [107, 142, 35, 1]
, orange: [255, 165, 0, 1]
, orangered: [255, 69, 0, 1]
, orchid: [218, 112, 214, 1]
, palegoldenrod: [238, 232, 170, 1]
, palegreen: [152, 251, 152, 1]
, paleturquoise: [175, 238, 238, 1]
, palevioletred: [219, 112, 147, 1]
, papayawhip: [255, 239, 213, 1]
, peachpuff: [255, 218, 185, 1]
, peru: [205, 133, 63, 1]
, pink: [255, 192, 203, 1]
, plum: [221, 160, 221, 1]
, powderblue: [176, 224, 230, 1]
, purple: [128, 0, 128, 1]
, red: [255, 0, 0, 1]
, rosybrown: [188, 143, 143, 1]
, royalblue: [65, 105, 225, 1]
, saddlebrown: [139, 69, 19, 1]
, salmon: [250, 128, 114, 1]
, sandybrown: [244, 164, 96, 1]
, seagreen: [46, 139, 87, 1]
, seashell: [255, 245, 238, 1]
, sienna: [160, 82, 45, 1]
, silver: [192, 192, 192, 1]
, skyblue: [135, 206, 235, 1]
, slateblue: [106, 90, 205, 1]
, slategray: [112, 128, 144, 1]
, slategrey: [112, 128, 144, 1]
, snow: [255, 250, 250, 1]
, springgreen: [0, 255, 127, 1]
, steelblue: [70, 130, 180, 1]
, tan: [210, 180, 140, 1]
, teal: [0, 128, 128, 1]
, thistle: [216, 191, 216, 1]
, tomato: [255, 99, 71, 1]
, transparent: [0, 0, 0, 0]
, turquoise: [64, 224, 208, 1]
, violet: [238, 130, 238, 1]
, wheat: [245, 222, 179, 1]
, white: [255, 255, 255, 1]
, whitesmoke: [245, 245, 245, 1]
, yellow: [255, 255, 0, 1]
, yellowgreen: [154, 205, 50, 1]
, rebeccapurple: [102, 51, 153, 1]
};
+307
View File
@@ -0,0 +1,307 @@
/*!
* Stylus - CSS to Stylus conversion
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Convert the given `css` to Stylus source.
*
* @param {String} css
* @return {String}
* @api public
*/
module.exports = function(css){
return new Converter(css).stylus();
};
/**
* Initialize a new `Converter` with the given `css`.
*
* @param {String} css
* @api private
*/
function Converter(css) {
var parse = require('css-parse');
this.css = css;
this.root = parse(css, { position: false });
this.indents = 0;
}
/**
* Convert to Stylus.
*
* @return {String}
* @api private
*/
Converter.prototype.stylus = function(){
return this.visitRules(this.root.stylesheet.rules);
};
/**
* Return indent string.
*
* @return {String}
* @api private
*/
Converter.prototype.__defineGetter__('indent', function(){
return Array(this.indents + 1).join(' ');
});
/**
* Visit `node`.
*
* @param {*} node
* @return {String}
* @api private
*/
Converter.prototype.visit = function(node){
switch (node.type) {
case 'rule':
case 'comment':
case 'charset':
case 'namespace':
case 'media':
case 'import':
case 'document':
case 'keyframes':
case 'page':
case 'host':
case 'supports':
var name = node.type[0].toUpperCase() + node.type.slice(1);
return this['visit' + name](node);
}
};
/**
* Visit the rules on `node`.
*
* @param {Array} node
* @return {String}
* @api private
*/
Converter.prototype.visitRules = function(node){
var buf = '';
for (var i = 0, len = node.length; i < len; ++i) {
buf += this.visit(node[i]);
}
return buf;
};
/**
* Visit Media `node`.
*
* @param {Media} node
* @return {String}
* @api private
*/
Converter.prototype.visitMedia = function(node){
var buf = this.indent + '@media ' + node.media;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
/**
* Visit Declaration `node`.
*
* @param {Declaration} node
* @return {String}
* @api private
*/
Converter.prototype.visitDeclaration = function(node){
if ('comment' == node.type) {
return this.visitComment(node);
} else {
var buf = this.indent + node.property + ': ' + node.value + '\n';
return buf;
}
};
/**
* Visit Rule `node`.`
*
* @param {Rule} node
* @return {String}
* @api private
*/
Converter.prototype.visitRule = function(node){
var buf = this.indent + node.selectors.join(',\n' + this.indent) + '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf + '\n';
};
/**
* Visit Comment `node`.`
*
* @param {Comment} node
* @return {String}
* @api private
*/
Converter.prototype.visitComment = function(node){
var buf = this.indent + '/*' + node.comment + '*/';
return buf + '\n';
};
/**
* Visit Charset `node`.`
*
* @param {Charset} node
* @return {String}
* @api private
*/
Converter.prototype.visitCharset = function(node){
var buf = this.indent + '@charset ' + node.charset;
return buf + '\n';
};
/**
* Visit Namespace `node`.`
*
* @param {Namespace} node
* @return {String}
* @api private
*/
Converter.prototype.visitNamespace = function(node){
var buf = this.indent + '@namespace ' + node.namespace;
return buf + '\n';
};
/**
* Visit Import `node`.`
*
* @param {Import} node
* @return {String}
* @api private
*/
Converter.prototype.visitImport = function(node){
var buf = this.indent + '@import ' + node.import;
return buf + '\n';
};
/**
* Visit Document `node`.`
*
* @param {Document} node
* @return {String}
* @api private
*/
Converter.prototype.visitDocument = function(node){
var buf = this.indent + '@' + node.vendor + 'document ' + node.document;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
/**
* Visit Keyframes `node`.`
*
* @param {Keyframes} node
* @return {String}
* @api private
*/
Converter.prototype.visitKeyframes = function(node){
var buf = this.indent + '@keyframes ' + node.name;
buf += '\n';
++this.indents;
for (var i = 0, len = node.keyframes.length; i < len; ++i) {
buf += this.visitKeyframe(node.keyframes[i]);
}
--this.indents;
return buf;
};
/**
* Visit Keyframe `node`.`
*
* @param {Keyframe} node
* @return {String}
* @api private
*/
Converter.prototype.visitKeyframe = function(node){
var buf = this.indent + node.values.join(', ');
buf += '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf;
};
/**
* Visit Page `node`.`
*
* @param {Page} node
* @return {String}
* @api private
*/
Converter.prototype.visitPage = function(node){
var buf = this.indent + '@page' + (node.selectors.length ? ' ' + node.selectors.join(', ') : '');
buf += '\n';
++this.indents;
for (var i = 0, len = node.declarations.length; i < len; ++i) {
buf += this.visitDeclaration(node.declarations[i]);
}
--this.indents;
return buf;
};
/**
* Visit Supports `node`.`
*
* @param {Supports} node
* @return {String}
* @api private
*/
Converter.prototype.visitSupports = function(node){
var buf = this.indent + '@supports ' + node.supports;
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
/**
* Visit Host `node`.`
*
* @param {Host} node
* @return {String}
* @api private
*/
Converter.prototype.visitHost = function(node){
var buf = this.indent + '@host';
buf += '\n';
++this.indents;
buf += this.visitRules(node.rules);
--this.indents;
return buf;
};
+58
View File
@@ -0,0 +1,58 @@
/*!
* Stylus - errors
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Expose constructors.
*/
exports.ParseError = ParseError;
exports.SyntaxError = SyntaxError;
/**
* Inherit from `Error.prototype`.
*/
SyntaxError.prototype.__proto__ = Error.prototype;
/**
* Initialize a new `ParseError` with the given `msg`.
*
* @param {String} msg
* @api private
*/
function ParseError(msg) {
this.name = 'ParseError';
this.message = msg;
Error.captureStackTrace(this, ParseError);
}
/**
* Inherit from `Error.prototype`.
*/
ParseError.prototype.__proto__ = Error.prototype;
/**
* Initialize a new `SyntaxError` with the given `msg`.
*
* @param {String} msg
* @api private
*/
function SyntaxError(msg) {
this.name = 'SyntaxError';
this.message = msg;
Error.captureStackTrace(this, ParseError);
}
/**
* Inherit from `Error.prototype`.
*/
SyntaxError.prototype.__proto__ = Error.prototype;
+29
View File
@@ -0,0 +1,29 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Add property `name` with the given `expr`
* to the mixin-able block.
*
* @param {String|Ident|Literal} name
* @param {Expression} expr
* @return {Property}
* @api public
*/
(module.exports = function addProperty(name, expr){
utils.assertType(name, 'expression', 'name');
name = utils.unwrap(name).first;
utils.assertString(name, 'name');
utils.assertType(expr, 'expression', 'expr');
var prop = new nodes.Property([name], expr);
var block = this.closestBlock;
var len = block.nodes.length
, head = block.nodes.slice(0, block.index)
, tail = block.nodes.slice(block.index++, len);
head.push(prop);
block.nodes = head.concat(tail);
return prop;
}).raw = true;
+28
View File
@@ -0,0 +1,28 @@
var utils = require('../utils');
/**
* Adjust HSL `color` `prop` by `amount`.
*
* @param {RGBA|HSLA} color
* @param {String} prop
* @param {Unit} amount
* @return {RGBA}
* @api private
*/
module.exports = function adjust(color, prop, amount){
utils.assertColor(color, 'color');
utils.assertString(prop, 'prop');
utils.assertType(amount, 'unit', 'amount');
var hsl = color.hsla.clone();
prop = { hue: 'h', saturation: 's', lightness: 'l' }[prop.string];
if (!prop) throw new Error('invalid adjustment property');
var val = amount.val;
if ('%' == amount.type){
val = 'l' == prop && val > 0
? (100 - hsl[prop]) * val / 100
: hsl[prop] * (val / 100);
}
hsl[prop] += val;
return hsl.rgba;
};
+36
View File
@@ -0,0 +1,36 @@
var nodes = require('../nodes')
, rgba = require('./rgba');
/**
* Return the alpha component of the given `color`,
* or set the alpha component to the optional second `value` argument.
*
* Examples:
*
* alpha(#fff)
* // => 1
*
* alpha(rgba(0,0,0,0.3))
* // => 0.3
*
* alpha(#fff, 0.5)
* // => rgba(255,255,255,0.5)
*
* @param {RGBA|HSLA} color
* @param {Unit} [value]
* @return {Unit|RGBA}
* @api public
*/
module.exports = function alpha(color, value){
color = color.rgba;
if (value) {
return rgba(
new nodes.Unit(color.r),
new nodes.Unit(color.g),
new nodes.Unit(color.b),
value
);
}
return new nodes.Unit(color.a, '');
};
+26
View File
@@ -0,0 +1,26 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Return a `Literal` `num` converted to the provided `base`, padded to `width`
* with zeroes (default width is 2)
*
* @param {Number} num
* @param {Number} base
* @param {Number} width
* @return {Literal}
* @api public
*/
(module.exports = function(num, base, width) {
utils.assertPresent(num, 'number');
utils.assertPresent(base, 'base');
num = utils.unwrap(num).nodes[0].val;
base = utils.unwrap(base).nodes[0].val;
width = (width && utils.unwrap(width).nodes[0].val) || 2;
var result = Number(num).toString(base);
while (result.length < width) {
result = '0' + result;
}
return new nodes.Literal(result);
}).raw = true;
+15
View File
@@ -0,0 +1,15 @@
var utils = require('../utils')
, path = require('path');
/**
* Return the basename of `path`.
*
* @param {String} path
* @return {String}
* @api public
*/
module.exports = function basename(p, ext){
utils.assertString(p, 'path');
return path.basename(p.val, ext && ext.val);
};
+37
View File
@@ -0,0 +1,37 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Blend the `top` color over the `bottom`
*
* Examples:
*
* blend(rgba(#FFF, 0.5), #000)
* // => #808080
*
* blend(rgba(#FFDE00,.42), #19C261)
* // => #7ace38
*
* blend(rgba(lime, 0.5), rgba(red, 0.25))
* // => rgba(128,128,0,0.625)
*
* @param {RGBA|HSLA} top
* @param {RGBA|HSLA} [bottom=#fff]
* @return {RGBA}
* @api public
*/
module.exports = function blend(top, bottom){
// TODO: different blend modes like overlay etc.
utils.assertColor(top);
top = top.rgba;
bottom = bottom || new nodes.RGBA(255, 255, 255, 1);
utils.assertColor(bottom);
bottom = bottom.rgba;
return new nodes.RGBA(
top.r * top.a + bottom.r * (1 - top.a),
top.g * top.a + bottom.g * (1 - top.a),
top.b * top.a + bottom.b * (1 - top.a),
top.a + bottom.a - top.a * bottom.a);
};
+33
View File
@@ -0,0 +1,33 @@
var nodes = require('../nodes')
, rgba = require('./rgba');
/**
* Return the blue component of the given `color`,
* or set the blue component to the optional second `value` argument.
*
* Examples:
*
* blue(#00c)
* // => 204
*
* blue(#000, 255)
* // => #00f
*
* @param {RGBA|HSLA} color
* @param {Unit} [value]
* @return {Unit|RGBA}
* @api public
*/
module.exports = function blue(color, value){
color = color.rgba;
if (value) {
return rgba(
new nodes.Unit(color.r),
new nodes.Unit(color.g),
value,
new nodes.Unit(color.a)
);
}
return new nodes.Unit(color.b, '');
};
+14
View File
@@ -0,0 +1,14 @@
var utils = require('../utils');
/**
* Return a clone of the given `expr`.
*
* @param {Expression} expr
* @return {Node}
* @api public
*/
(module.exports = function clone(expr){
utils.assertPresent(expr, 'expr');
return expr.clone();
}).raw = true;
+60
View File
@@ -0,0 +1,60 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Color component name map.
*/
var componentMap = {
red: 'r'
, green: 'g'
, blue: 'b'
, alpha: 'a'
, hue: 'h'
, saturation: 's'
, lightness: 'l'
};
/**
* Color component unit type map.
*/
var unitMap = {
hue: 'deg'
, saturation: '%'
, lightness: '%'
};
/**
* Color type map.
*/
var typeMap = {
red: 'rgba'
, blue: 'rgba'
, green: 'rgba'
, alpha: 'rgba'
, hue: 'hsla'
, saturation: 'hsla'
, lightness: 'hsla'
};
/**
* Return component `name` for the given `color`.
*
* @param {RGBA|HSLA} color
* @param {String} name
* @return {Unit}
* @api public
*/
module.exports = function component(color, name) {
utils.assertColor(color, 'color');
utils.assertString(name, 'name');
var name = name.string
, unit = unitMap[name]
, type = typeMap[name]
, name = componentMap[name];
if (!name) throw new Error('invalid color component "' + name + '"');
return new nodes.Unit(color[type][name], unit);
};
+75
View File
@@ -0,0 +1,75 @@
var utils = require('../utils')
, nodes = require('../nodes')
, blend = require('./blend')
, luminosity = require('./luminosity');
/**
* Returns the contrast ratio object between `top` and `bottom` colors,
* based on http://leaverou.github.io/contrast-ratio/
* and https://github.com/LeaVerou/contrast-ratio/blob/gh-pages/color.js#L108
*
* Examples:
*
* contrast(#000, #fff).ratio
* => 21
*
* contrast(#000, rgba(#FFF, 0.5))
* => { "ratio": "13.15;", "error": "7.85", "min": "5.3", "max": "21" }
*
* @param {RGBA|HSLA} top
* @param {RGBA|HSLA} [bottom=#fff]
* @return {Object}
* @api public
*/
module.exports = function contrast(top, bottom){
if ('rgba' != top.nodeName && 'hsla' != top.nodeName) {
return new nodes.Literal('contrast(' + (top.isNull ? '' : top.toString()) + ')');
}
var result = new nodes.Object();
top = top.rgba;
bottom = bottom || new nodes.RGBA(255, 255, 255, 1);
utils.assertColor(bottom);
bottom = bottom.rgba;
function contrast(top, bottom) {
if (1 > top.a) {
top = blend(top, bottom);
}
var l1 = luminosity(bottom).val + 0.05
, l2 = luminosity(top).val + 0.05
, ratio = l1 / l2;
if (l2 > l1) {
ratio = 1 / ratio;
}
return Math.round(ratio * 10) / 10;
}
if (1 <= bottom.a) {
var resultRatio = new nodes.Unit(contrast(top, bottom));
result.set('ratio', resultRatio);
result.set('error', new nodes.Unit(0));
result.set('min', resultRatio);
result.set('max', resultRatio);
} else {
var onBlack = contrast(top, blend(bottom, new nodes.RGBA(0, 0, 0, 1)))
, onWhite = contrast(top, blend(bottom, new nodes.RGBA(255, 255, 255, 1)))
, max = Math.max(onBlack, onWhite);
function processChannel(topChannel, bottomChannel) {
return Math.min(Math.max(0, (topChannel - bottomChannel * bottom.a) / (1 - bottom.a)), 255);
}
var closest = new nodes.RGBA(
processChannel(top.r, bottom.r),
processChannel(top.g, bottom.g),
processChannel(top.b, bottom.b),
1
);
var min = contrast(top, blend(bottom, closest));
result.set('ratio', new nodes.Unit(Math.round((min + max) * 50) / 100));
result.set('error', new nodes.Unit(Math.round((max - min) * 50) / 100));
result.set('min', new nodes.Unit(min));
result.set('max', new nodes.Unit(max));
}
return result;
}
+15
View File
@@ -0,0 +1,15 @@
var utils = require('../utils');
/**
* Like `unquote` but tries to convert
* the given `str` to a Stylus node.
*
* @param {String} str
* @return {Node}
* @api public
*/
module.exports = function convert(str){
utils.assertString(str, 'str');
return utils.parseString(str.string);
};
+22
View File
@@ -0,0 +1,22 @@
var nodes = require('../nodes');
/**
* Returns the @media string for the current block
*
* @return {String}
* @api public
*/
module.exports = function currentMedia(){
var self = this;
return new nodes.String(lookForMedia(this.closestBlock.node) || '');
function lookForMedia(node){
if ('media' == node.nodeName) {
node.val = self.visit(node.val);
return node.toString();
} else if (node.block.parent.node) {
return lookForMedia(node.block.parent.node);
}
}
};
+23
View File
@@ -0,0 +1,23 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Set a variable `name` on current scope.
*
* @param {String} name
* @param {Expression} expr
* @param {Boolean} [global]
* @api public
*/
module.exports = function define(name, expr, global){
utils.assertType(name, 'string', 'name');
expr = utils.unwrap(expr);
var scope = this.currentScope;
if (global && global.toBoolean().isTrue) {
scope = this.global.scope;
}
var node = new nodes.Ident(name.val, expr);
scope.add(node);
return nodes.null;
};
+15
View File
@@ -0,0 +1,15 @@
var utils = require('../utils')
, path = require('path');
/**
* Return the dirname of `path`.
*
* @param {String} path
* @return {String}
* @api public
*/
module.exports = function dirname(p){
utils.assertString(p, 'path');
return path.dirname(p.val).replace(/\\/g, '/');
};
+15
View File
@@ -0,0 +1,15 @@
var utils = require('../utils');
/**
* Throw an error with the given `msg`.
*
* @param {String} msg
* @api public
*/
module.exports = function error(msg){
utils.assertType(msg, 'string', 'msg');
var err = new Error(msg.val);
err.fromStylus = true;
throw err;
};
+15
View File
@@ -0,0 +1,15 @@
var utils = require('../utils')
, path = require('path');
/**
* Return the extname of `path`.
*
* @param {String} path
* @return {String}
* @api public
*/
module.exports = function extname(p){
utils.assertString(p, 'path');
return path.extname(p.val);
};
+33
View File
@@ -0,0 +1,33 @@
var nodes = require('../nodes')
, rgba = require('./rgba');
/**
* Return the green component of the given `color`,
* or set the green component to the optional second `value` argument.
*
* Examples:
*
* green(#0c0)
* // => 204
*
* green(#000, 255)
* // => #0f0
*
* @param {RGBA|HSLA} color
* @param {Unit} [value]
* @return {Unit|RGBA}
* @api public
*/
module.exports = function green(color, value){
color = color.rgba;
if (value) {
return rgba(
new nodes.Unit(color.r),
value,
new nodes.Unit(color.b),
new nodes.Unit(color.a)
);
}
return new nodes.Unit(color.g, '');
};
+35
View File
@@ -0,0 +1,35 @@
var utils = require('../utils')
, nodes = require('../nodes')
, hsla = require('./hsla');
/**
* Convert the given `color` to an `HSLA` node,
* or h,s,l component values.
*
* Examples:
*
* hsl(10, 50, 30)
* // => HSLA
*
* hsl(#ffcc00)
* // => HSLA
*
* @param {Unit|HSLA|RGBA} hue
* @param {Unit} saturation
* @param {Unit} lightness
* @return {HSLA}
* @api public
*/
module.exports = function hsl(hue, saturation, lightness){
if (1 == arguments.length) {
utils.assertColor(hue, 'color');
return hue.hsla;
} else {
return hsla(
hue
, saturation
, lightness
, new nodes.Unit(1));
}
};
+53
View File
@@ -0,0 +1,53 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Convert the given `color` to an `HSLA` node,
* or h,s,l,a component values.
*
* Examples:
*
* hsla(10deg, 50%, 30%, 0.5)
* // => HSLA
*
* hsla(#ffcc00)
* // => HSLA
*
* @param {RGBA|HSLA|Unit} hue
* @param {Unit} saturation
* @param {Unit} lightness
* @param {Unit} alpha
* @return {HSLA}
* @api public
*/
module.exports = function hsla(hue, saturation, lightness, alpha){
switch (arguments.length) {
case 1:
utils.assertColor(hue);
return hue.hsla;
case 2:
utils.assertColor(hue);
var color = hue.hsla;
utils.assertType(saturation, 'unit', 'alpha');
var alpha = saturation.clone();
if ('%' == alpha.type) alpha.val /= 100;
return new nodes.HSLA(
color.h
, color.s
, color.l
, alpha.val);
default:
utils.assertType(hue, 'unit', 'hue');
utils.assertType(saturation, 'unit', 'saturation');
utils.assertType(lightness, 'unit', 'lightness');
utils.assertType(alpha, 'unit', 'alpha');
var alpha = alpha.clone();
if (alpha && '%' == alpha.type) alpha.val /= 100;
return new nodes.HSLA(
hue.val
, saturation.val
, lightness.val
, alpha.val);
}
};
+34
View File
@@ -0,0 +1,34 @@
var nodes = require('../nodes')
, hsla = require('./hsla')
, component = require('./component');
/**
* Return the hue component of the given `color`,
* or set the hue component to the optional second `value` argument.
*
* Examples:
*
* hue(#00c)
* // => 240deg
*
* hue(#00c, 90deg)
* // => #6c0
*
* @param {RGBA|HSLA} color
* @param {Unit} [value]
* @return {Unit|RGBA}
* @api public
*/
module.exports = function hue(color, value){
if (value) {
var hslaColor = color.hsla;
return hsla(
value,
new nodes.Unit(hslaColor.s),
new nodes.Unit(hslaColor.l),
new nodes.Unit(hslaColor.a)
)
}
return component(color, new nodes.String('hue'));
};
+58
View File
@@ -0,0 +1,58 @@
var utils = require('../utils')
, nodes = require('../nodes')
, Image = require('./image');
/**
* Return the width and height of the given `img` path.
*
* Examples:
*
* image-size('foo.png')
* // => 200px 100px
*
* image-size('foo.png')[0]
* // => 200px
*
* image-size('foo.png')[1]
* // => 100px
*
* Can be used to test if the image exists,
* using an optional argument set to `true`
* (without this argument this function throws error
* if there is no such image).
*
* Example:
*
* image-size('nosuchimage.png', true)[0]
* // => 0
*
* @param {String} img
* @param {Boolean} ignoreErr
* @return {Expression}
* @api public
*/
module.exports = function imageSize(img, ignoreErr) {
utils.assertType(img, 'string', 'img');
try {
var img = new Image(this, img.string);
} catch (err) {
if (ignoreErr) {
return [new nodes.Unit(0), new nodes.Unit(0)];
} else {
throw err;
}
}
// Read size
img.open();
var size = img.size();
img.close();
// Return (w h)
var expr = [];
expr.push(new nodes.Unit(size[0], 'px'));
expr.push(new nodes.Unit(size[1], 'px'));
return expr;
};
+162
View File
@@ -0,0 +1,162 @@
/*!
* Stylus - plugin - url
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, nodes = require('../nodes')
, fs = require('fs')
, path = require('path')
, sax = require('sax');
/**
* Initialize a new `Image` with the given `ctx` and `path.
*
* @param {Evaluator} ctx
* @param {String} path
* @api private
*/
var Image = module.exports = function Image(ctx, path) {
this.ctx = ctx;
this.path = utils.lookup(path, ctx.paths);
if (!this.path) throw new Error('failed to locate file ' + path);
};
/**
* Open the image for reading.
*
* @api private
*/
Image.prototype.open = function(){
this.fd = fs.openSync(this.path, 'r');
this.length = fs.fstatSync(this.fd).size;
this.extname = path.extname(this.path).slice(1);
};
/**
* Close the file.
*
* @api private
*/
Image.prototype.close = function(){
if (this.fd) fs.closeSync(this.fd);
};
/**
* Return the type of image, supports:
*
* - gif
* - png
* - jpeg
* - svg
*
* @return {String}
* @api private
*/
Image.prototype.type = function(){
var type
, buf = new Buffer(4);
fs.readSync(this.fd, buf, 0, 4, 0);
// GIF
if (0x47 == buf[0] && 0x49 == buf[1] && 0x46 == buf[2]) type = 'gif';
// PNG
else if (0x50 == buf[1] && 0x4E == buf[2] && 0x47 == buf[3]) type = 'png';
// JPEG
else if (0xff == buf[0] && 0xd8 == buf[1]) type = 'jpeg';
// SVG
else if ('svg' == this.extname) type = this.extname;
return type;
};
/**
* Return image dimensions `[width, height]`.
*
* @return {Array}
* @api private
*/
Image.prototype.size = function(){
var type = this.type()
, width
, height
, buf
, offset
, blockSize
, parser;
function uint16(b) { return b[1] << 8 | b[0]; }
function uint32(b) { return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; }
// Determine dimensions
switch (type) {
case 'jpeg':
buf = new Buffer(this.length);
fs.readSync(this.fd, buf, 0, this.length, 0);
offset = 4;
blockSize = buf[offset] << 8 | buf[offset + 1];
while (offset < this.length) {
offset += blockSize;
if (offset >= this.length || 0xff != buf[offset]) break;
// SOF0 or SOF2 (progressive)
if (0xc0 == buf[offset + 1] || 0xc2 == buf[offset + 1]) {
height = buf[offset + 5] << 8 | buf[offset + 6];
width = buf[offset + 7] << 8 | buf[offset + 8];
} else {
offset += 2;
blockSize = buf[offset] << 8 | buf[offset + 1];
}
}
break;
case 'png':
buf = new Buffer(8);
// IHDR chunk width / height uint32_t big-endian
fs.readSync(this.fd, buf, 0, 8, 16);
width = uint32(buf);
height = uint32(buf.slice(4, 8));
break;
case 'gif':
buf = new Buffer(4);
// width / height uint16_t little-endian
fs.readSync(this.fd, buf, 0, 4, 6);
width = uint16(buf);
height = uint16(buf.slice(2, 4));
break;
case 'svg':
offset = Math.min(this.length, 1024);
buf = new Buffer(offset);
fs.readSync(this.fd, buf, 0, offset, 0);
buf = buf.toString('utf8');
parser = sax.parser(true);
parser.onopentag = function(node) {
if ('svg' == node.name && node.attributes.width && node.attributes.height) {
width = parseInt(node.attributes.width, 10);
height = parseInt(node.attributes.height, 10);
}
};
parser.write(buf).close();
break;
}
if ('number' != typeof width) throw new Error('failed to find width of "' + this.path + '"');
if ('number' != typeof height) throw new Error('failed to find height of "' + this.path + '"');
return [width, height];
};
+69
View File
@@ -0,0 +1,69 @@
/*!
* Stylus - Evaluator - built-in functions
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
exports['add-property'] = require('./add-property');
exports.adjust = require('./adjust');
exports.alpha = require('./alpha');
exports['base-convert'] = require('./base-convert');
exports.basename = require('./basename');
exports.blend = require('./blend');
exports.blue = require('./blue');
exports.clone = require('./clone');
exports.component = require('./component');
exports.contrast = require('./contrast');
exports.convert = require('./convert');
exports['current-media'] = require('./current-media');
exports.define = require('./define');
exports.dirname = require('./dirname');
exports.error = require('./error');
exports.extname = require('./extname');
exports.green = require('./green');
exports.hsl = require('./hsl');
exports.hsla = require('./hsla');
exports.hue = require('./hue');
exports['image-size'] = require('./image-size');
exports.json = require('./json');
exports.length = require('./length');
exports.lightness = require('./lightness');
exports['list-separator'] = require('./list-separator');
exports.lookup = require('./lookup');
exports.luminosity = require('./luminosity');
exports.match = require('./match');
exports.math = require('./math');
exports.merge = exports.extend = require('./merge');
exports.operate = require('./operate');
exports['opposite-position'] = require('./opposite-position');
exports.p = require('./p');
exports.pathjoin = require('./pathjoin');
exports.pop = require('./pop');
exports.push = exports.append = require('./push');
exports.range = require('./range');
exports.red = require('./red');
exports.remove = require('./remove');
exports.replace = require('./replace');
exports.rgb = require('./rgb');
exports.rgba = require('./rgba');
exports.s = require('./s');
exports.saturation = require('./saturation');
exports['selector-exists'] = require('./selector-exists');
exports.selector = require('./selector');
exports.selectors = require('./selectors');
exports.shift = require('./shift');
exports.split = require('./split');
exports.substr = require('./substr');
exports.slice = require('./slice');
exports.tan = require('./tan');
exports.trace = require('./trace');
exports.transparentify = require('./transparentify');
exports.type = exports.typeof = exports['type-of'] = require('./type');
exports.unit = require('./unit');
exports.unquote = require('./unquote');
exports.unshift = exports.prepend = require('./unshift');
exports.use = require('./use');
exports.warn = require('./warn');
exports['-math-prop'] = require('./math-prop');
exports['-prefix-classes'] = require('./prefix-classes');
+297
View File
@@ -0,0 +1,297 @@
called-from = ()
vendors = moz webkit o ms official
// stringify the given arg
-string(arg)
type(arg) + ' ' + arg
// require a color
require-color(color)
unless color is a 'color'
error('RGB or HSL value expected, got a ' + -string(color))
// require a unit
require-unit(n)
unless n is a 'unit'
error('unit expected, got a ' + -string(n))
// require a string
require-string(str)
unless str is a 'string' or str is a 'ident'
error('string expected, got a ' + -string(str))
// Math functions
abs(n) { math(n, 'abs') }
min(a, b) { a < b ? a : b }
max(a, b) { a > b ? a : b }
// Trigonometrics
PI = -math-prop('PI')
radians-to-degrees(angle)
angle * (180 / PI)
degrees-to-radians(angle)
unit(angle * (PI / 180),'')
sin(n)
n = degrees-to-radians(n) if unit(n) == 'deg'
round(math(n, 'sin'), 9)
cos(n)
n = degrees-to-radians(n) if unit(n) == 'deg'
round(math(n, 'cos'), 9)
// Rounding Math functions
ceil(n, precision = 0)
multiplier = 10 ** precision
math(n * multiplier, 'ceil') / multiplier
floor(n, precision = 0)
multiplier = 10 ** precision
math(n * multiplier, 'floor') / multiplier
round(n, precision = 0)
multiplier = 10 ** precision
math(n * multiplier, 'round') / multiplier
// return the sum of the given numbers
sum(nums)
sum = 0
sum += n for n in nums
// return the average of the given numbers
avg(nums)
sum(nums) / length(nums)
// return a unitless number, or pass through
remove-unit(n)
if typeof(n) is "unit"
unit(n, "")
else
n
// convert a percent to a decimal, or pass through
percent-to-decimal(n)
if unit(n) is "%"
remove-unit(n) / 100
else
n
// check if n is an odd number
odd(n)
1 == n % 2
// check if n is an even number
even(n)
0 == n % 2
// check if color is light
light(color)
lightness(color) >= 50%
// check if color is dark
dark(color)
lightness(color) < 50%
// desaturate color by amount
desaturate(color, amount)
adjust(color, 'saturation', - amount)
// saturate color by amount
saturate(color = '', amount = 100%)
if color is a 'color'
adjust(color, 'saturation', amount)
else
unquote( "saturate(" + color + ")" )
// darken by the given amount
darken(color, amount)
adjust(color, 'lightness', - amount)
// lighten by the given amount
lighten(color, amount)
adjust(color, 'lightness', amount)
// decrease opacity by amount
fade-out(color, amount)
color - rgba(black, percent-to-decimal(amount))
// increase opacity by amount
fade-in(color, amount)
color + rgba(black, percent-to-decimal(amount))
// spin hue by a given amount
spin(color, amount)
color + unit(amount, deg)
// mix two colors by a given amount
mix(color1, color2, weight = 50%)
unless weight in 0..100
error("Weight must be between 0% and 100%")
if length(color1) == 2
weight = color1[0]
color1 = color1[1]
else if length(color2) == 2
weight = 100 - color2[0]
color2 = color2[1]
require-color(color1)
require-color(color2)
p = unit(weight / 100, '')
w = p * 2 - 1
a = alpha(color1) - alpha(color2)
w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2
w2 = 1 - w1
channels = (red(color1) red(color2)) (green(color1) green(color2)) (blue(color1) blue(color2))
rgb = ()
for pair in channels
push(rgb, floor(pair[0] * w1 + pair[1] * w2))
a1 = alpha(color1) * p
a2 = alpha(color2) * (1 - p)
alpha = a1 + a2
rgba(rgb[0], rgb[1], rgb[2], alpha)
// invert colors, leave alpha intact
invert(color = '')
if color is a 'color'
rgba(#fff - color, alpha(color))
else
unquote( "invert(" + color + ")" )
// give complement of the given color
complement( color )
spin( color, 180 )
// give grayscale of the given color
grayscale( color = '' )
if color is a 'color'
desaturate( color, 100% )
else
unquote( "grayscale(" + color + ")" )
// mix the given color with white
tint( color, percent )
mix( white, color, percent )
// mix the given color with black
shade( color, percent )
mix( black, color, percent )
// return the last value in the given expr
last(expr)
expr[length(expr) - 1]
// return keys in the given pairs or object
keys(pairs)
ret = ()
if type(pairs) == 'object'
for key in pairs
push(ret, key)
else
for pair in pairs
push(ret, pair[0]);
ret
// return values in the given pairs or object
values(pairs)
ret = ()
if type(pairs) == 'object'
for key, val in pairs
push(ret, val)
else
for pair in pairs
push(ret, pair[1]);
ret
// join values with the given delimiter
join(delim, vals...)
buf = ''
vals = vals[0] if length(vals) == 1
for val, i in vals
buf += i ? delim + val : val
// add a CSS rule to the containing block
// - This definition allows add-property to be used as a mixin
// - It has the same effect as interpolation but allows users
// to opt for a functional style
add-property-function = add-property
add-property(name, expr)
if mixin
{name} expr
else
add-property-function(name, expr)
prefix-classes(prefix)
-prefix-classes(prefix, block)
// Caching mixin, use inside your functions to enable caching by extending.
$stylus_mixin_cache = {}
cache()
$key = (current-media() or 'no-media') + '__' + called-from[0] + '__' + arguments
if $key in $stylus_mixin_cache
@extend {"$cache_placeholder_for_" + $stylus_mixin_cache[$key]}
else if 'cache' in called-from
{block}
else
$id = length($stylus_mixin_cache)
&,
/$cache_placeholder_for_{$id}
$stylus_mixin_cache[$key] = $id
{block}
// Percentage function to convert a number, e.g. ".45", into a percentage, e.g. "45%"
percentage(num)
return unit(num * 100, '%')
// Returns the position of a `value` within a `list`
index(list, value)
for val, i in list
return i if val == value
+116
View File
@@ -0,0 +1,116 @@
var utils = require('../utils')
, nodes = require('../nodes')
, readFile = require('fs').readFileSync;
/**
* Convert a .json file into stylus variables or object.
* Nested variable object keys are joined with a dash (-)
*
* Given this sample media-queries.json file:
* {
* "small": "screen and (max-width:400px)",
* "tablet": {
* "landscape": "screen and (min-width:600px) and (orientation:landscape)",
* "portrait": "screen and (min-width:600px) and (orientation:portrait)"
* }
* }
*
* Examples:
*
* json('media-queries.json')
*
* @media small
* // => @media screen and (max-width:400px)
*
* @media tablet-landscape
* // => @media screen and (min-width:600px) and (orientation:landscape)
*
* vars = json('vars.json', { hash: true })
* body
* width: vars.width
*
* @param {String} path
* @param {Boolean} [local]
* @param {String} [namePrefix]
* @api public
*/
module.exports = function(path, local, namePrefix){
utils.assertString(path, 'path');
// lookup
path = path.string;
var found = utils.lookup(path, this.options.paths, this.options.filename)
, options = (local && 'object' == local.nodeName) && local;
if (!found) {
// optional JSON file
if (options && options.get('optional').toBoolean().isTrue) {
return nodes.null;
}
throw new Error('failed to locate .json file ' + path);
}
// read
var json = JSON.parse(readFile(found, 'utf8'));
if (options) {
return convert(json, options);
} else {
oldJson.call(this, json, local, namePrefix);
}
function convert(obj, options){
var ret = new nodes.Object()
, leaveStrings = options.get('leave-strings').toBoolean();
for (var key in obj) {
var val = obj[key];
if ('object' == typeof val) {
ret.set(key, convert(val, options));
} else {
val = utils.coerce(val);
if ('string' == val.nodeName && leaveStrings.isFalse) {
val = utils.parseString(val.string);
}
ret.set(key, val);
}
}
return ret;
}
};
/**
* Old `json` BIF.
*
* @api private
*/
function oldJson(json, local, namePrefix){
if (namePrefix) {
utils.assertString(namePrefix, 'namePrefix');
namePrefix = namePrefix.val;
} else {
namePrefix = '';
}
local = local ? local.toBoolean() : new nodes.Boolean(local);
var scope = local.isTrue ? this.currentScope : this.global.scope;
convert(json);
return;
function convert(obj, prefix){
prefix = prefix ? prefix + '-' : '';
for (var key in obj){
var val = obj[key];
var name = prefix + key;
if ('object' == typeof val) {
convert(val, name);
} else {
val = utils.coerce(val);
if ('string' == val.nodeName) val = utils.parseString(val.string);
scope.add({ name: namePrefix + name, val: val });
}
}
}
};
+25
View File
@@ -0,0 +1,25 @@
var utils = require('../utils');
/**
* Return length of the given `expr`.
*
* @param {Expression} expr
* @return {Unit}
* @api public
*/
(module.exports = function length(expr){
if (expr) {
if (expr.nodes) {
var nodes = utils.unwrap(expr).nodes;
if (1 == nodes.length && 'object' == nodes[0].nodeName) {
return nodes[0].length;
} else {
return nodes.length;
}
} else {
return 1;
}
}
return 0;
}).raw = true;
+34
View File
@@ -0,0 +1,34 @@
var nodes = require('../nodes')
, hsla = require('./hsla')
, component = require('./component');
/**
* Return the lightness component of the given `color`,
* or set the lightness component to the optional second `value` argument.
*
* Examples:
*
* lightness(#00c)
* // => 100%
*
* lightness(#00c, 80%)
* // => #99f
*
* @param {RGBA|HSLA} color
* @param {Unit} [value]
* @return {Unit|RGBA}
* @api public
*/
module.exports = function lightness(color, value){
if (value) {
var hslaColor = color.hsla;
return hsla(
new nodes.Unit(hslaColor.h),
new nodes.Unit(hslaColor.s),
value,
new nodes.Unit(hslaColor.a)
)
}
return component(color, new nodes.String('lightness'));
};
+25
View File
@@ -0,0 +1,25 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Return the separator of the given `list`.
*
* Examples:
*
* list1 = a b c
* list-separator(list1)
* // => ' '
*
* list2 = a, b, c
* list-separator(list2)
* // => ','
*
* @param {Experssion} list
* @return {String}
* @api public
*/
(module.exports = function listSeparator(list){
list = utils.unwrap(list);
return new nodes.String(list.isList ? ',' : ' ');
}).raw = true;
+17
View File
@@ -0,0 +1,17 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Lookup variable `name` or return Null.
*
* @param {String} name
* @return {Mixed}
* @api public
*/
module.exports = function lookup(name){
utils.assertType(name, 'string', 'name');
var node = this.lookup(name.val);
if (!node) return nodes.null;
return this.visit(node);
};
+38
View File
@@ -0,0 +1,38 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Returns the relative luminance of the given `color`,
* see http://www.w3.org/TR/WCAG20/#relativeluminancedef
*
* Examples:
*
* luminosity(white)
* // => 1
*
* luminosity(#000)
* // => 0
*
* luminosity(red)
* // => 0.2126
*
* @param {RGBA|HSLA} color
* @return {Unit}
* @api public
*/
module.exports = function luminosity(color){
utils.assertColor(color);
color = color.rgba;
function processChannel(channel) {
channel = channel / 255;
return (0.03928 > channel)
? channel / 12.92
: Math.pow(((channel + 0.055) / 1.055), 2.4);
}
return new nodes.Unit(
0.2126 * processChannel(color.r)
+ 0.7152 * processChannel(color.g)
+ 0.0722 * processChannel(color.b)
);
};
+43
View File
@@ -0,0 +1,43 @@
var utils = require('../utils')
, nodes = require('../nodes');
var VALID_FLAGS = 'igm';
/**
* retrieves the matches when matching a `val`(string)
* against a `pattern`(regular expression).
*
* Examples:
* $regex = '^(height|width)?([<>=]{1,})(.*)'
*
* match($regex,'height>=sm')
* // => ('height>=sm' 'height' '>=' 'sm')
* // => also truthy
*
* match($regex, 'lorem ipsum')
* // => null
*
* @param {String} pattern
* @param {String|Ident} val
* @param {String|Ident} [flags='']
* @return {String|Null}
* @api public
*/
module.exports = function match(pattern, val, flags){
utils.assertType(pattern, 'string', 'pattern');
utils.assertString(val, 'val');
var re = new RegExp(pattern.val, validateFlags(flags) ? flags.string : '');
return val.string.match(re);
};
function validateFlags(flags) {
flags = flags && flags.string;
if (flags) {
return flags.split('').every(function(flag) {
return ~VALID_FLAGS.indexOf(flag);
});
}
return false;
}
+13
View File
@@ -0,0 +1,13 @@
var nodes = require('../nodes');
/**
* Get Math `prop`.
*
* @param {String} prop
* @return {Unit}
* @api private
*/
module.exports = function math(prop){
return new nodes.Unit(Math[prop.string]);
};
+17
View File
@@ -0,0 +1,17 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Apply Math `fn` to `n`.
*
* @param {Unit} n
* @param {String} fn
* @return {Unit}
* @api private
*/
module.exports = function math(n, fn){
utils.assertType(n, 'unit', 'n');
utils.assertString(fn, 'fn');
return new nodes.Unit(Math[fn.string](n.val), n.type);
};
+24
View File
@@ -0,0 +1,24 @@
var utils = require('../utils');
/**
* Merge the object `dest` with the given args.
*
* @param {Object} dest
* @param {Object} ...
* @return {Object} dest
* @api public
*/
(module.exports = function merge(dest){
utils.assertPresent(dest, 'dest');
dest = utils.unwrap(dest).first;
utils.assertType(dest, 'object', 'dest');
var last = utils.unwrap(arguments[arguments.length - 1]).first
, deep = (true === last.val);
for (var i = 1, len = arguments.length - deep; i < len; ++i) {
utils.merge(dest.vals, utils.unwrap(arguments[i]).first.vals, deep);
}
return dest;
}).raw = true;
+18
View File
@@ -0,0 +1,18 @@
var utils = require('../utils');
/**
* Perform `op` on the `left` and `right` operands.
*
* @param {String} op
* @param {Node} left
* @param {Node} right
* @return {Node}
* @api public
*/
module.exports = function operate(op, left, right){
utils.assertType(op, 'string', 'op');
utils.assertPresent(left, 'left');
utils.assertPresent(right, 'right');
return left.operate(op.val, right);
};
+32
View File
@@ -0,0 +1,32 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Return the opposites of the given `positions`.
*
* Examples:
*
* opposite-position(top left)
* // => bottom right
*
* @param {Expression} positions
* @return {Expression}
* @api public
*/
(module.exports = function oppositePosition(positions){
var expr = [];
utils.unwrap(positions).nodes.forEach(function(pos, i){
utils.assertString(pos, 'position ' + i);
pos = (function(){ switch (pos.string) {
case 'top': return 'bottom';
case 'bottom': return 'top';
case 'left': return 'right';
case 'right': return 'left';
case 'center': return 'center';
default: throw new Error('invalid position ' + pos);
}})();
expr.push(new nodes.Literal(pos));
});
return expr;
}).raw = true;
+18
View File
@@ -0,0 +1,18 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Inspect the given `expr`.
*
* @param {Expression} expr
* @api public
*/
(module.exports = function p(){
[].slice.call(arguments).forEach(function(expr){
expr = utils.unwrap(expr);
if (!expr.nodes.length) return;
console.log('\u001b[90minspect:\u001b[0m %s', expr.toString().replace(/^\(|\)$/g, ''));
})
return nodes.null;
}).raw = true;
+16
View File
@@ -0,0 +1,16 @@
var path = require('path');
/**
* Peform a path join.
*
* @param {String} path
* @return {String}
* @api public
*/
(module.exports = function pathjoin(){
var paths = [].slice.call(arguments).map(function(path){
return path.first.string;
});
return path.join.apply(null, paths).replace(/\\/g, '/');
}).raw = true;
+14
View File
@@ -0,0 +1,14 @@
var utils = require('../utils');
/**
* Pop a value from `expr`.
*
* @param {Expression} expr
* @return {Node}
* @api public
*/
(module.exports = function pop(expr) {
expr = utils.unwrap(expr);
return expr.nodes.pop();
}).raw = true;
+22
View File
@@ -0,0 +1,22 @@
var utils = require('../utils');
/**
* Prefix css classes in a block
*
* @param {String} prefix
* @param {Block} block
* @return {Block}
* @api private
*/
module.exports = function prefixClasses(prefix, block){
utils.assertString(prefix, 'prefix');
utils.assertType(block, 'block', 'block');
var _prefix = this.prefix;
this.options.prefix = this.prefix = prefix.string;
block = this.visit(block);
this.options.prefix = this.prefix = _prefix;
return block;
};
+18
View File
@@ -0,0 +1,18 @@
var utils = require('../utils');
/**
* Push the given args to `expr`.
*
* @param {Expression} expr
* @param {Node} ...
* @return {Unit}
* @api public
*/
(module.exports = function(expr){
expr = utils.unwrap(expr);
for (var i = 1, len = arguments.length; i < len; ++i) {
expr.nodes.push(utils.unwrap(arguments[i]).clone());
}
return expr.nodes.length;
}).raw = true;
+32
View File
@@ -0,0 +1,32 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Returns a list of units from `start` to `stop`
* by `step`. If `step` argument is omitted,
* it defaults to 1.
*
* @param {Unit} start
* @param {Unit} stop
* @param {Unit} [step]
* @return {Expression}
* @api public
*/
module.exports = function range(start, stop, step){
utils.assertType(start, 'unit', 'start');
utils.assertType(stop, 'unit', 'stop');
if (step) {
utils.assertType(step, 'unit', 'step');
if (0 == step.val) {
throw new Error('ArgumentError: "step" argument must not be zero');
}
} else {
step = new nodes.Unit(1);
}
var list = new nodes.Expression;
for (var i = start.val; i <= stop.val; i += step.val) {
list.push(new nodes.Unit(i, start.type));
}
return list;
};
+33
View File
@@ -0,0 +1,33 @@
var nodes = require('../nodes')
, rgba = require('./rgba');
/**
* Return the red component of the given `color`,
* or set the red component to the optional second `value` argument.
*
* Examples:
*
* red(#c00)
* // => 204
*
* red(#000, 255)
* // => #f00
*
* @param {RGBA|HSLA} color
* @param {Unit} [value]
* @return {Unit|RGBA}
* @api public
*/
module.exports = function red(color, value){
color = color.rgba;
if (value) {
return rgba(
value,
new nodes.Unit(color.g),
new nodes.Unit(color.b),
new nodes.Unit(color.a)
);
}
return new nodes.Unit(color.r, '');
};
+17
View File
@@ -0,0 +1,17 @@
var utils = require('../utils');
/**
* Remove the given `key` from the `object`.
*
* @param {Object} object
* @param {String} key
* @return {Object}
* @api public
*/
module.exports = function remove(object, key){
utils.assertType(object, 'object', 'object');
utils.assertString(key, 'key');
delete object.vals[key.string];
return object;
};
+23
View File
@@ -0,0 +1,23 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Returns string with all matches of `pattern` replaced by `replacement` in given `val`
*
* @param {String} pattern
* @param {String} replacement
* @param {String|Ident} val
* @return {String|Ident}
* @api public
*/
module.exports = function replace(pattern, replacement, val){
utils.assertString(pattern, 'pattern');
utils.assertString(replacement, 'replacement');
utils.assertString(val, 'val');
pattern = new RegExp(pattern.string, 'g');
var res = val.string.replace(pattern, replacement.string);
return val instanceof nodes.Ident
? new nodes.Ident(res)
: new nodes.String(res);
};
+85
View File
@@ -0,0 +1,85 @@
/**
* Module dependencies.
*/
var Compiler = require('../visitor/compiler')
, nodes = require('../nodes')
, parse = require('url').parse
, relative = require('path').relative
, join = require('path').join
, dirname = require('path').dirname
, extname = require('path').extname
, sep = require('path').sep;
/**
* Return a url() function which resolves urls.
*
* Options:
*
* - `paths` resolution path(s), merged with general lookup paths
* - `nocheck` don't check file existence
*
* Examples:
*
* stylus(str)
* .set('filename', __dirname + '/css/test.styl')
* .define('url', stylus.resolver({ nocheck: true }))
* .render(function(err, css){ ... })
*
* @param {Object} [options]
* @return {Function}
* @api public
*/
module.exports = function(options) {
options = options || {};
function resolver(url) {
// Compile the url
var compiler = new Compiler(url)
, filename = url.filename;
compiler.isURL = true;
url = parse(url.nodes.map(function(node){
return compiler.visit(node);
}).join(''));
// Parse literal
var literal = new nodes.Literal('url("' + url.href + '")')
, path = url.pathname
, dest = this.options.dest
, tail = ''
, res;
// Absolute or hash
if (url.protocol || !path || '/' == path[0]) return literal;
// Check that file exists
if (!options.nocheck) {
var _paths = options.paths || [];
path = require('../utils').lookup(path, _paths.concat(this.paths));
if (!path) return literal;
}
if (this.includeCSS && extname(path) == '.css')
return new nodes.Literal(url.href);
if (url.search) tail += url.search;
if (url.hash) tail += url.hash;
if (dest && extname(dest) == '.css')
dest = dirname(dest);
res = relative(dest || dirname(this.filename), options.nocheck
? join(dirname(filename), path)
: path) + tail;
if ('\\' == sep) res = res.replace(/\\/g, '/');
return new nodes.Literal('url("' + res + '")');
};
// Expose options to Evaluator
resolver.options = options;
resolver.raw = true;
return resolver;
};
+40
View File
@@ -0,0 +1,40 @@
var utils = require('../utils')
, nodes = require('../nodes')
, rgba = require('./rgba');
/**
* Return a `RGBA` from the r,g,b channels.
*
* Examples:
*
* rgb(255,204,0)
* // => #ffcc00
*
* rgb(#fff)
* // => #fff
*
* @param {Unit|RGBA|HSLA} red
* @param {Unit} green
* @param {Unit} blue
* @return {RGBA}
* @api public
*/
module.exports = function rgb(red, green, blue){
switch (arguments.length) {
case 1:
utils.assertColor(red);
var color = red.rgba;
return new nodes.RGBA(
color.r
, color.g
, color.b
, 1);
default:
return rgba(
red
, green
, blue
, new nodes.Unit(1));
}
};
+59
View File
@@ -0,0 +1,59 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Return a `RGBA` from the r,g,b,a channels.
*
* Examples:
*
* rgba(255,0,0,0.5)
* // => rgba(255,0,0,0.5)
*
* rgba(255,0,0,1)
* // => #ff0000
*
* rgba(#ffcc00, 50%)
* // rgba(255,204,0,0.5)
*
* @param {Unit|RGBA|HSLA} red
* @param {Unit} green
* @param {Unit} blue
* @param {Unit} alpha
* @return {RGBA}
* @api public
*/
module.exports = function rgba(red, green, blue, alpha){
switch (arguments.length) {
case 1:
utils.assertColor(red);
return red.rgba;
case 2:
utils.assertColor(red);
var color = red.rgba;
utils.assertType(green, 'unit', 'alpha');
alpha = green.clone();
if ('%' == alpha.type) alpha.val /= 100;
return new nodes.RGBA(
color.r
, color.g
, color.b
, alpha.val);
default:
utils.assertType(red, 'unit', 'red');
utils.assertType(green, 'unit', 'green');
utils.assertType(blue, 'unit', 'blue');
utils.assertType(alpha, 'unit', 'alpha');
var r = '%' == red.type ? Math.round(red.val * 2.55) : red.val
, g = '%' == green.type ? Math.round(green.val * 2.55) : green.val
, b = '%' == blue.type ? Math.round(blue.val * 2.55) : blue.val;
alpha = alpha.clone();
if (alpha && '%' == alpha.type) alpha.val /= 100;
return new nodes.RGBA(
r
, g
, b
, alpha.val);
}
};
+37
View File
@@ -0,0 +1,37 @@
var utils = require('../utils')
, nodes = require('../nodes')
, Compiler = require('../visitor/compiler');
/**
* Return a `Literal` with the given `fmt`, and
* variable number of arguments.
*
* @param {String} fmt
* @param {Node} ...
* @return {Literal}
* @api public
*/
(module.exports = function s(fmt){
fmt = utils.unwrap(fmt).nodes[0];
utils.assertString(fmt);
var self = this
, str = fmt.string
, args = arguments
, i = 1;
// format
str = str.replace(/%(s|d)/g, function(_, specifier){
var arg = args[i++] || nodes.null;
switch (specifier) {
case 's':
return new Compiler(arg, self.options).compile();
case 'd':
arg = utils.unwrap(arg).first;
if ('unit' != arg.nodeName) throw new Error('%d requires a unit');
return arg.val;
}
});
return new nodes.Literal(str);
}).raw = true;
+35
View File
@@ -0,0 +1,35 @@
var nodes = require('../nodes')
, hsla = require('./hsla')
, component = require('./component');
/**
* Return the saturation component of the given `color`,
* or set the saturation component to the optional second `value` argument.
*
* Examples:
*
* saturation(#00c)
* // => 100%
*
* saturation(#00c, 50%)
* // => #339
*
* @param {RGBA|HSLA} color
* @param {Unit} [value]
* @return {Unit|RGBA}
* @api public
*/
module.exports = function saturation(color, value){
if (value) {
var hslaColor = color.hsla;
return hsla(
new nodes.Unit(hslaColor.h),
value,
new nodes.Unit(hslaColor.l),
new nodes.Unit(hslaColor.a)
)
}
return component(color, new nodes.String('saturation'));
};
+23
View File
@@ -0,0 +1,23 @@
var utils = require('../utils');
/**
* Returns true if the given selector exists.
*
* @param {String} sel
* @return {Boolean}
* @api public
*/
module.exports = function selectorExists(sel) {
utils.assertString(sel, 'selector');
if (!this.__selectorsMap__) {
var Normalizer = require('../visitor/normalizer')
, visitor = new Normalizer(this.root.clone());
visitor.visit(visitor.root);
this.__selectorsMap__ = visitor.map;
}
return sel.string in this.__selectorsMap__;
};
+71
View File
@@ -0,0 +1,71 @@
var utils = require('../utils');
/**
* Return the current selector or compile
* selector from a string or a list.
*
* @param {String|Expression}
* @return {String}
* @api public
*/
(module.exports = function selector(){
var stack = this.selectorStack
, args = [].slice.call(arguments);
if (1 == args.length) {
var expr = utils.unwrap(args[0])
, len = expr.nodes.length;
// selector('.a')
if (1 == len) {
utils.assertString(expr.first, 'selector');
var SelectorParser = require('../selector-parser')
, val = expr.first.string
, parsed = new SelectorParser(val).parse().val;
if (parsed == val) return val;
stack.push(parse(val));
} else if (len > 1) {
// selector-list = '.a', '.b', '.c'
// selector(selector-list)
if (expr.isList) {
pushToStack(expr.nodes, stack);
// selector('.a' '.b' '.c')
} else {
stack.push(parse(expr.nodes.map(function(node){
utils.assertString(node, 'selector');
return node.string;
}).join(' ')));
}
}
// selector('.a', '.b', '.c')
} else if (args.length > 1) {
pushToStack(args, stack);
}
return stack.length ? utils.compileSelectors(stack).join(',') : '&';
}).raw = true;
function pushToStack(selectors, stack) {
selectors.forEach(function(sel) {
sel = sel.first;
utils.assertString(sel, 'selector');
stack.push(parse(sel.string));
});
}
function parse(selector) {
var Parser = new require('../parser')
, parser = new Parser(selector)
, nodes;
parser.state.push('selector-parts');
nodes = parser.selector();
nodes.forEach(function(node) {
node.val = node.segments.map(function(seg){
return seg.toString();
}).join('');
});
return nodes;
}
+43
View File
@@ -0,0 +1,43 @@
var nodes = require('../nodes')
, Parser = require('../selector-parser');
/**
* Return a list with raw selectors parts
* of the current group.
*
* For example:
*
* .a, .b
* .c
* .d
* test: selectors() // => '.a,.b', '& .c', '& .d'
*
* @return {Expression}
* @api public
*/
module.exports = function selectors(){
var stack = this.selectorStack
, expr = new nodes.Expression(true);
if (stack.length) {
for (var i = 0; i < stack.length; i++) {
var group = stack[i]
, nested;
if (group.length > 1) {
expr.push(new nodes.String(group.map(function(selector) {
nested = new Parser(selector.val).parse().nested;
return (nested && i ? '& ' : '') + selector.val;
}).join(',')))
} else {
var selector = group[0].val
nested = new Parser(selector).parse().nested;
expr.push(new nodes.String((nested && i ? '& ' : '') + selector));
}
}
} else {
expr.push(new nodes.String('&'));
}
return expr;
};
+15
View File
@@ -0,0 +1,15 @@
var utils = require('../utils');
/**
* Shift an element from `expr`.
*
* @param {Expression} expr
* @return {Node}
* @api public
*/
(module.exports = function(expr){
expr = utils.unwrap(expr);
return expr.nodes.shift();
}).raw = true;
+28
View File
@@ -0,0 +1,28 @@
var utils = require('../utils'),
nodes = require('../nodes');
/**
* This is a heler function for the slice method
*
* @param {String|Ident} vals
* @param {Unit} start [0]
* @param {Unit} end [vals.length]
* @return {String|Literal|Null}
* @api public
*/
(module.exports = function slice(val, start, end) {
start = start && start.nodes[0].val;
end = end && end.nodes[0].val;
val = utils.unwrap(val).nodes;
if (val.length > 1) {
return utils.coerce(val.slice(start, end), true);
}
var result = val[0].string.slice(start, end);
return val[0] instanceof nodes.Ident
? new nodes.Ident(result)
: new nodes.String(result);
}).raw = true;
+25
View File
@@ -0,0 +1,25 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Splits the given `val` by `delim`
*
* @param {String} delim
* @param {String|Ident} val
* @return {Expression}
* @api public
*/
module.exports = function split(delim, val){
utils.assertString(delim, 'delimiter');
utils.assertString(val, 'val');
var splitted = val.string.split(delim.string);
var expr = new nodes.Expression();
var ItemNode = val instanceof nodes.Ident
? nodes.Ident
: nodes.String;
for (var i = 0, len = splitted.length; i < len; ++i) {
expr.nodes.push(new ItemNode(splitted[i]));
}
return expr;
};
+22
View File
@@ -0,0 +1,22 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Returns substring of the given `val`.
*
* @param {String|Ident} val
* @param {Number} start
* @param {Number} [length]
* @return {String|Ident}
* @api public
*/
module.exports = function substr(val, start, length){
utils.assertString(val, 'val');
utils.assertType(start, 'unit', 'start');
length = length && length.val;
var res = val.string.substr(start.val, length);
return val instanceof nodes.Ident
? new nodes.Ident(res)
: new nodes.String(res);
};
+28
View File
@@ -0,0 +1,28 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Return the tangent of the given `angle`.
*
* @param {Unit} angle
* @return {Unit}
* @api public
*/
module.exports = function tan(angle) {
utils.assertType(angle, 'unit', 'angle');
var radians = angle.val;
if (angle.type === 'deg') {
radians *= Math.PI / 180;
}
var m = Math.pow(10, 9);
var sin = Math.round(Math.sin(radians) * m) / m
, cos = Math.round(Math.cos(radians) * m) / m
, tan = Math.round(m * sin / cos ) / m;
return new nodes.Unit(tan, '');
};
+12
View File
@@ -0,0 +1,12 @@
var nodes = require('../nodes');
/**
* Output stack trace.
*
* @api public
*/
module.exports = function trace(){
console.log(this.stack);
return nodes.null;
};
+63
View File
@@ -0,0 +1,63 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Returns the transparent version of the given `top` color,
* as if it was blend over the given `bottom` color.
*
* Examples:
*
* transparentify(#808080)
* => rgba(0,0,0,0.5)
*
* transparentify(#414141, #000)
* => rgba(255,255,255,0.25)
*
* transparentify(#91974C, #F34949, 0.5)
* => rgba(47,229,79,0.5)
*
* @param {RGBA|HSLA} top
* @param {RGBA|HSLA} [bottom=#fff]
* @param {Unit} [alpha]
* @return {RGBA}
* @api public
*/
module.exports = function transparentify(top, bottom, alpha){
utils.assertColor(top);
top = top.rgba;
// Handle default arguments
bottom = bottom || new nodes.RGBA(255, 255, 255, 1);
if (!alpha && bottom && !bottom.rgba) {
alpha = bottom;
bottom = new nodes.RGBA(255, 255, 255, 1);
}
utils.assertColor(bottom);
bottom = bottom.rgba;
var bestAlpha = ['r', 'g', 'b'].map(function(channel){
return (top[channel] - bottom[channel]) / ((0 < (top[channel] - bottom[channel]) ? 255 : 0) - bottom[channel]);
}).sort(function(a, b){return a < b;})[0];
if (alpha) {
utils.assertType(alpha, 'unit', 'alpha');
if ('%' == alpha.type) {
bestAlpha = alpha.val / 100;
} else if (!alpha.type) {
bestAlpha = alpha = alpha.val;
}
}
bestAlpha = Math.max(Math.min(bestAlpha, 1), 0);
// Calculate the resulting color
function processChannel(channel) {
if (0 == bestAlpha) {
return bottom[channel]
} else {
return bottom[channel] + (top[channel] - bottom[channel]) / bestAlpha
}
}
return new nodes.RGBA(
processChannel('r'),
processChannel('g'),
processChannel('b'),
Math.round(bestAlpha * 100) / 100
);
}
+30
View File
@@ -0,0 +1,30 @@
var utils = require('../utils');
/**
* Return type of `node`.
*
* Examples:
*
* type(12)
* // => 'unit'
*
* type(#fff)
* // => 'color'
*
* type(type)
* // => 'function'
*
* type(unbound)
* typeof(unbound)
* type-of(unbound)
* // => 'ident'
*
* @param {Node} node
* @return {String}
* @api public
*/
module.exports = function type(node){
utils.assertPresent(node, 'expression');
return node.nodeName;
};
+23
View File
@@ -0,0 +1,23 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Assign `type` to the given `unit` or return `unit`'s type.
*
* @param {Unit} unit
* @param {String|Ident} type
* @return {Unit}
* @api public
*/
module.exports = function unit(unit, type){
utils.assertType(unit, 'unit', 'unit');
// Assign
if (type) {
utils.assertString(type, 'type');
return new nodes.Unit(unit.val, type.string);
} else {
return unit.type || '';
}
};
+23
View File
@@ -0,0 +1,23 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Unquote the given `string`.
*
* Examples:
*
* unquote("sans-serif")
* // => sans-serif
*
* unquote(sans-serif)
* // => sans-serif
*
* @param {String|Ident} string
* @return {Literal}
* @api public
*/
module.exports = function unquote(string){
utils.assertString(string, 'string');
return new nodes.Literal(string.string);
};
+18
View File
@@ -0,0 +1,18 @@
var utils = require('../utils');
/**
* Unshift the given args to `expr`.
*
* @param {Expression} expr
* @param {Node} ...
* @return {Unit}
* @api public
*/
(module.exports = function(expr){
expr = utils.unwrap(expr);
for (var i = 1, len = arguments.length; i < len; ++i) {
expr.nodes.unshift(utils.unwrap(arguments[i]));
}
return expr.nodes.length;
}).raw = true;
+142
View File
@@ -0,0 +1,142 @@
/*!
* Stylus - plugin - url
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Compiler = require('../visitor/compiler')
, events = require('../renderer').events
, nodes = require('../nodes')
, parse = require('url').parse
, extname = require('path').extname
, utils = require('../utils')
, fs = require('fs');
/**
* Mime table.
*/
var defaultMimes = {
'.gif': 'image/gif'
, '.png': 'image/png'
, '.jpg': 'image/jpeg'
, '.jpeg': 'image/jpeg'
, '.svg': 'image/svg+xml'
, '.webp': 'image/webp'
, '.ttf': 'application/x-font-ttf'
, '.eot': 'application/vnd.ms-fontobject'
, '.woff': 'application/font-woff'
, '.woff2': 'application/font-woff2'
};
/**
* Supported encoding types
*/
var encodingTypes = {
BASE_64: 'base64',
UTF8: 'charset=utf-8'
}
/**
* Return a url() function with the given `options`.
*
* Options:
*
* - `limit` bytesize limit defaulting to 30Kb
* - `paths` image resolution path(s), merged with general lookup paths
*
* Examples:
*
* stylus(str)
* .set('filename', __dirname + '/css/test.styl')
* .define('url', stylus.url({ paths: [__dirname + '/public'] }))
* .render(function(err, css){ ... })
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function(options) {
options = options || {};
var _paths = options.paths || [];
var sizeLimit = null != options.limit ? options.limit : 30000;
var mimes = options.mimes || defaultMimes;
/**
* @param {object} url - The path to the image you want to encode.
* @param {object} enc - The encoding for the image. Defaults to base64, the
* other valid option is `utf8`.
*/
function fn(url, enc){
// Compile the url
var compiler = new Compiler(url)
, encoding = encodingTypes.BASE_64;
compiler.isURL = true;
url = url.nodes.map(function(node){
return compiler.visit(node);
}).join('');
// Parse literal
url = parse(url);
var ext = extname(url.pathname)
, mime = mimes[ext]
, hash = url.hash || ''
, literal = new nodes.Literal('url("' + url.href + '")')
, paths = _paths.concat(this.paths)
, buf
, result;
// Not supported
if (!mime) return literal;
// Absolute
if (url.protocol) return literal;
// Lookup
var found = utils.lookup(url.pathname, paths);
// Failed to lookup
if (!found) {
events.emit(
'file not found'
, 'File ' + literal + ' could not be found, literal url retained!'
);
return literal;
}
// Read data
buf = fs.readFileSync(found);
// Too large
if (false !== sizeLimit && buf.length > sizeLimit) return literal;
if (enc && 'utf8' == enc.first.val.toLowerCase()) {
encoding = encodingTypes.UTF8;
result = buf.toString('utf8').replace(/\s+/g, ' ')
.replace(/[{}\|\\\^~\[\]`"<>#%]/g, function(match) {
return '%' + match[0].charCodeAt(0).toString(16).toUpperCase();
}).trim();
} else {
result = buf.toString(encoding) + hash;
}
// Encode
return new nodes.Literal('url("data:' + mime + ';' + encoding + ',' + result + '")');
};
fn.raw = true;
return fn;
};
// Exporting default mimes so we could easily access them
module.exports.mimes = defaultMimes;
+74
View File
@@ -0,0 +1,74 @@
var utils = require('../utils')
, path = require('path');
/**
* Use the given `plugin`
*
* Examples:
*
* use("plugins/add.js")
*
* width add(10, 100)
* // => width: 110
*/
module.exports = function use(plugin, options){
utils.assertString(plugin, 'plugin');
if (options) {
utils.assertType(options, 'object', 'options');
options = parseObject(options);
}
// lookup
plugin = plugin.string;
var found = utils.lookup(plugin, this.options.paths, this.options.filename);
if (!found) throw new Error('failed to locate plugin file "' + plugin + '"');
// use
var fn = require(path.resolve(found));
if ('function' != typeof fn) {
throw new Error('plugin "' + plugin + '" does not export a function');
}
this.renderer.use(fn(options || this.options));
};
/**
* Attempt to parse object node to the javascript object.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
function parseObject(obj){
obj = obj.vals;
for (var key in obj) {
var nodes = obj[key].nodes[0].nodes;
if (nodes && nodes.length) {
obj[key] = [];
for (var i = 0, len = nodes.length; i < len; ++i) {
obj[key].push(convert(nodes[i]));
}
} else {
obj[key] = convert(obj[key].first);
}
}
return obj;
function convert(node){
switch (node.nodeName) {
case 'object':
return parseObject(node);
case 'boolean':
return node.isTrue;
case 'unit':
return node.type ? node.toString() : +node.val;
case 'string':
case 'literal':
return node.val;
default:
return node.toString();
}
}
}
+15
View File
@@ -0,0 +1,15 @@
var utils = require('../utils')
, nodes = require('../nodes');
/**
* Warn with the given `msg` prefixed by "Warning: ".
*
* @param {String} msg
* @api public
*/
module.exports = function warn(msg){
utils.assertType(msg, 'string', 'msg');
console.warn('Warning: %s', msg.val);
return nodes.null;
};
+882
View File
@@ -0,0 +1,882 @@
/*!
* Stylus - Lexer
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Token = require('./token')
, nodes = require('./nodes')
, errors = require('./errors');
/**
* Expose `Lexer`.
*/
exports = module.exports = Lexer;
/**
* Operator aliases.
*/
var alias = {
'and': '&&'
, 'or': '||'
, 'is': '=='
, 'isnt': '!='
, 'is not': '!='
, ':=': '?='
};
/**
* Initialize a new `Lexer` with the given `str` and `options`.
*
* @param {String} str
* @param {Object} options
* @api private
*/
function Lexer(str, options) {
options = options || {};
this.stash = [];
this.indentStack = [];
this.indentRe = null;
this.lineno = 1;
this.column = 1;
// HACK!
function comment(str, val, offset, s) {
var inComment = s.lastIndexOf('/*', offset) > s.lastIndexOf('*/', offset)
, commentIdx = s.lastIndexOf('//', offset)
, i = s.lastIndexOf('\n', offset)
, double = 0
, single = 0;
if (~commentIdx && commentIdx > i) {
while (i != offset) {
if ("'" == s[i]) single ? single-- : single++;
if ('"' == s[i]) double ? double-- : double++;
if ('/' == s[i] && '/' == s[i + 1]) {
inComment = !single && !double;
break;
}
++i;
}
}
return inComment
? str
: val + '\r';
};
// Remove UTF-8 BOM.
if ('\uFEFF' == str.charAt(0)) str = str.slice(1);
this.str = str
.replace(/\s+$/, '\n')
.replace(/\r\n?/g, '\n')
.replace(/\\ *\n/g, '\r')
.replace(/([,(:](?!\/\/[^ ])) *(?:\/\/[^\n]*|\/\*.*?\*\/)?\n\s*/g, comment)
.replace(/\s*\n[ \t]*([,)])/g, comment);
};
/**
* Lexer prototype.
*/
Lexer.prototype = {
/**
* Custom inspect.
*/
inspect: function(){
var tok
, tmp = this.str
, buf = [];
while ('eos' != (tok = this.next()).type) {
buf.push(tok.inspect());
}
this.str = tmp;
return buf.concat(tok.inspect()).join('\n');
},
/**
* Lookahead `n` tokens.
*
* @param {Number} n
* @return {Object}
* @api private
*/
lookahead: function(n){
var fetch = n - this.stash.length;
while (fetch-- > 0) this.stash.push(this.advance());
return this.stash[--n];
},
/**
* Consume the given `len`.
*
* @param {Number|Array} len
* @api private
*/
skip: function(len){
var chunk = len[0];
len = chunk ? chunk.length : len;
this.str = this.str.substr(len);
if (chunk) {
this.move(chunk);
} else {
this.column += len;
}
},
/**
* Move current line and column position.
*
* @param {String} str
* @api private
*/
move: function(str){
var lines = str.match(/\n/g)
, idx = str.lastIndexOf('\n');
if (lines) this.lineno += lines.length;
this.column = ~idx
? str.length - idx
: this.column + str.length;
},
/**
* Fetch next token including those stashed by peek.
*
* @return {Token}
* @api private
*/
next: function() {
var tok = this.stashed() || this.advance();
this.prev = tok;
return tok;
},
/**
* Check if the current token is a part of selector.
*
* @return {Boolean}
* @api private
*/
isPartOfSelector: function() {
var tok = this.stash[this.stash.length - 1] || this.prev;
switch (tok && tok.type) {
// #for
case 'color':
return 2 == tok.val.raw.length;
// .or
case '.':
// [is]
case '[':
return true;
}
return false;
},
/**
* Fetch next token.
*
* @return {Token}
* @api private
*/
advance: function() {
var column = this.column
, line = this.lineno
, tok = this.eos()
|| this.null()
|| this.sep()
|| this.keyword()
|| this.urlchars()
|| this.comment()
|| this.newline()
|| this.escaped()
|| this.important()
|| this.literal()
|| this.anonFunc()
|| this.atrule()
|| this.function()
|| this.brace()
|| this.paren()
|| this.color()
|| this.string()
|| this.unit()
|| this.namedop()
|| this.boolean()
|| this.unicode()
|| this.ident()
|| this.op()
|| this.eol()
|| this.space()
|| this.selector();
tok.lineno = line;
tok.column = column;
return tok;
},
/**
* Lookahead a single token.
*
* @return {Token}
* @api private
*/
peek: function() {
return this.lookahead(1);
},
/**
* Return the next possibly stashed token.
*
* @return {Token}
* @api private
*/
stashed: function() {
return this.stash.shift();
},
/**
* EOS | trailing outdents.
*/
eos: function() {
if (this.str.length) return;
if (this.indentStack.length) {
this.indentStack.shift();
return new Token('outdent');
} else {
return new Token('eos');
}
},
/**
* url char
*/
urlchars: function() {
var captures;
if (!this.isURL) return;
if (captures = /^[\/:@.;?&=*!,<>#%0-9]+/.exec(this.str)) {
this.skip(captures);
return new Token('literal', new nodes.Literal(captures[0]));
}
},
/**
* ';' [ \t]*
*/
sep: function() {
var captures;
if (captures = /^;[ \t]*/.exec(this.str)) {
this.skip(captures);
return new Token(';');
}
},
/**
* '\r'
*/
eol: function() {
if ('\r' == this.str[0]) {
++this.lineno;
this.skip(1);
return this.advance();
}
},
/**
* ' '+
*/
space: function() {
var captures;
if (captures = /^([ \t]+)/.exec(this.str)) {
this.skip(captures);
return new Token('space');
}
},
/**
* '\\' . ' '*
*/
escaped: function() {
var captures;
if (captures = /^\\(.)[ \t]*/.exec(this.str)) {
var c = captures[1];
this.skip(captures);
return new Token('ident', new nodes.Literal(c));
}
},
/**
* '@css' ' '* '{' .* '}' ' '*
*/
literal: function() {
// HACK attack !!!
var captures;
if (captures = /^@css[ \t]*\{/.exec(this.str)) {
this.skip(captures);
var c
, braces = 1
, css = ''
, node;
while (c = this.str[0]) {
this.str = this.str.substr(1);
switch (c) {
case '{': ++braces; break;
case '}': --braces; break;
case '\n':
case '\r':
++this.lineno;
break;
}
css += c;
if (!braces) break;
}
css = css.replace(/\s*}$/, '');
node = new nodes.Literal(css);
node.css = true;
return new Token('literal', node);
}
},
/**
* '!important' ' '*
*/
important: function() {
var captures;
if (captures = /^!important[ \t]*/.exec(this.str)) {
this.skip(captures);
return new Token('ident', new nodes.Literal('!important'));
}
},
/**
* '{' | '}'
*/
brace: function() {
var captures;
if (captures = /^([{}])/.exec(this.str)) {
this.skip(1);
var brace = captures[1];
return new Token(brace, brace);
}
},
/**
* '(' | ')' ' '*
*/
paren: function() {
var captures;
if (captures = /^([()])([ \t]*)/.exec(this.str)) {
var paren = captures[1];
this.skip(captures);
if (')' == paren) this.isURL = false;
var tok = new Token(paren, paren);
tok.space = captures[2];
return tok;
}
},
/**
* 'null'
*/
null: function() {
var captures
, tok;
if (captures = /^(null)\b[ \t]*/.exec(this.str)) {
this.skip(captures);
if (this.isPartOfSelector()) {
tok = new Token('ident', new nodes.Ident(captures[0]));
} else {
tok = new Token('null', nodes.null);
}
return tok;
}
},
/**
* 'if'
* | 'else'
* | 'unless'
* | 'return'
* | 'for'
* | 'in'
*/
keyword: function() {
var captures
, tok;
if (captures = /^(return|if|else|unless|for|in)\b[ \t]*/.exec(this.str)) {
var keyword = captures[1];
this.skip(captures);
if (this.isPartOfSelector()) {
tok = new Token('ident', new nodes.Ident(captures[0]));
} else {
tok = new Token(keyword, keyword);
}
return tok;
}
},
/**
* 'not'
* | 'and'
* | 'or'
* | 'is'
* | 'is not'
* | 'isnt'
* | 'is a'
* | 'is defined'
*/
namedop: function() {
var captures
, tok;
if (captures = /^(not|and|or|is a|is defined|isnt|is not|is)(?!-)\b([ \t]*)/.exec(this.str)) {
var op = captures[1];
this.skip(captures);
if (this.isPartOfSelector()) {
tok = new Token('ident', new nodes.Ident(captures[0]));
} else {
op = alias[op] || op;
tok = new Token(op, op);
}
tok.space = captures[2];
return tok;
}
},
/**
* ','
* | '+'
* | '+='
* | '-'
* | '-='
* | '*'
* | '*='
* | '/'
* | '/='
* | '%'
* | '%='
* | '**'
* | '!'
* | '&'
* | '&&'
* | '||'
* | '>'
* | '>='
* | '<'
* | '<='
* | '='
* | '=='
* | '!='
* | '!'
* | '~'
* | '?='
* | ':='
* | '?'
* | ':'
* | '['
* | ']'
* | '.'
* | '..'
* | '...'
*/
op: function() {
var captures;
if (captures = /^([.]{1,3}|&&|\|\||[!<>=?:]=|\*\*|[-+*\/%]=?|[,=?:!~<>&\[\]])([ \t]*)/.exec(this.str)) {
var op = captures[1];
this.skip(captures);
op = alias[op] || op;
var tok = new Token(op, op);
tok.space = captures[2];
this.isURL = false;
return tok;
}
},
/**
* '@('
*/
anonFunc: function() {
var tok;
if ('@' == this.str[0] && '(' == this.str[1]) {
this.skip(2);
tok = new Token('function', new nodes.Ident('anonymous'));
tok.anonymous = true;
return tok;
}
},
/**
* '@' (-(\w+)-)?[a-zA-Z0-9-_]+
*/
atrule: function() {
var captures;
if (captures = /^@(?:-(\w+)-)?([a-zA-Z0-9-_]+)[ \t]*/.exec(this.str)) {
this.skip(captures);
var vendor = captures[1]
, type = captures[2]
, tok;
switch (type) {
case 'require':
case 'import':
case 'charset':
case 'namespace':
case 'media':
case 'scope':
case 'supports':
return new Token(type);
case 'document':
return new Token('-moz-document');
case 'block':
return new Token('atblock');
case 'extend':
case 'extends':
return new Token('extend');
case 'keyframes':
return new Token(type, vendor);
default:
return new Token('atrule', (vendor ? '-' + vendor + '-' + type : type));
}
}
},
/**
* '//' *
*/
comment: function() {
// Single line
if ('/' == this.str[0] && '/' == this.str[1]) {
var end = this.str.indexOf('\n');
if (-1 == end) end = this.str.length;
this.skip(end);
return this.advance();
}
// Multi-line
if ('/' == this.str[0] && '*' == this.str[1]) {
var end = this.str.indexOf('*/');
if (-1 == end) end = this.str.length;
var str = this.str.substr(0, end + 2)
, lines = str.split(/\n|\r/).length - 1
, suppress = true
, inline = false;
this.lineno += lines;
this.skip(end + 2);
// output
if ('!' == str[2]) {
str = str.replace('*!', '*');
suppress = false;
}
if (this.prev && ';' == this.prev.type) inline = true;
return new Token('comment', new nodes.Comment(str, suppress, inline));
}
},
/**
* 'true' | 'false'
*/
boolean: function() {
var captures;
if (captures = /^(true|false)\b([ \t]*)/.exec(this.str)) {
var val = nodes.Boolean('true' == captures[1]);
this.skip(captures);
var tok = new Token('boolean', val);
tok.space = captures[2];
return tok;
}
},
/**
* 'U+' [0-9A-Fa-f?]{1,6}(?:-[0-9A-Fa-f]{1,6})?
*/
unicode: function() {
var captures;
if (captures = /^u\+[0-9a-f?]{1,6}(?:-[0-9a-f]{1,6})?/i.exec(this.str)) {
this.skip(captures);
return new Token('literal', new nodes.Literal(captures[0]));
}
},
/**
* -*[_a-zA-Z$] [-\w\d$]* '('
*/
function: function() {
var captures;
if (captures = /^(-*[_a-zA-Z$][-\w\d$]*)\(([ \t]*)/.exec(this.str)) {
var name = captures[1];
this.skip(captures);
this.isURL = 'url' == name;
var tok = new Token('function', new nodes.Ident(name));
tok.space = captures[2];
return tok;
}
},
/**
* -*[_a-zA-Z$] [-\w\d$]*
*/
ident: function() {
var captures;
if (captures = /^-*[_a-zA-Z$][-\w\d$]*/.exec(this.str)) {
this.skip(captures);
return new Token('ident', new nodes.Ident(captures[0]));
}
},
/**
* '\n' ' '+
*/
newline: function() {
var captures, re;
// we have established the indentation regexp
if (this.indentRe){
captures = this.indentRe.exec(this.str);
// figure out if we are using tabs or spaces
} else {
// try tabs
re = /^\n([\t]*)[ \t]*/;
captures = re.exec(this.str);
// nope, try spaces
if (captures && !captures[1].length) {
re = /^\n([ \t]*)/;
captures = re.exec(this.str);
}
// established
if (captures && captures[1].length) this.indentRe = re;
}
if (captures) {
var tok
, indents = captures[1].length;
this.skip(captures);
if (this.str[0] === ' ' || this.str[0] === '\t') {
throw new errors.SyntaxError('Invalid indentation. You can use tabs or spaces to indent, but not both.');
}
// Blank line
if ('\n' == this.str[0]) return this.advance();
// Outdent
if (this.indentStack.length && indents < this.indentStack[0]) {
while (this.indentStack.length && this.indentStack[0] > indents) {
this.stash.push(new Token('outdent'));
this.indentStack.shift();
}
tok = this.stash.pop();
// Indent
} else if (indents && indents != this.indentStack[0]) {
this.indentStack.unshift(indents);
tok = new Token('indent');
// Newline
} else {
tok = new Token('newline');
}
return tok;
}
},
/**
* '-'? (digit+ | digit* '.' digit+) unit
*/
unit: function() {
var captures;
if (captures = /^(-)?(\d+\.\d+|\d+|\.\d+)(%|[a-zA-Z]+)?[ \t]*/.exec(this.str)) {
this.skip(captures);
var n = parseFloat(captures[2]);
if ('-' == captures[1]) n = -n;
var node = new nodes.Unit(n, captures[3]);
node.raw = captures[0];
return new Token('unit', node);
}
},
/**
* '"' [^"]+ '"' | "'"" [^']+ "'"
*/
string: function() {
var captures;
if (captures = /^("[^"]*"|'[^']*')[ \t]*/.exec(this.str)) {
var str = captures[1]
, quote = captures[0][0];
this.skip(captures);
str = str.slice(1,-1).replace(/\\n/g, '\n');
return new Token('string', new nodes.String(str, quote));
}
},
/**
* #rrggbbaa | #rrggbb | #rgba | #rgb | #nn | #n
*/
color: function() {
return this.rrggbbaa()
|| this.rrggbb()
|| this.rgba()
|| this.rgb()
|| this.nn()
|| this.n()
},
/**
* #n
*/
n: function() {
var captures;
if (captures = /^#([a-fA-F0-9]{1})[ \t]*/.exec(this.str)) {
this.skip(captures);
var n = parseInt(captures[1] + captures[1], 16)
, color = new nodes.RGBA(n, n, n, 1);
color.raw = captures[0];
return new Token('color', color);
}
},
/**
* #nn
*/
nn: function() {
var captures;
if (captures = /^#([a-fA-F0-9]{2})[ \t]*/.exec(this.str)) {
this.skip(captures);
var n = parseInt(captures[1], 16)
, color = new nodes.RGBA(n, n, n, 1);
color.raw = captures[0];
return new Token('color', color);
}
},
/**
* #rgb
*/
rgb: function() {
var captures;
if (captures = /^#([a-fA-F0-9]{3})[ \t]*/.exec(this.str)) {
this.skip(captures);
var rgb = captures[1]
, r = parseInt(rgb[0] + rgb[0], 16)
, g = parseInt(rgb[1] + rgb[1], 16)
, b = parseInt(rgb[2] + rgb[2], 16)
, color = new nodes.RGBA(r, g, b, 1);
color.raw = captures[0];
return new Token('color', color);
}
},
/**
* #rgba
*/
rgba: function() {
var captures;
if (captures = /^#([a-fA-F0-9]{4})[ \t]*/.exec(this.str)) {
this.skip(captures);
var rgb = captures[1]
, r = parseInt(rgb[0] + rgb[0], 16)
, g = parseInt(rgb[1] + rgb[1], 16)
, b = parseInt(rgb[2] + rgb[2], 16)
, a = parseInt(rgb[3] + rgb[3], 16)
, color = new nodes.RGBA(r, g, b, a/255);
color.raw = captures[0];
return new Token('color', color);
}
},
/**
* #rrggbb
*/
rrggbb: function() {
var captures;
if (captures = /^#([a-fA-F0-9]{6})[ \t]*/.exec(this.str)) {
this.skip(captures);
var rgb = captures[1]
, r = parseInt(rgb.substr(0, 2), 16)
, g = parseInt(rgb.substr(2, 2), 16)
, b = parseInt(rgb.substr(4, 2), 16)
, color = new nodes.RGBA(r, g, b, 1);
color.raw = captures[0];
return new Token('color', color);
}
},
/**
* #rrggbbaa
*/
rrggbbaa: function() {
var captures;
if (captures = /^#([a-fA-F0-9]{8})[ \t]*/.exec(this.str)) {
this.skip(captures);
var rgb = captures[1]
, r = parseInt(rgb.substr(0, 2), 16)
, g = parseInt(rgb.substr(2, 2), 16)
, b = parseInt(rgb.substr(4, 2), 16)
, a = parseInt(rgb.substr(6, 2), 16)
, color = new nodes.RGBA(r, g, b, a/255);
color.raw = captures[0];
return new Token('color', color);
}
},
/**
* ^|[^\n,;]+
*/
selector: function() {
var captures;
if (captures = /^\^|.*?(?=\/\/(?![^\[]*\])|[,\n{])/.exec(this.str)) {
var selector = captures[0];
this.skip(captures);
return new Token('selector', selector);
}
}
};
+256
View File
@@ -0,0 +1,256 @@
/*!
* Stylus - middleware
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var stylus = require('./stylus')
, fs = require('fs')
, url = require('url')
, dirname = require('path').dirname
, mkdirp = require('mkdirp')
, join = require('path').join
, sep = require('path').sep
, debug = require('debug')('stylus:middleware');
/**
* Import map.
*/
var imports = {};
/**
* Return Connect middleware with the given `options`.
*
* Options:
*
* `force` Always re-compile
* `src` Source directory used to find .styl files,
* a string or function accepting `(path)` of request.
* `dest` Destination directory used to output .css files,
* a string or function accepting `(path)` of request,
* when undefined defaults to `src`.
* `compile` Custom compile function, accepting the arguments
* `(str, path)`.
* `compress` Whether the output .css files should be compressed
* `firebug` Emits debug infos in the generated CSS that can
* be used by the FireStylus Firebug plugin
* `linenos` Emits comments in the generated CSS indicating
* the corresponding Stylus line
* 'sourcemap' Generates a sourcemap in sourcemaps v3 format
*
* Examples:
*
* Here we set up the custom compile function so that we may
* set the `compress` option, or define additional functions.
*
* By default the compile function simply sets the `filename`
* and renders the CSS.
*
* function compile(str, path) {
* return stylus(str)
* .set('filename', path)
* .set('compress', true);
* }
*
* Pass the middleware to Connect, grabbing .styl files from this directory
* and saving .css files to _./public_. Also supplying our custom `compile` function.
*
* Following that we have a `static()` layer setup to serve the .css
* files generated by Stylus.
*
* var app = connect();
*
* app.middleware({
* src: __dirname
* , dest: __dirname + '/public'
* , compile: compile
* })
*
* app.use(connect.static(__dirname + '/public'));
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function(options){
options = options || {};
// Accept src/dest dir
if ('string' == typeof options) {
options = { src: options };
}
// Force compilation
var force = options.force;
// Source dir required
var src = options.src;
if (!src) throw new Error('stylus.middleware() requires "src" directory');
// Default dest dir to source
var dest = options.dest || src;
// Default compile callback
options.compile = options.compile || function(str, path){
// inline sourcemap
if (options.sourcemap) {
if ('boolean' == typeof options.sourcemap)
options.sourcemap = {};
options.sourcemap.inline = true;
}
return stylus(str)
.set('filename', path)
.set('compress', options.compress)
.set('firebug', options.firebug)
.set('linenos', options.linenos)
.set('sourcemap', options.sourcemap);
};
// Middleware
return function stylus(req, res, next){
if ('GET' != req.method && 'HEAD' != req.method) return next();
var path = url.parse(req.url).pathname;
if (/\.css$/.test(path)) {
if (typeof dest == 'string') {
// check for dest-path overlap
var overlap = compare(dest, path).length;
if ('/' == path.charAt(0)) overlap++;
path = path.slice(overlap);
}
var cssPath, stylusPath;
cssPath = (typeof dest == 'function')
? dest(path)
: join(dest, path);
stylusPath = (typeof src == 'function')
? src(path)
: join(src, path.replace('.css', '.styl'));
// Ignore ENOENT to fall through as 404
function error(err) {
next('ENOENT' == err.code
? null
: err);
}
// Force
if (force) return compile();
// Compile to cssPath
function compile() {
debug('read %s', cssPath);
fs.readFile(stylusPath, 'utf8', function(err, str){
if (err) return error(err);
var style = options.compile(str, stylusPath);
var paths = style.options._imports = [];
imports[stylusPath] = null;
style.render(function(err, css){
if (err) return next(err);
debug('render %s', stylusPath);
imports[stylusPath] = paths;
mkdirp(dirname(cssPath), parseInt('0700', 8), function(err){
if (err) return error(err);
fs.writeFile(cssPath, css, 'utf8', next);
});
});
});
}
// Re-compile on server restart, disregarding
// mtimes since we need to map imports
if (!imports[stylusPath]) return compile();
// Compare mtimes
fs.stat(stylusPath, function(err, stylusStats){
if (err) return error(err);
fs.stat(cssPath, function(err, cssStats){
// CSS has not been compiled, compile it!
if (err) {
if ('ENOENT' == err.code) {
debug('not found %s', cssPath);
compile();
} else {
next(err);
}
} else {
// Source has changed, compile it
if (stylusStats.mtime > cssStats.mtime) {
debug('modified %s', cssPath);
compile();
// Already compiled, check imports
} else {
checkImports(stylusPath, function(changed){
if (debug && changed.length) {
changed.forEach(function(path) {
debug('modified import %s', path);
});
}
changed.length ? compile() : next();
});
}
}
});
});
} else {
next();
}
}
};
/**
* Check `path`'s imports to see if they have been altered.
*
* @param {String} path
* @param {Function} fn
* @api private
*/
function checkImports(path, fn) {
var nodes = imports[path];
if (!nodes) return fn();
if (!nodes.length) return fn();
var pending = nodes.length
, changed = [];
nodes.forEach(function(imported){
fs.stat(imported.path, function(err, stat){
// error or newer mtime
if (err || !imported.mtime || stat.mtime > imported.mtime) {
changed.push(imported.path);
}
--pending || fn(changed);
});
});
}
/**
* get the overlaping path from the end of path A, and the begining of path B.
*
* @param {String} pathA
* @param {String} pathB
* @return {String}
* @api private
*/
function compare(pathA, pathB) {
pathA = pathA.split(sep);
pathB = pathB.split('/');
if (!pathA[pathA.length - 1]) pathA.pop();
if (!pathB[0]) pathB.shift();
var overlap = [];
while (pathA[pathA.length - 1] == pathB[0]) {
overlap.push(pathA.pop());
pathB.shift();
}
return overlap.join('/');
}
+92
View File
@@ -0,0 +1,92 @@
/*!
* Stylus - Arguments
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node')
, nodes = require('../nodes')
, utils = require('../utils');
/**
* Initialize a new `Arguments`.
*
* @api public
*/
var Arguments = module.exports = function Arguments(){
nodes.Expression.call(this);
this.map = {};
};
/**
* Inherit from `nodes.Expression.prototype`.
*/
Arguments.prototype.__proto__ = nodes.Expression.prototype;
/**
* Initialize an `Arguments` object with the nodes
* from the given `expr`.
*
* @param {Expression} expr
* @return {Arguments}
* @api public
*/
Arguments.fromExpression = function(expr){
var args = new Arguments
, len = expr.nodes.length;
args.lineno = expr.lineno;
args.column = expr.column;
args.isList = expr.isList;
for (var i = 0; i < len; ++i) {
args.push(expr.nodes[i]);
}
return args;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Arguments.prototype.clone = function(parent){
var clone = nodes.Expression.prototype.clone.call(this, parent);
clone.map = {};
for (var key in this.map) {
clone.map[key] = this.map[key].clone(parent, clone);
}
clone.isList = this.isList;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Arguments.prototype.toJSON = function(){
return {
__type: 'Arguments',
map: this.map,
isList: this.isList,
preserve: this.preserve,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
};
};
+79
View File
@@ -0,0 +1,79 @@
/*!
* Stylus - @block
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `@block` node.
*
* @api public
*/
var Atblock = module.exports = function Atblock(){
Node.call(this);
};
/**
* Return `block` nodes.
*/
Atblock.prototype.__defineGetter__('nodes', function(){
return this.block.nodes;
});
/**
* Inherit from `Node.prototype`.
*/
Atblock.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Atblock.prototype.clone = function(parent){
var clone = new Atblock;
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return @block.
*
* @return {String}
* @api public
*/
Atblock.prototype.toString = function(){
return '@block';
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Atblock.prototype.toJSON = function(){
return {
__type: 'Atblock',
block: this.block,
lineno: this.lineno,
column: this.column,
fileno: this.fileno
};
};
+136
View File
@@ -0,0 +1,136 @@
/*!
* Stylus - at-rule
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new at-rule node.
*
* @param {String} type
* @api public
*/
var Atrule = module.exports = function Atrule(type){
Node.call(this);
this.type = type;
};
/**
* Inherit from `Node.prototype`.
*/
Atrule.prototype.__proto__ = Node.prototype;
/**
* Check if at-rule's block has only properties.
*
* @return {Boolean}
* @api public
*/
Atrule.prototype.__defineGetter__('hasOnlyProperties', function(){
if (!this.block) return false;
var nodes = this.block.nodes;
for (var i = 0, len = nodes.length; i < len; ++i) {
var nodeName = nodes[i].nodeName;
switch(nodes[i].nodeName) {
case 'property':
case 'expression':
case 'comment':
continue;
default:
return false;
}
}
return true;
});
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Atrule.prototype.clone = function(parent){
var clone = new Atrule(this.type);
if (this.block) clone.block = this.block.clone(parent, clone);
clone.segments = this.segments.map(function(node){ return node.clone(parent, clone); });
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Atrule.prototype.toJSON = function(){
var json = {
__type: 'Atrule',
type: this.type,
segments: this.segments,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.block) json.block = this.block;
return json;
};
/**
* Return @<type>.
*
* @return {String}
* @api public
*/
Atrule.prototype.toString = function(){
return '@' + this.type;
};
/**
* Check if the at-rule's block has output nodes.
*
* @return {Boolean}
* @api public
*/
Atrule.prototype.__defineGetter__('hasOutput', function(){
return !!this.block && hasOutput(this.block);
});
function hasOutput(block) {
var nodes = block.nodes;
// only placeholder selectors
if (nodes.every(function(node){
return 'group' == node.nodeName && node.hasOnlyPlaceholders;
})) return false;
// something visible
return nodes.some(function(node) {
switch (node.nodeName) {
case 'property':
case 'literal':
case 'import':
return true;
case 'block':
return hasOutput(node);
default:
if (node.block) return hasOutput(node.block);
}
});
}
+83
View File
@@ -0,0 +1,83 @@
/*!
* Stylus - BinOp
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `BinOp` with `op`, `left` and `right`.
*
* @param {String} op
* @param {Node} left
* @param {Node} right
* @api public
*/
var BinOp = module.exports = function BinOp(op, left, right){
Node.call(this);
this.op = op;
this.left = left;
this.right = right;
};
/**
* Inherit from `Node.prototype`.
*/
BinOp.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
BinOp.prototype.clone = function(parent){
var clone = new BinOp(this.op);
clone.left = this.left.clone(parent, clone);
clone.right = this.right && this.right.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
if (this.val) clone.val = this.val.clone(parent, clone);
return clone;
};
/**
* Return <left> <op> <right>
*
* @return {String}
* @api public
*/
BinOp.prototype.toString = function() {
return this.left.toString() + ' ' + this.op + ' ' + this.right.toString();
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
BinOp.prototype.toJSON = function(){
var json = {
__type: 'BinOp',
left: this.left,
right: this.right,
op: this.op,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.val) json.val = this.val;
return json;
};
+127
View File
@@ -0,0 +1,127 @@
/*!
* Stylus - Block
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `Block` node with `parent` Block.
*
* @param {Block} parent
* @api public
*/
var Block = module.exports = function Block(parent, node){
Node.call(this);
this.nodes = [];
this.parent = parent;
this.node = node;
this.scope = true;
};
/**
* Inherit from `Node.prototype`.
*/
Block.prototype.__proto__ = Node.prototype;
/**
* Check if this block has properties..
*
* @return {Boolean}
* @api public
*/
Block.prototype.__defineGetter__('hasProperties', function(){
for (var i = 0, len = this.nodes.length; i < len; ++i) {
if ('property' == this.nodes[i].nodeName) {
return true;
}
}
});
/**
* Check if this block has @media nodes.
*
* @return {Boolean}
* @api public
*/
Block.prototype.__defineGetter__('hasMedia', function(){
for (var i = 0, len = this.nodes.length; i < len; ++i) {
var nodeName = this.nodes[i].nodeName;
if ('media' == nodeName) {
return true;
}
}
return false;
});
/**
* Check if this block is empty.
*
* @return {Boolean}
* @api public
*/
Block.prototype.__defineGetter__('isEmpty', function(){
return !this.nodes.length;
});
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Block.prototype.clone = function(parent, node){
parent = parent || this.parent;
var clone = new Block(parent, node || this.node);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.scope = this.scope;
this.nodes.forEach(function(node){
clone.push(node.clone(clone, clone));
});
return clone;
};
/**
* Push a `node` to this block.
*
* @param {Node} node
* @api public
*/
Block.prototype.push = function(node){
this.nodes.push(node);
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Block.prototype.toJSON = function(){
return {
__type: 'Block',
// parent: this.parent,
// node: this.node,
scope: this.scope,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
};
};
+117
View File
@@ -0,0 +1,117 @@
/*!
* Stylus - Boolean
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node')
, nodes = require('./');
/**
* Initialize a new `Boolean` node with the given `val`.
*
* @param {Boolean} val
* @api public
*/
var Boolean = module.exports = function Boolean(val){
Node.call(this);
if (this.nodeName) {
this.val = !!val;
} else {
return new Boolean(val);
}
};
/**
* Inherit from `Node.prototype`.
*/
Boolean.prototype.__proto__ = Node.prototype;
/**
* Return `this` node.
*
* @return {Boolean}
* @api public
*/
Boolean.prototype.toBoolean = function(){
return this;
};
/**
* Return `true` if this node represents `true`.
*
* @return {Boolean}
* @api public
*/
Boolean.prototype.__defineGetter__('isTrue', function(){
return this.val;
});
/**
* Return `true` if this node represents `false`.
*
* @return {Boolean}
* @api public
*/
Boolean.prototype.__defineGetter__('isFalse', function(){
return ! this.val;
});
/**
* Negate the value.
*
* @return {Boolean}
* @api public
*/
Boolean.prototype.negate = function(){
return new Boolean(!this.val);
};
/**
* Return 'Boolean'.
*
* @return {String}
* @api public
*/
Boolean.prototype.inspect = function(){
return '[Boolean ' + this.val + ']';
};
/**
* Return 'true' or 'false'.
*
* @return {String}
* @api public
*/
Boolean.prototype.toString = function(){
return this.val
? 'true'
: 'false';
};
/**
* Return a JSON representaiton of this node.
*
* @return {Object}
* @api public
*/
Boolean.prototype.toJSON = function(){
return {
__type: 'Boolean',
val: this.val
};
};
+85
View File
@@ -0,0 +1,85 @@
/*!
* Stylus - Call
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `Call` with `name` and `args`.
*
* @param {String} name
* @param {Expression} args
* @api public
*/
var Call = module.exports = function Call(name, args){
Node.call(this);
this.name = name;
this.args = args;
};
/**
* Inherit from `Node.prototype`.
*/
Call.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Call.prototype.clone = function(parent){
var clone = new Call(this.name);
clone.args = this.args.clone(parent, clone);
if (this.block) clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return <name>(param1, param2, ...).
*
* @return {String}
* @api public
*/
Call.prototype.toString = function(){
var args = this.args.nodes.map(function(node) {
var str = node.toString();
return str.slice(1, str.length - 1);
}).join(', ');
return this.name + '(' + args + ')';
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Call.prototype.toJSON = function(){
var json = {
__type: 'Call',
name: this.name,
args: this.args,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.block) json.block = this.block;
return json;
};
+58
View File
@@ -0,0 +1,58 @@
/*!
* Stylus - Charset
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `Charset` with the given `val`
*
* @param {String} val
* @api public
*/
var Charset = module.exports = function Charset(val){
Node.call(this);
this.val = val;
};
/**
* Inherit from `Node.prototype`.
*/
Charset.prototype.__proto__ = Node.prototype;
/**
* Return @charset "val".
*
* @return {String}
* @api public
*/
Charset.prototype.toString = function(){
return '@charset ' + this.val;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Charset.prototype.toJSON = function(){
return {
__type: 'Charset',
val: this.val,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
+64
View File
@@ -0,0 +1,64 @@
/*!
* Stylus - Comment
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `Comment` with the given `str`.
*
* @param {String} str
* @param {Boolean} suppress
* @param {Boolean} inline
* @api public
*/
var Comment = module.exports = function Comment(str, suppress, inline){
Node.call(this);
this.str = str;
this.suppress = suppress;
this.inline = inline;
};
/**
* Inherit from `Node.prototype`.
*/
Comment.prototype.__proto__ = Node.prototype;
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Comment.prototype.toJSON = function(){
return {
__type: 'Comment',
str: this.str,
suppress: this.suppress,
inline: this.inline,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return comment.
*
* @return {String}
* @api public
*/
Comment.prototype.toString = function(){
return this.str;
};
+75
View File
@@ -0,0 +1,75 @@
/*!
* Stylus - Each
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node')
, nodes = require('./');
/**
* Initialize a new `Each` node with the given `val` name,
* `key` name, `expr`, and `block`.
*
* @param {String} val
* @param {String} key
* @param {Expression} expr
* @param {Block} block
* @api public
*/
var Each = module.exports = function Each(val, key, expr, block){
Node.call(this);
this.val = val;
this.key = key;
this.expr = expr;
this.block = block;
};
/**
* Inherit from `Node.prototype`.
*/
Each.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Each.prototype.clone = function(parent){
var clone = new Each(this.val, this.key);
clone.expr = this.expr.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Each.prototype.toJSON = function(){
return {
__type: 'Each',
val: this.val,
key: this.key,
expr: this.expr,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
+220
View File
@@ -0,0 +1,220 @@
/*!
* Stylus - Expression
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node')
, nodes = require('../nodes')
, utils = require('../utils');
/**
* Initialize a new `Expression`.
*
* @param {Boolean} isList
* @api public
*/
var Expression = module.exports = function Expression(isList){
Node.call(this);
this.nodes = [];
this.isList = isList;
};
/**
* Check if the variable has a value.
*
* @return {Boolean}
* @api public
*/
Expression.prototype.__defineGetter__('isEmpty', function(){
return !this.nodes.length;
});
/**
* Return the first node in this expression.
*
* @return {Node}
* @api public
*/
Expression.prototype.__defineGetter__('first', function(){
return this.nodes[0]
? this.nodes[0].first
: nodes.null;
});
/**
* Hash all the nodes in order.
*
* @return {String}
* @api public
*/
Expression.prototype.__defineGetter__('hash', function(){
return this.nodes.map(function(node){
return node.hash;
}).join('::');
});
/**
* Inherit from `Node.prototype`.
*/
Expression.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Expression.prototype.clone = function(parent){
var clone = new this.constructor(this.isList);
clone.preserve = this.preserve;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.nodes = this.nodes.map(function(node) {
return node.clone(parent, clone);
});
return clone;
};
/**
* Push the given `node`.
*
* @param {Node} node
* @api public
*/
Expression.prototype.push = function(node){
this.nodes.push(node);
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Expression.prototype.operate = function(op, right, val){
switch (op) {
case '[]=':
var self = this
, range = utils.unwrap(right).nodes
, val = utils.unwrap(val)
, len
, node;
range.forEach(function(unit){
len = self.nodes.length;
if ('unit' == unit.nodeName) {
var i = unit.val < 0 ? len + unit.val : unit.val
, n = i;
while (i-- > len) self.nodes[i] = nodes.null;
self.nodes[n] = val;
} else if (unit.string) {
node = self.nodes[0];
if (node && 'object' == node.nodeName) node.set(unit.string, val.clone());
}
});
return val;
case '[]':
var expr = new nodes.Expression
, vals = utils.unwrap(this).nodes
, range = utils.unwrap(right).nodes
, node;
range.forEach(function(unit){
if ('unit' == unit.nodeName) {
node = vals[unit.val < 0 ? vals.length + unit.val : unit.val];
} else if ('object' == vals[0].nodeName) {
node = vals[0].get(unit.string);
}
if (node) expr.push(node);
});
return expr.isEmpty
? nodes.null
: utils.unwrap(expr);
case '||':
return this.toBoolean().isTrue
? this
: right;
case 'in':
return Node.prototype.operate.call(this, op, right);
case '!=':
return this.operate('==', right, val).negate();
case '==':
var len = this.nodes.length
, right = right.toExpression()
, a
, b;
if (len != right.nodes.length) return nodes.false;
for (var i = 0; i < len; ++i) {
a = this.nodes[i];
b = right.nodes[i];
if (a.operate(op, b).isTrue) continue;
return nodes.false;
}
return nodes.true;
break;
default:
return this.first.operate(op, right, val);
}
};
/**
* Expressions with length > 1 are truthy,
* otherwise the first value's toBoolean()
* method is invoked.
*
* @return {Boolean}
* @api public
*/
Expression.prototype.toBoolean = function(){
if (this.nodes.length > 1) return nodes.true;
return this.first.toBoolean();
};
/**
* Return "<a> <b> <c>" or "<a>, <b>, <c>" if
* the expression represents a list.
*
* @return {String}
* @api public
*/
Expression.prototype.toString = function(){
return '(' + this.nodes.map(function(node){
return node.toString();
}).join(this.isList ? ', ' : ' ') + ')';
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Expression.prototype.toJSON = function(){
return {
__type: 'Expression',
isList: this.isList,
preserve: this.preserve,
lineno: this.lineno,
column: this.column,
filename: this.filename,
nodes: this.nodes
};
};
+69
View File
@@ -0,0 +1,69 @@
/*!
* Stylus - Extend
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `Extend` with the given `selectors` array.
*
* @param {Array} selectors array of the selectors
* @api public
*/
var Extend = module.exports = function Extend(selectors){
Node.call(this);
this.selectors = selectors;
};
/**
* Inherit from `Node.prototype`.
*/
Extend.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Extend.prototype.clone = function(){
return new Extend(this.selectors);
};
/**
* Return `@extend selectors`.
*
* @return {String}
* @api public
*/
Extend.prototype.toString = function(){
return '@extend ' + this.selectors.join(', ');
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Extend.prototype.toJSON = function(){
return {
__type: 'Extend',
selectors: this.selectors,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
+84
View File
@@ -0,0 +1,84 @@
/*!
* Stylus - Feature
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `Feature` with the given `segs`.
*
* @param {Array} segs
* @api public
*/
var Feature = module.exports = function Feature(segs){
Node.call(this);
this.segments = segs;
this.expr = null;
};
/**
* Inherit from `Node.prototype`.
*/
Feature.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Feature.prototype.clone = function(parent){
var clone = new Feature;
clone.segments = this.segments.map(function(node){ return node.clone(parent, clone); });
if (this.expr) clone.expr = this.expr.clone(parent, clone);
if (this.name) clone.name = this.name;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return "<ident>" or "(<ident>: <expr>)"
*
* @return {String}
* @api public
*/
Feature.prototype.toString = function(){
if (this.expr) {
return '(' + this.segments.join('') + ': ' + this.expr.toString() + ')';
} else {
return this.segments.join('');
}
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Feature.prototype.toJSON = function(){
var json = {
__type: 'Feature',
segments: this.segments,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.expr) json.expr = this.expr;
if (this.name) json.name = this.name;
return json;
};
+128
View File
@@ -0,0 +1,128 @@
/*!
* Stylus - Function
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `Function` with `name`, `params`, and `body`.
*
* @param {String} name
* @param {Params|Function} params
* @param {Block} body
* @api public
*/
var Function = module.exports = function Function(name, params, body){
Node.call(this);
this.name = name;
this.params = params;
this.block = body;
if ('function' == typeof params) this.fn = params;
};
/**
* Check function arity.
*
* @return {Boolean}
* @api public
*/
Function.prototype.__defineGetter__('arity', function(){
return this.params.length;
});
/**
* Inherit from `Node.prototype`.
*/
Function.prototype.__proto__ = Node.prototype;
/**
* Return hash.
*
* @return {String}
* @api public
*/
Function.prototype.__defineGetter__('hash', function(){
return 'function ' + this.name;
});
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Function.prototype.clone = function(parent){
if (this.fn) {
var clone = new Function(
this.name
, this.fn);
} else {
var clone = new Function(this.name);
clone.params = this.params.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
}
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return <name>(param1, param2, ...).
*
* @return {String}
* @api public
*/
Function.prototype.toString = function(){
if (this.fn) {
return this.name
+ '('
+ this.fn.toString()
.match(/^function *\w*\((.*?)\)/)
.slice(1)
.join(', ')
+ ')';
} else {
return this.name
+ '('
+ this.params.nodes.join(', ')
+ ')';
}
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Function.prototype.toJSON = function(){
var json = {
__type: 'Function',
name: this.name,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
if (this.fn) {
json.fn = this.fn;
} else {
json.params = this.params;
json.block = this.block;
}
return json;
};
+110
View File
@@ -0,0 +1,110 @@
/*!
* Stylus - Group
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `Group`.
*
* @api public
*/
var Group = module.exports = function Group(){
Node.call(this);
this.nodes = [];
this.extends = [];
};
/**
* Inherit from `Node.prototype`.
*/
Group.prototype.__proto__ = Node.prototype;
/**
* Push the given `selector` node.
*
* @param {Selector} selector
* @api public
*/
Group.prototype.push = function(selector){
this.nodes.push(selector);
};
/**
* Return this set's `Block`.
*/
Group.prototype.__defineGetter__('block', function(){
return this.nodes[0].block;
});
/**
* Assign `block` to each selector in this set.
*
* @param {Block} block
* @api public
*/
Group.prototype.__defineSetter__('block', function(block){
for (var i = 0, len = this.nodes.length; i < len; ++i) {
this.nodes[i].block = block;
}
});
/**
* Check if this set has only placeholders.
*
* @return {Boolean}
* @api public
*/
Group.prototype.__defineGetter__('hasOnlyPlaceholders', function(){
return this.nodes.every(function(selector) { return selector.isPlaceholder; });
});
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Group.prototype.clone = function(parent){
var clone = new Group;
clone.lineno = this.lineno;
clone.column = this.column;
this.nodes.forEach(function(node){
clone.push(node.clone(parent, clone));
});
clone.filename = this.filename;
clone.block = this.block.clone(parent, clone);
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Group.prototype.toJSON = function(){
return {
__type: 'Group',
nodes: this.nodes,
block: this.block,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
+277
View File
@@ -0,0 +1,277 @@
/*!
* Stylus - HSLA
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node')
, nodes = require('./');
/**
* Initialize a new `HSLA` with the given h,s,l,a component values.
*
* @param {Number} h
* @param {Number} s
* @param {Number} l
* @param {Number} a
* @api public
*/
var HSLA = exports = module.exports = function HSLA(h,s,l,a){
Node.call(this);
this.h = clampDegrees(h);
this.s = clampPercentage(s);
this.l = clampPercentage(l);
this.a = clampAlpha(a);
this.hsla = this;
};
/**
* Inherit from `Node.prototype`.
*/
HSLA.prototype.__proto__ = Node.prototype;
/**
* Return hsla(n,n,n,n).
*
* @return {String}
* @api public
*/
HSLA.prototype.toString = function(){
return 'hsla('
+ this.h + ','
+ this.s.toFixed(0) + '%,'
+ this.l.toFixed(0) + '%,'
+ this.a + ')';
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
HSLA.prototype.clone = function(parent){
var clone = new HSLA(
this.h
, this.s
, this.l
, this.a);
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
HSLA.prototype.toJSON = function(){
return {
__type: 'HSLA',
h: this.h,
s: this.s,
l: this.l,
a: this.a,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return rgba `RGBA` representation.
*
* @return {RGBA}
* @api public
*/
HSLA.prototype.__defineGetter__('rgba', function(){
return nodes.RGBA.fromHSLA(this);
});
/**
* Return hash.
*
* @return {String}
* @api public
*/
HSLA.prototype.__defineGetter__('hash', function(){
return this.rgba.toString();
});
/**
* Add h,s,l to the current component values.
*
* @param {Number} h
* @param {Number} s
* @param {Number} l
* @return {HSLA} new node
* @api public
*/
HSLA.prototype.add = function(h,s,l){
return new HSLA(
this.h + h
, this.s + s
, this.l + l
, this.a);
};
/**
* Subtract h,s,l from the current component values.
*
* @param {Number} h
* @param {Number} s
* @param {Number} l
* @return {HSLA} new node
* @api public
*/
HSLA.prototype.sub = function(h,s,l){
return this.add(-h, -s, -l);
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
HSLA.prototype.operate = function(op, right){
switch (op) {
case '==':
case '!=':
case '<=':
case '>=':
case '<':
case '>':
case 'is a':
case '||':
case '&&':
return this.rgba.operate(op, right);
default:
return this.rgba.operate(op, right).hsla;
}
};
/**
* Return `HSLA` representation of the given `color`.
*
* @param {RGBA} color
* @return {HSLA}
* @api public
*/
exports.fromRGBA = function(rgba){
var r = rgba.r / 255
, g = rgba.g / 255
, b = rgba.b / 255
, a = rgba.a;
var min = Math.min(r,g,b)
, max = Math.max(r,g,b)
, l = (max + min) / 2
, d = max - min
, h, s;
switch (max) {
case min: h = 0; break;
case r: h = 60 * (g-b) / d; break;
case g: h = 60 * (b-r) / d + 120; break;
case b: h = 60 * (r-g) / d + 240; break;
}
if (max == min) {
s = 0;
} else if (l < .5) {
s = d / (2 * l);
} else {
s = d / (2 - 2 * l);
}
h %= 360;
s *= 100;
l *= 100;
return new HSLA(h,s,l,a);
};
/**
* Adjust lightness by `percent`.
*
* @param {Number} percent
* @return {HSLA} for chaining
* @api public
*/
HSLA.prototype.adjustLightness = function(percent){
this.l = clampPercentage(this.l + this.l * (percent / 100));
return this;
};
/**
* Adjust hue by `deg`.
*
* @param {Number} deg
* @return {HSLA} for chaining
* @api public
*/
HSLA.prototype.adjustHue = function(deg){
this.h = clampDegrees(this.h + deg);
return this;
};
/**
* Clamp degree `n` >= 0 and <= 360.
*
* @param {Number} n
* @return {Number}
* @api private
*/
function clampDegrees(n) {
n = n % 360;
return n >= 0 ? n : 360 + n;
}
/**
* Clamp percentage `n` >= 0 and <= 100.
*
* @param {Number} n
* @return {Number}
* @api private
*/
function clampPercentage(n) {
return Math.max(0, Math.min(n, 100));
}
/**
* Clamp alpha `n` >= 0 and <= 1.
*
* @param {Number} n
* @return {Number}
* @api private
*/
function clampAlpha(n) {
return Math.max(0, Math.min(n, 1));
}
+156
View File
@@ -0,0 +1,156 @@
/*!
* Stylus - Ident
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node')
, nodes = require('./');
/**
* Initialize a new `Ident` by `name` with the given `val` node.
*
* @param {String} name
* @param {Node} val
* @api public
*/
var Ident = module.exports = function Ident(name, val, mixin){
Node.call(this);
this.name = name;
this.string = name;
this.val = val || nodes.null;
this.mixin = !!mixin;
};
/**
* Check if the variable has a value.
*
* @return {Boolean}
* @api public
*/
Ident.prototype.__defineGetter__('isEmpty', function(){
return undefined == this.val;
});
/**
* Return hash.
*
* @return {String}
* @api public
*/
Ident.prototype.__defineGetter__('hash', function(){
return this.name;
});
/**
* Inherit from `Node.prototype`.
*/
Ident.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
Ident.prototype.clone = function(parent){
var clone = new Ident(this.name);
clone.val = this.val.clone(parent, clone);
clone.mixin = this.mixin;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
clone.property = this.property;
clone.rest = this.rest;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
Ident.prototype.toJSON = function(){
return {
__type: 'Ident',
name: this.name,
val: this.val,
mixin: this.mixin,
property: this.property,
rest: this.rest,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return <name>.
*
* @return {String}
* @api public
*/
Ident.prototype.toString = function(){
return this.name;
};
/**
* Coerce `other` to an ident.
*
* @param {Node} other
* @return {String}
* @api public
*/
Ident.prototype.coerce = function(other){
switch (other.nodeName) {
case 'ident':
case 'string':
case 'literal':
return new Ident(other.string);
case 'unit':
return new Ident(other.toString());
default:
return Node.prototype.coerce.call(this, other);
}
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
Ident.prototype.operate = function(op, right){
var val = right.first;
switch (op) {
case '-':
if ('unit' == val.nodeName) {
var expr = new nodes.Expression;
val = val.clone();
val.val = -val.val;
expr.push(this);
expr.push(val);
return expr;
}
case '+':
return new nodes.Ident(this.string + this.coerce(val).string);
}
return Node.prototype.operate.call(this, op, right);
};
+78
View File
@@ -0,0 +1,78 @@
/*!
* Stylus - If
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node');
/**
* Initialize a new `If` with the given `cond`.
*
* @param {Expression} cond
* @param {Boolean|Block} negate, block
* @api public
*/
var If = module.exports = function If(cond, negate){
Node.call(this);
this.cond = cond;
this.elses = [];
if (negate && negate.nodeName) {
this.block = negate;
} else {
this.negate = negate;
}
};
/**
* Inherit from `Node.prototype`.
*/
If.prototype.__proto__ = Node.prototype;
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
If.prototype.clone = function(parent){
var clone = new If();
clone.cond = this.cond.clone(parent, clone);
clone.block = this.block.clone(parent, clone);
clone.elses = this.elses.map(function(node){ return node.clone(parent, clone); });
clone.negate = this.negate;
clone.postfix = this.postfix;
clone.lineno = this.lineno;
clone.column = this.column;
clone.filename = this.filename;
return clone;
};
/**
* Return a JSON representation of this node.
*
* @return {Object}
* @api public
*/
If.prototype.toJSON = function(){
return {
__type: 'If',
cond: this.cond,
block: this.block,
elses: this.elses,
negate: this.negate,
postfix: this.postfix,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};

Some files were not shown because too many files have changed in this diff Show More