Skip to content
This repository has been archived by the owner on Dec 30, 2019. It is now read-only.

Commit

Permalink
Merge branch 'master' of github.com:twitter/recess
Browse files Browse the repository at this point in the history
Conflicts:
	package.json
	test/types/lint.js
  • Loading branch information
fat committed Aug 19, 2012
2 parents 6971513 + 8c87127 commit 2ec6067
Show file tree
Hide file tree
Showing 16 changed files with 195 additions and 16 deletions.
10 changes: 9 additions & 1 deletion README.md
Expand Up @@ -26,6 +26,7 @@ OPTIONS
- --noOverqualifying - doesn't complain about overqualified selectors (ie: `div#foo.bar`)
- --noUnderscores - doesn't complain about using underscores in your class names
- --noUniversalSelectors - doesn't complain about using the universal `*` selector
- --prefixWhitespace - adds whitespace prefix to line up vender prefixed properties
- --strictPropertyOrder - doesn't looking into your property ordering
- --zeroUnits - doesn't complain if you add units to values of 0

Expand Down Expand Up @@ -54,7 +55,13 @@ $ recess ./bootstrap.less --compress > ./bootstrap-production.css
Watch a directory for changes and auto compile a css file from the changes. *experimental*

```CLI
$ recess input.less:ouput.css --compile --watch watch/this/dir/for/changes
$ recess input.less:ouput.css --watch watch/this/dir/for/changes
```

Watch a single file for changes and auto compile a css file from the changes. *experimental*

```CLI
$ recess input.less:ouput.css --watch
```

PROGRAMMATIC API
Expand Down Expand Up @@ -83,6 +90,7 @@ The following options (and defaults) are available in the programatic api:
- noUniversalSelectors: true
- prefixWhitespace: true
- strictPropertyOrder: true
- stripColors: false
- zeroUnits: true

The callback is fired when each instance has finished processessing an input. The callback is passed an array of of instances (one for each path). The instances have a bunch of useful things on them like the raw data and an array of output strings.
Expand Down
16 changes: 14 additions & 2 deletions bin/recess
Expand Up @@ -61,6 +61,9 @@ options.cli = true
// if not watch - run Recess
if (!options.watch) return recess(paths, options)

// if options watch, but compile isn't set - make it happen
if (options.watch && !options.compile && !options.compress) options.compile = true;

// set CLI to false
options.cli = false
paths = paths[0].split(':')
Expand All @@ -74,9 +77,18 @@ writeFile = function () {
})
}

// create monitor to watch filetree
// if watch doesn't exist, watch the path
if (!(fs.existsSync || path.existsSync)(options.watch)) options.watch = path.resolve(paths)

// throw if can't find file to watch
if (!(fs.existsSync || path.existsSync)(options.watch)) return console.log("can't find file: " + options.watch)

// use fs.watch if watchign single file
if (path.extname(options.watch)) return fs.watch(options.watch, writeFile)

// create monitor to watch filetree if provided dir
watch.createMonitor(options.watch, function (monitor) {
monitor.on("created", writeFile)
monitor.on("changed", writeFile)
monitor.on("removed", writeFile)
})
})
46 changes: 46 additions & 0 deletions lib/compile/inline-images.js
@@ -0,0 +1,46 @@
// ==========================================
// RECESS
// COMPILE: replaces image links with base64 image data
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under the Apache License v2.0
// http://www.apache.org/licenses/LICENSE-2.0
// ==========================================

'use strict'

var less = require('less')
, fs = require('fs')
, seperator = (process.platform == 'win32') ? '\\' : '/'
, toCSS
, path

