sqwish 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +25 -0
- data/lib/sqwish.rb +25 -0
- data/sqwish/README.md +53 -0
- data/sqwish/src/index.js +127 -0
- metadata +81 -0
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Sqwish-ruby
|
2
|
+
#### A CSS compressor
|
3
|
+
|
4
|
+
This as a Ruby bridge to [Sqwish](https://github.com/ded/sqwish) by Dustin
|
5
|
+
Diaz. Just install it:
|
6
|
+
|
7
|
+
$ gem install sqwish
|
8
|
+
|
9
|
+
And use it like so:
|
10
|
+
|
11
|
+
require 'sqwish'
|
12
|
+
Sqwish.minify "div { color: red; } div { background: black; }"
|
13
|
+
#=> "div{color:red;background:black}"
|
14
|
+
|
15
|
+
You can also use the `strict: false` flag (it defaults to true):
|
16
|
+
|
17
|
+
Sqwish.minify "div { color: red; } div { background: black; }", strict: false
|
18
|
+
#=> "div{color:red}div{background:black}"
|
19
|
+
|
20
|
+
## Authors
|
21
|
+
|
22
|
+
* **Sqwish** is by Dustin Diaz @ [github.com/ded/sqwish](https://github.com/ded/sqwish).
|
23
|
+
* This Ruby gem is by Rico Sta. Cruz @ [github.com/rstacruz/sqwish.rb](http://github.com/rstacruz/sqwish.rb).github.com/rstacruz/sqwish.rb).
|
24
|
+
|
25
|
+
MIT.
|
data/lib/sqwish.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'execjs'
|
2
|
+
|
3
|
+
module Sqwish
|
4
|
+
class << self
|
5
|
+
def minify(src, options={:strict => true})
|
6
|
+
sqwish_js.call "sqwish", src, !! options[:strict]
|
7
|
+
end
|
8
|
+
|
9
|
+
def sqwish_js
|
10
|
+
@squish_js ||= ExecJS.compile(sqwish_src)
|
11
|
+
end
|
12
|
+
|
13
|
+
def sqwish_src
|
14
|
+
open(sqwish_js_path).read
|
15
|
+
end
|
16
|
+
|
17
|
+
def sqwish_js_path
|
18
|
+
File.expand_path '../../sqwish/src/index.js', __FILE__
|
19
|
+
end
|
20
|
+
|
21
|
+
def version
|
22
|
+
"0.0.1"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/sqwish/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
Welcome to Sqwish
|
2
|
+
----------
|
3
|
+
A [Node](http://nodejs.org) based CSS Compressor. It works like this.
|
4
|
+
|
5
|
+
require('sqwish').minify('body { color: #ff33cc; }');
|
6
|
+
// =>
|
7
|
+
body{color:#f3c}
|
8
|
+
|
9
|
+
CLI
|
10
|
+
---
|
11
|
+
Install it.
|
12
|
+
|
13
|
+
$ npm install sqwish
|
14
|
+
|
15
|
+
Use it like this:
|
16
|
+
|
17
|
+
sqwish css/styles.css -o css/prod-styles.min.css
|
18
|
+
|
19
|
+
Notes
|
20
|
+
-------
|
21
|
+
Sqwish does not attempt to fix invalid CSS, therefore, at minimum, your CSS should at least follow the basic rules:
|
22
|
+
|
23
|
+
selectors[,more selectors] {
|
24
|
+
property: value;
|
25
|
+
another-property: another value;
|
26
|
+
}
|
27
|
+
|
28
|
+
Strict Optimizations
|
29
|
+
----------
|
30
|
+
Aside from regular minification, in <code>--strict</code> mode Sqwish will combines duplicate selectors and merge duplicate properties.
|
31
|
+
|
32
|
+
// before
|
33
|
+
div {
|
34
|
+
color: orange;
|
35
|
+
background: red;
|
36
|
+
}
|
37
|
+
div {
|
38
|
+
color: #ff33cc;
|
39
|
+
margin: 0px;
|
40
|
+
}
|
41
|
+
|
42
|
+
// after
|
43
|
+
div{color:#f3c;background:red;margin:0}
|
44
|
+
|
45
|
+
This mode can be enabled as so:
|
46
|
+
|
47
|
+
sqwish.minify(css, true);
|
48
|
+
|
49
|
+
on the command line
|
50
|
+
|
51
|
+
sqwish styles.css --strict
|
52
|
+
|
53
|
+
Happy Sqwishing!
|
data/sqwish/src/index.js
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
/*!
|
2
|
+
* Sqwish - a CSS Compressor
|
3
|
+
* Copyright Dustin Diaz 2011
|
4
|
+
* https://github.com/ded/sqwish
|
5
|
+
* License MIT
|
6
|
+
*/
|
7
|
+
|
8
|
+
var fs = require('fs');
|
9
|
+
|
10
|
+
function uniq(ar) {
|
11
|
+
var a = [], i, j;
|
12
|
+
label:
|
13
|
+
for (i = ar.length - 1; i >= 0; i--) {
|
14
|
+
for (j = a.length - 1; j >= 0; j--) {
|
15
|
+
if (a[j] == ar[i]) {
|
16
|
+
continue label;
|
17
|
+
}
|
18
|
+
}
|
19
|
+
a[a.length] = ar[i];
|
20
|
+
}
|
21
|
+
return a;
|
22
|
+
}
|
23
|
+
|
24
|
+
function sqwish(css, strict) {
|
25
|
+
// allow /*! bla */ style comments to retain copyrights etc.
|
26
|
+
var comments = css.match(/\/\*![\s\S]+?\*\//g);
|
27
|
+
|
28
|
+
css = css.trim() // give it a solid trimming to start
|
29
|
+
|
30
|
+
// comments
|
31
|
+
.replace(/\/\*[\s\S]+?\*\//g, '')
|
32
|
+
|
33
|
+
// line breaks and carriage returns
|
34
|
+
.replace(/[\n\r]/g, '')
|
35
|
+
|
36
|
+
// space between selectors, declarations, properties and values
|
37
|
+
.replace(/\s*([:;,{}])\s*/g, '$1')
|
38
|
+
|
39
|
+
// replace multiple spaces with single spaces
|
40
|
+
.replace(/\s+/g, ' ')
|
41
|
+
|
42
|
+
// space between last declaration and end of rule
|
43
|
+
// also remove trailing semi-colons on last declaration
|
44
|
+
.replace(/;}/g, '}')
|
45
|
+
|
46
|
+
// this is important
|
47
|
+
.replace(/\s+(!important)/g, '$1')
|
48
|
+
|
49
|
+
// convert longhand hex to shorthand hex
|
50
|
+
.replace(/#([a-fA-F0-9])\1([a-fA-F0-9])\2([a-fA-F0-9])\3/g, '#$1$2$3')
|
51
|
+
|
52
|
+
// replace 0px with 0
|
53
|
+
.replace(/([\s|:])[0]+px/g, '$10');
|
54
|
+
|
55
|
+
if (strict) {
|
56
|
+
css = strict_css(css);
|
57
|
+
}
|
58
|
+
|
59
|
+
// put back in copyrights
|
60
|
+
if (comments) {
|
61
|
+
comments = comments ? comments.join('\n') : '';
|
62
|
+
css = comments + '\n' + css;
|
63
|
+
}
|
64
|
+
return css;
|
65
|
+
}
|
66
|
+
|
67
|
+
function strict_css(css) {
|
68
|
+
// now some super fun funky shit where we remove duplicate declarations
|
69
|
+
// into combined rules
|
70
|
+
|
71
|
+
// store global dict of all rules
|
72
|
+
var ruleList = {},
|
73
|
+
rules = css.match(/([^{]+\{[^}]+\})+?/g);
|
74
|
+
|
75
|
+
// lets find the dups
|
76
|
+
rules.forEach(function (rule) {
|
77
|
+
// break rule into selector|declaration parts
|
78
|
+
var parts = rule.match(/([^{]+)\{([^}]+)/),
|
79
|
+
selector = parts[1],
|
80
|
+
declarations = parts[2];
|
81
|
+
|
82
|
+
// start new list if it wasn't created already
|
83
|
+
if (!ruleList[selector]) {
|
84
|
+
ruleList[selector] = [];
|
85
|
+
}
|
86
|
+
|
87
|
+
declarations = declarations.split(';');
|
88
|
+
// filter out duplicate properties
|
89
|
+
ruleList[selector] = ruleList[selector].filter(function (decl) {
|
90
|
+
var prop = decl.match(/[^:]+/)[0];
|
91
|
+
// pre-existing properties are not wanted anymore
|
92
|
+
return !declarations.some(function (dec) {
|
93
|
+
// must include '^' as to not confuse "color" with "border-color" etc.
|
94
|
+
return dec.match(new RegExp('^' + prop + ':'));
|
95
|
+
});
|
96
|
+
});
|
97
|
+
|
98
|
+
// latter takes presedence :)
|
99
|
+
ruleList[selector] = ruleList[selector].concat(declarations);
|
100
|
+
// still dups? just in case
|
101
|
+
ruleList[selector] = uniq(ruleList[selector]);
|
102
|
+
});
|
103
|
+
|
104
|
+
// reset css because we're gonna recreate the whole shabang.
|
105
|
+
css = '';
|
106
|
+
for (var selector in ruleList) {
|
107
|
+
var joinedRuleList = ruleList[selector].join(';');
|
108
|
+
css += selector + '{' + (joinedRuleList).replace(/;$/, '') + '}';
|
109
|
+
}
|
110
|
+
return css;
|
111
|
+
}
|
112
|
+
|
113
|
+
module.exports.exec = function (args) {
|
114
|
+
var out;
|
115
|
+
var read = args[0];
|
116
|
+
if (out = args.indexOf('-o') != -1) {
|
117
|
+
out = args[out + 1];
|
118
|
+
} else {
|
119
|
+
out = read.replace(/\.css$/, '.min.css');
|
120
|
+
}
|
121
|
+
console.log('compressing ' + read + ' to ' + out + '...');
|
122
|
+
var data = fs.readFileSync(read, 'utf8');
|
123
|
+
fs.writeFileSync(out, sqwish(data, (args.indexOf('--strict') != -1)), 'utf8');
|
124
|
+
};
|
125
|
+
module.exports.minify = function (css, strict) {
|
126
|
+
return sqwish(css, strict);
|
127
|
+
};
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sqwish
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Rico Sta. Cruz
|
13
|
+
- Dustin Diaz
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-26 00:00:00 +08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: execjs
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: Compresses CSS.
|
35
|
+
email:
|
36
|
+
- rico@sinefunc.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/sqwish.rb
|
45
|
+
- sqwish/README.md
|
46
|
+
- sqwish/src/index.js
|
47
|
+
- README.md
|
48
|
+
has_rdoc: true
|
49
|
+
homepage: http://github.com/rstacruz/sqwish
|
50
|
+
licenses: []
|
51
|
+
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.3.7
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: A node-based CSS compressor
|
80
|
+
test_files: []
|
81
|
+
|