Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

refactored everything into compile function & added more tests

  • Loading branch information...
commit 590f2cd567d586d6e29729034b57ce2a360f4953 1 parent e841121
Chris Khoo authored
3  .npmignore
@@ -2,4 +2,5 @@
2 2 .idea/
3 3 Cakefile
4 4 src/
5   -test/
  5 +test/
  6 +README.md
71 lib/coffee-css.js
... ... @@ -1,27 +1,27 @@
1 1 (function() {
2   - var coffee, fs, getDefaultMixins, util, vm, _;
  2 + var coffee, compileObject, fs, getDefaultMixins, util, vm, _;
3 3 coffee = require('coffee-script');
4 4 fs = require('fs');
5 5 _ = require('underscore');
6 6 util = require('util');
7 7 vm = require('vm');
8   - exports.compileFile = function(options) {
9   - var fileName, settings;
10   - settings = {
11   - afterWriteFile: function(fileName, newFileName) {},
12   - errorWriteFile: function(err, fileName, newFileName) {},
13   - fileName: void 0,
14   - newFilename: void 0
15   - };
16   - if (typeof options === 'string') {
17   - fileName = options;
18   - } else {
19   - _.extend(settings, options);
20   - fileName = settings.fileName;
  8 + exports.compile = function(fileName, newFileName, callback) {
  9 + if (callback == null) {
  10 + callback = function(err, fileName, newFileName) {};
  11 + }
  12 + if (typeof fileName === 'object') {
  13 + return compileObject(fileName, newFileName);
  14 + }
  15 + if (typeof newFileName === 'function') {
  16 + callback = newFileName;
  17 + newFileName = void 0;
21 18 }
22   - return fs.readFile(fileName, function(err, data) {
23   - var css, js, newFileName, sandbox;
24   - try {
  19 + if (newFileName === void 0) {
  20 + newFileName = fileName.replace(/\.css\.coffee$/i, '.css');
  21 + }
  22 + try {
  23 + return fs.readFile(fileName, function(err, data) {
  24 + var css, js, sandbox;
25 25 js = coffee.compile(data.toString().trim());
26 26 sandbox = {
27 27 exports: {
@@ -31,46 +31,51 @@
31 31 require: require
32 32 };
33 33 vm.runInNewContext(js, sandbox);
34   - css = exports.compileObject(sandbox.exports.css, sandbox.exports.mixins);
35   - newFileName = settings.newFilename || fileName.replace(/\.css\.coffee$/i, '.css');
36   - return fs.writeFile(newFileName, css, settings.afterWriteFile(fileName, newFileName));
37   - } catch (err) {
38   - return settings.errorWriteFile(err, fileName, newFileName);
39   - }
40   - });
  34 + css = compileObject(sandbox.exports.css, sandbox.exports.mixins);
  35 + return fs.writeFile(newFileName, css, function(err) {
  36 + if (err) {
  37 + throw err;
  38 + }
  39 + return callback(null, fileName, newFileName);
  40 + });
  41 + });
  42 + } catch (err) {
  43 + return callback(err, fileName, newFileName);
  44 + }
41 45 };
42   - exports.compileObject = function(cssObject, mixins) {
  46 + exports.getDefaultMixins = getDefaultMixins;
  47 + compileObject = function(cssObject, mixins) {
43 48 var compileCssList, outputList;
44 49 mixins || (mixins = getDefaultMixins());
45 50 outputList = [];
46 51 compileCssList = function(cssObject) {
47   - var declarationText, declarations, iterateDeclarations, nestedSelectors, selector, _results;
  52 + var declarationText, declarations, isNested, iterateDeclarations, nestedSelectors, selector, _results;
48 53 _results = [];
49 54 for (selector in cssObject) {
50 55 declarations = cssObject[selector];
51 56 declarationText = [];
52 57 nestedSelectors = {};
  58 + isNested = false;
53 59 iterateDeclarations = function(d) {
54 60 var cssProperty, key, value, _results2;
55 61 _results2 = [];
56 62 for (key in d) {
57 63 value = d[key];
58   - _results2.push(typeof value === 'object' ? nestedSelectors["" + selector + " " + key] = value : mixins[key] ? iterateDeclarations(mixins[key](value)) : (cssProperty = key.replace(/[A-Z]/g, function(s) {
  64 + _results2.push(typeof value === 'object' ? (nestedSelectors["" + selector + " " + key] = value, isNested = true) : mixins[key] ? iterateDeclarations(mixins[key](value)) : (cssProperty = key.replace(/[A-Z]/g, function(s) {
59 65 return '-' + s.toLowerCase();
60   - }), declarationText.push(" " + cssProperty + ": " + value + ";")));
  66 + }), declarationText.push(" " + cssProperty + ": " + value + ";")));
61 67 }
62 68 return _results2;
63 69 };
64 70 iterateDeclarations(declarations);
65 71 outputList.push("" + selector + " {\n" + (declarationText.join('\n')) + "\n}");
66   - _results.push(compileCssList(nestedSelectors));
  72 + _results.push(isNested ? compileCssList(nestedSelectors) : void 0);
67 73 }
68 74 return _results;
69 75 };
70 76 compileCssList(cssObject);
71 77 return outputList.join('\n');
72 78 };
73   - exports.getDefaultMixins = getDefaultMixins;
74 79 getDefaultMixins = function() {
75 80 return {
76 81 boxShadowAll: function(value) {
@@ -79,6 +84,12 @@
79 84 MozBoxShadow: value,
80 85 boxShadow: value
81 86 };
  87 + },
  88 + opacityAll: function(value) {
  89 + return {
  90 + filter: 'alpha(opacity=' + (value * 100) + ')',
  91 + opacity: value
  92 + };
82 93 }
83 94 };
84 95 };
2  package.json
@@ -2,7 +2,7 @@
2 2 "name": "coffee-css",
3 3 "description": "More CSS for CoffeeScript",
4 4 "author": "khoomeister",
5   - "version": "0.0.3",
  5 + "version": "0.0.4",
6 6 "licenses": [{
7 7 "type": "MIT",
8 8 "url": "https://github.com/aeosynth/ccss/raw/master/LICENSE"
56 src/coffee-css.coffee
@@ -6,21 +6,19 @@ util = require 'util'
6 6 vm = require 'vm'
7 7
8 8 # public functions
9   -exports.compileFile = (options) ->
10   - settings =
11   - afterWriteFile: (fileName, newFileName) ->
12   - errorWriteFile: (err, fileName, newFileName) ->
13   - fileName: undefined
14   - newFilename: undefined
  9 +exports.compile = (fileName, newFileName, callback = (err, fileName, newFileName) ->) ->
  10 + if typeof fileName is 'object'
  11 + # assume compile object (cssObject, mixins)
  12 + return compileObject fileName, newFileName
15 13
16   - if typeof options is 'string'
17   - fileName = options
18   - else
19   - _.extend settings, options
20   - fileName = settings.fileName
  14 + if typeof newFileName is 'function'
  15 + callback = newFileName
  16 + newFileName = undefined
  17 + if newFileName is undefined
  18 + newFileName = fileName.replace /\.css\.coffee$/i, '.css'
21 19
22   - fs.readFile fileName, (err, data) ->
23   - try
  20 + try
  21 + fs.readFile fileName, (err, data) ->
24 22 js = coffee.compile(data.toString().trim())
25 23 sandbox =
26 24 exports:
@@ -28,13 +26,18 @@ exports.compileFile = (options) ->
28 26 mixins: getDefaultMixins()
29 27 require: require
30 28 vm.runInNewContext js, sandbox
31   - css = exports.compileObject sandbox.exports.css, sandbox.exports.mixins
32   - newFileName = settings.newFilename || fileName.replace /\.css\.coffee$/i, '.css'
33   - fs.writeFile newFileName, css, settings.afterWriteFile(fileName, newFileName)
34   - catch err
35   - settings.errorWriteFile(err, fileName, newFileName)
  29 +
  30 + css = compileObject sandbox.exports.css, sandbox.exports.mixins
  31 + fs.writeFile newFileName, css, (err) ->
  32 + if err then throw err
  33 + callback null, fileName, newFileName
  34 + catch err
  35 + callback err, fileName, newFileName
36 36
37   -exports.compileObject = (cssObject, mixins) ->
  37 +exports.getDefaultMixins = getDefaultMixins
  38 +
  39 +# privates
  40 +compileObject = (cssObject, mixins) ->
38 41 mixins or= getDefaultMixins()
39 42 outputList = []
40 43
@@ -42,30 +45,33 @@ exports.compileObject = (cssObject, mixins) ->
42 45 for selector, declarations of cssObject
43 46 declarationText = []
44 47 nestedSelectors = {}
  48 + isNested = false
45 49
46 50 iterateDeclarations = (d) ->
47 51 for key, value of d
48 52 if typeof value is 'object'
49 53 nestedSelectors["#{selector} #{key}"] = value
  54 + isNested = true
50 55 else
51 56 if mixins[key]
52 57 iterateDeclarations mixins[key](value)
53 58 else
54 59 cssProperty = key.replace /[A-Z]/g, (s) -> '-' + s.toLowerCase()
55   - declarationText.push " #{cssProperty}: #{value};"
  60 + declarationText.push " #{cssProperty}: #{value};"
56 61
57 62 iterateDeclarations declarations
58 63 outputList.push "#{selector} {\n#{declarationText.join('\n')}\n}"
59   - compileCssList nestedSelectors
  64 + if isNested
  65 + compileCssList nestedSelectors
60 66
61 67 compileCssList cssObject
62 68 outputList.join '\n'
63 69
64   -exports.getDefaultMixins = getDefaultMixins
65   -
66   -# privates
67 70 getDefaultMixins = ->
68 71 boxShadowAll: (value) ->
69 72 WebkitBoxShadow: value
70 73 MozBoxShadow: value
71   - boxShadow: value
  74 + boxShadow: value
  75 + opacityAll: (value) ->
  76 + filter: 'alpha(opacity=' + (value * 100) + ')'
  77 + opacity: value
106 test/test.coffee
... ... @@ -1,33 +1,101 @@
1 1 # requires
2   -require 'should'
3   -
4 2 coffeeCss = require '../lib/coffee-css'
5 3 fs = require 'fs'
6 4 path = require 'path'
  5 +should = require 'should'
7 6
8   -# functions
9   -compileCssTest = ->
10   - coffeeCss.compileFile
11   - fileName: __dirname + '/test.css.coffee'
  7 +# constants
  8 +COFFEE_CSS_SAMPLE_FILE_DATA = """
  9 + exports.css =
  10 + 'a':
  11 + textDecoration: 'none'
  12 + 'a:hover':
  13 + textDecoration: 'underline'
  14 + """
12 15
13 16 # tests
14 17 exports.testBoxShadowAll = ->
15   - css = coffeeCss.compileObject
  18 + css = coffeeCss.compile
16 19 div:
17 20 boxShadowAll: '5px'
18 21 css.should.equal """
19 22 div {
20   - -webkit-box-shadow: 5px;
21   - -moz-box-shadow: 5px;
22   - box-shadow: 5px;
  23 + -webkit-box-shadow: 5px;
  24 + -moz-box-shadow: 5px;
  25 + box-shadow: 5px;
  26 + }
  27 + """
  28 +
  29 +exports.testCustomMixins = ->
  30 + cssObject =
  31 + div:
  32 + boxShadowAll: '5px'
  33 + marginAndPadding: '10px'
  34 + css = coffeeCss.compile cssObject,
  35 + marginAndPadding: (value) ->
  36 + margin: value
  37 + padding: value
  38 +
  39 + css.should.equal """
  40 + div {
  41 + box-shadow-all: 5px;
  42 + margin: 10px;
  43 + padding: 10px;
  44 + }
  45 + """
  46 +
  47 +exports.testNestedObject = ->
  48 + css = coffeeCss.compile
  49 + form:
  50 + margin: '5px'
  51 +
  52 + input:
  53 + border: '1px solid #000'
  54 +
  55 + button:
  56 + backgroundColor: '#ddd'
  57 +
  58 + css.should.equal """
  59 + form {
  60 + margin: 5px;
  61 + }
  62 + form input {
  63 + border: 1px solid #000;
  64 + }
  65 + form button {
  66 + background-color: #ddd;
  67 + }
  68 + """
  69 +
  70 +exports.testOpacityAll = ->
  71 + css = coffeeCss.compile
  72 + div:
  73 + opacityAll: 0.25
  74 + css.should.equal """
  75 + div {
  76 + filter: alpha(opacity=25);
  77 + opacity: 0.25;
23 78 }
24 79 """
25   -
26   -exports.compileWorks = ->
27   - cssFile = __dirname + '/test.css'
28   - path.exists cssFile, (exists) ->
29   - if exists
30   - fs.unlink cssFile, (err) ->
31   - compileCssTest()
32   - else
33   - compileCssTest()
  80 +
  81 +exports.testCompileFile = ->
  82 + coffeeCssFile = __dirname + '/testFile.css.coffee'
  83 + data = COFFEE_CSS_SAMPLE_FILE_DATA
  84 +
  85 + fs.writeFile coffeeCssFile, data, (err) ->
  86 + coffeeCss.compile coffeeCssFile, (err, fileName, newFileName) ->
  87 + should.not.exist err
  88 + fileName.should.equal coffeeCssFile
  89 + newFileName.should.equal __dirname + '/testFile.css'
  90 +
  91 + fs.readFile newFileName, (err, data) ->
  92 + data.toString().should.equal """
  93 + a {
  94 + text-decoration: none;
  95 + }
  96 + a:hover {
  97 + text-decoration: underline;
  98 + }
  99 + """
  100 + fs.unlink fileName
  101 + fs.unlink newFileName
30 test/test.css
... ... @@ -1,30 +0,0 @@
1   -a {
2   - text-decoration: none;
3   -}
4   -a:hover {
5   - text-decoration: underline;
6   -}
7   -form {
8   - border-radius: 5px;
9   - -webkit-box-shadow: 5px;
10   - -moz-box-shadow: 5px;
11   - box-shadow: 5px;
12   - opacity: 1;
13   - padding: 10px;
14   -}
15   -form input {
16   - border: 1px solid #fff;
17   - padding: 5px;
18   -}
19   -form button {
20   - padding: 5px 0 5px;
21   -}
22   -#id .className {
23   - opacity: 1;
24   -}
25   -img {
26   - opacity: 1;
27   -}
28   -img:hover {
29   - opacity: 0.8;
30   -}
23 test/test.css.coffee
... ... @@ -1,23 +0,0 @@
1   -exports.css =
2   - 'a':
3   - textDecoration: 'none'
4   - 'a:hover':
5   - textDecoration: 'underline'
6   - 'form':
7   - borderRadius: '5px',
8   - boxShadowAll: '5px'
9   - opacity: 1
10   - padding: '10px'
11   -
12   - input:
13   - border: '1px solid #fff'
14   - padding: '5px'
15   -
16   - button:
17   - padding: '5px 0 5px'
18   - '#id .className':
19   - opacity: 1
20   - 'img':
21   - opacity: 1
22   - 'img:hover':
23   - opacity: 0.8

0 comments on commit 590f2cd

Please sign in to comment.
Something went wrong with that request. Please try again.