function compile () {
// strip units from 0 values
var props = toCSS.apply(this, arguments)

// do we have a url here?
if (/url\(/.test(props)) {
var fileName = props.match(/url\((['"]?)(.*)\1\)/)[2]
, ext = fileName.match(/[^.]*$/)[0]
, mimetype = 'image/' + ext.replace(/jpg/, 'jpeg')
, pathParts = path.split(seperator)
, filePath = pathParts.slice(0, pathParts.length - 1).join(seperator)
, imgBuffer = new Buffer(fs.readFileSync(filePath+seperator+fileName)).toString('base64')
, urlData = 'url(data:' + mimetype + ';base64,' + imgBuffer + ')'

return props.replace(/url\([^\)]*\)/, urlData)
}

return props
}

module.exports.on = function () {
path = this.path
toCSS = less.tree.Value.prototype.toCSS
less.tree.Value.prototype.toCSS = compile
}

module.exports.off = function () {
less.tree.Value.prototype.toCSS = toCSS
}
2 changes: 1 addition & 1 deletion lib/core.js
Expand Up @@ -154,7 +154,7 @@ RECESS.prototype = {
Object.keys(this.options).forEach(function (key) {
that.options[key]
&& RECESS.COMPILERS[key]
&& RECESS.COMPILERS[key].on()
&& RECESS.COMPILERS[key].on.call(that)
})

// iterate over defintions and compress them (join with new lines)
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -81,6 +81,7 @@ module.exports.DEFAULTS = RECESS.DEFAULTS = {
, stripColors: false
, watch: false
, zeroUnits: true
, inlineImages: false
}


Expand Down
60 changes: 60 additions & 0 deletions lib/lint/inline-images.js
@@ -0,0 +1,60 @@
// ===================================================
// RECESS
// RULE: Linked images should be embeded.
// ===================================================
// Copyright 2012 Twitter, Inc
// Licensed under the Apache License v2.0
// http://www.apache.org/licenses/LICENSE-2.0
// ===================================================

'use strict'

var util = require('../util')
, RULE = {
type: 'inlineImages'
, exp: /^url\((?!data:)/
, message: 'Linked images should be embeded.'
}

// validation method
module.exports = function (def, data) {

// default validation to true
var isValid = true

// return if no selector to validate
if (!def.rules) return isValid

// loop over selectors
def.rules.forEach(function (rule) {
var extract

// continue to next rule if no url is present
if ( !(rule.value
&& rule.value.is == 'value'
&& RULE.exp.test(rule.value.toCSS({}))) ) return

// calculate line number for the extract
extract = util.getLine(rule.index, data)
extract = util.padLine(extract)

// highlight invalid 0 units
extract += rule.toCSS({}).replace(RULE.exp, function ($1) {
return $1.magenta
})

// set invalid flag to false
isValid = false

// set error object on defintion token
util.throwError(def, {
type: RULE.type
, message: RULE.message
, extract: extract
})

})

// return validation state
return isValid
}
4 changes: 4 additions & 0 deletions lib/lint/strict-property-order.js
Expand Up @@ -95,6 +95,7 @@ var _ = require('underscore')
, 'list-style-type'
, 'list-style-position'
, 'list-style-image'
, 'pointer-events'
, 'cursor'
, 'background'
, 'background-attachment'
Expand Down Expand Up @@ -150,19 +151,22 @@ var _ = require('underscore')
, 'box-pack'
, 'box-shadow'
, 'box-sizing'
, 'table-layout'
, 'animation'
, 'animation-delay'
, 'animation-duration'
, 'animation-iteration-count'
, 'animation-name'
, 'animation-play-state'
, 'animation-timing-function'
, 'animation-fill-mode'
, 'transition'
, 'transition-delay'
, 'transition-duration'
, 'transition-property'
, 'transition-timing-function'
, 'background-clip'
, 'backface-visibility'
, 'resize'
, 'appearance'
, 'user-select'
Expand Down
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{ "name": "recess"
, "description": "A simple, attractive code quality tool for CSS built on top of LESS"
, "version": "1.0.5"
, "version": "1.1.5"
, "author": "Jacob Thornton <jacob@twitter.com> (https://github.com/fat)"
, "keywords": ["css", "lint"]
, "licenses": [ { "type": "Apache-2.0", "url": "http://www.apache.org/licenses/LICENSE-2.0" } ]
Expand Down
5 changes: 0 additions & 5 deletions test/compiled/blog.css
@@ -1,10 +1,5 @@
/* Fat's blog styles */

@font-face {
font-family: "Mistral";
src: url("/fonts/Mistral.ttf");
}

html,
body {
overflow: auto;
Expand Down
15 changes: 15 additions & 0 deletions test/compiled/inline-images.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions test/fixtures/blog.css
@@ -1,10 +1,5 @@
/* Fat's blog styles */

@font-face {
font-family: "Mistral";
src: url("/fonts/Mistral.ttf");
}

html,
body {
overflow: auto;
Expand Down
12 changes: 12 additions & 0 deletions test/fixtures/inline-images.css
@@ -0,0 +1,12 @@
.foo {
background-image: url("sprite.png");
}
.bar {
background: url('sprite.png');
}
.fat {
background: url(sprite.png);
}
.woo {
background: #fff url(../sprite.png) center center no-repeat;
}
Binary file added test/fixtures/sprite.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/sprite.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion test/types/compile.js
Expand Up @@ -4,8 +4,12 @@ var fs = require('fs')
, RECESS = require('../../lib')

fs.readdirSync('test/fixtures').forEach(function (file, index) {
// Ignore anything not a less/css file.
if (file.indexOf('css') === -1 && file.indexOf('less') === -1) {
return
}

RECESS('test/fixtures/' + file, { compile: true }, function (err, fat) {
RECESS('test/fixtures/' + file, { compile: true, inlineImages: true }, function (err, fat) {
file = file.replace(/less$/, 'css')
assert.ok(err == null)
assert.ok(fat.output[0] == fs.readFileSync('test/compiled/' + file, 'utf-8'))
Expand Down
27 changes: 27 additions & 0 deletions test/types/lint.js
Expand Up @@ -227,6 +227,33 @@ var assert = require('assert')
Recess.parse()

assert.notEqual(Recess.output[0], '\u001b[31mParse error\u001b[39m: Cannot read property \'red\' of undefined on line 1');

RECESS.Constructor.prototype.validate = validate

}()

//VALIDATIONS.inlineImage
!function () {

var path = 'test/fixtures/inline-images.css'
, Recess = new RECESS.Constructor()
, validate = RECESS.Constructor.prototype.validate
, def

RECESS.Constructor.prototype.validate = noop

Recess.data = fs.readFileSync(path, 'utf8')

Recess.parse()

def = Recess.definitions[0]

RECESS.Constructor.RULES.inlineImages(def, Recess.data)

assert.ok(def.errors)
assert.equal(def.errors.length, 1, 'one error found')
assert.equal(def.errors[0].type, 'inlineImages')

RECESS.Constructor.prototype.validate = validate

}()
Expand Down

0 comments on commit 2ec6067

Please sign in to comment.