sqwish 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. data/README.md +25 -0
  2. data/lib/sqwish.rb +25 -0
  3. data/sqwish/README.md +53 -0
  4. data/sqwish/src/index.js +127 -0
  5. 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!
@@ -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
+