css_modules 0.1.0 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 431374aa2a26649b2dac684cf81efe66e419c84c
4
- data.tar.gz: 2dffe66a072a52b0c60074940be0774a6513e7a1
3
+ metadata.gz: dce9ca6ecb86907f4b2b6dd0b19eed2769d56f8a
4
+ data.tar.gz: ef5476565fb76bb21618521dbe9e7e57c0adbef0
5
5
  SHA512:
6
- metadata.gz: b89042953316ab3a5b1b17c7c46eb5d2882e529415f5fb7a1c5247d3628ca1cd11aa796b09c9d0318c89578fe384a896f014d124f3f5616d07047b073fcc4c5f
7
- data.tar.gz: 9c6387bfb0e5b68e7f5879c2999e4cd994c1b3ddfa03449ac18b5213f276ca7bff7f6c4abe9227732f8430134f68a59d2db39673594b9128fc2f992d3656dc5e
6
+ metadata.gz: 386082a080e70bef2535c1bb7730f6203969f8d7655563572b427ffffbbcb96d197ac638e2a4abf8db14bbaaf50529ac414073e7703e8fa0f1ad10d397e79b38
7
+ data.tar.gz: fee03dea66978d5af49efb5a68b0702e0fc85ccfb8d1cca2ad683358dec4c325f6acfc13276bea7981c2f8b7503888a5a3f6111724e57254f280837f483587d6
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # CSSModules
2
2
 
3
+ [![Build Status](https://travis-ci.org/rmosolgo/css_modules.svg?branch=master)](https://travis-ci.org/rmosolgo/css_modules)
4
+ [![Gem Version](https://badge.fury.io/rb/css_modules.svg)](https://badge.fury.io/rb/css_modules)
5
+
3
6
  An alternative to "magic string" classnames in Sass or SCSS. Currently supports Sprockets 2 only 😖.
4
7
 
5
8
  Thanks to [Fatih Kadir Akın](https://twitter.com/fkadev) for his post, ["How I Implemented CSS Modules in Ruby on Rails, Easily"](https://medium.com/@fkadev/how-i-implemented-css-modules-to-ruby-on-rails-easily-abb324ce22d), which led the way on this idea!
@@ -118,6 +121,8 @@ $ gem install css_modules
118
121
  - Support plain `.css`
119
122
  - Use Sass's built-in parser?
120
123
  - Support Sprockets 3+
124
+ - Check for hash collisions in development
125
+ - Fix bundle cache
121
126
 
122
127
  ## License
123
128
 
@@ -0,0 +1,59 @@
1
+ // Usage:
2
+ //
3
+ // - Call with a module name + selector name to get a transformed (opaque) selector
4
+ //
5
+ // ```js
6
+ // CSSModule("events_index", "header")
7
+ // // => "..." (some opaque string that matches the stylesheet)
8
+ // ```
9
+ //
10
+ // - Call with a module name to get a function for modulizing selectors
11
+ //
12
+ // ```js
13
+ // var eventsModule = CSSModule("events_index")
14
+ // var headerSelector = eventsModule("header")
15
+ // var footerSelector = eventsModule("footer")
16
+ // ```
17
+ //
18
+ // This behavior has to match `CSSModules::Rewrite` in Ruby
19
+ // so that generated selectors match.
20
+ var CSSModule = (function() {
21
+ // This matches Transform.compute_hash in Ruby
22
+ var HASH_LIMIT = 10009;
23
+ var SUM_SIZE = 4;
24
+ function computeHash(inputString) {
25
+ var bytesCount = 0;
26
+ var stringSum = 0;
27
+ var byte;
28
+ for(var i = 0; i < inputString.length; i++) {
29
+ byte = inputString.charCodeAt(i);
30
+ stringSum += (byte * Math.pow(256, bytesCount))
31
+ bytesCount += 1;
32
+ bytesCount %= SUM_SIZE;
33
+ }
34
+
35
+ return stringSum % HASH_LIMIT;
36
+ };
37
+
38
+ function modulizeSelector(moduleName, selectorName, environment) {
39
+ if (environment === "production") {
40
+ return moduleName.substr(0, 1) + computeHash(moduleName + selectorName) + selectorName.substr(0, 1);
41
+ } else {
42
+ return moduleName + "_" + computeHash(moduleName + selectorName) + "_" + selectorName;
43
+ }
44
+ }
45
+
46
+ function _CSSModule(moduleName, selectorName, environment) {
47
+ environment || (environment = "<% Rails.env %>")
48
+
49
+ if (selectorName) {
50
+ return modulizeSelector(moduleName, selectorName, environment);
51
+ } else {
52
+ return function(selectorName) {
53
+ return modulizeSelector(moduleName, selectorName, environment);
54
+ };
55
+ }
56
+ };
57
+
58
+ return _CSSModule;
59
+ })();
@@ -1,5 +1,5 @@
1
1
  require "css_parser"
2
- require "base64"
2
+ require "css_modules/transform"
3
3
 
4
4
  module CSSModules
5
5
  module Rewrite
@@ -30,9 +30,12 @@ module CSSModules
30
30
 
31
31
  # Combine `module_name` and `selector`, but don't prepend a `.` or `#`
32
32
  # because this value will be inserted into the HTML page as `class=` or `id=`
33
+ # @param module_name [String] A CSS module name
34
+ # @param selector [String] A would-be DOM selector (without the leading `.` or `#`)
35
+ # @return [String] An opaque selector for this module-selector pair
33
36
  def modulize_selector(module_name, selector)
34
- transformed_name = transform_name(module_name)
35
- "#{transformed_name}_#{selector}"
37
+ tran = Rails.env.production? ? Transform::ProductionTransform : Transform::DevelopmentTransform
38
+ tran.transform(module_name, selector)
36
39
  end
37
40
 
38
41
  private
@@ -44,7 +47,7 @@ module CSSModules
44
47
  if matches.nil?
45
48
  selector
46
49
  else
47
- module_name = transform_name(matches[:module_name])
50
+ module_name = matches[:module_name]
48
51
  declaration_parts = matches[:declarations].split(" ")
49
52
  declaration_parts
50
53
  .map { |declaration_or_operator| rebuild_selector(module_name, declaration_or_operator) }
@@ -57,19 +60,12 @@ module CSSModules
57
60
  def rebuild_selector(module_ident, selector)
58
61
  case selector[0]
59
62
  when "#"
60
- "##{module_ident}_#{selector[1..-1]}"
63
+ "##{modulize_selector(module_ident, selector[1..-1])}"
61
64
  when "."
62
- ".#{module_ident}_#{selector[1..-1]}"
65
+ ".#{modulize_selector(module_ident, selector[1..-1])}"
63
66
  else
64
67
  selector
65
68
  end
66
69
  end
67
-
68
- def transform_name(css_module_name)
69
- # Some base64 characters aren't valid for CSS (eg, `=`)
70
- opaque_string = Base64.encode64(css_module_name).gsub(/[^a-zA-Z0-9]/, "")
71
- # p [css_module_name, opaque_string]
72
- "#{opaque_string}_#{css_module_name}"
73
- end
74
70
  end
75
71
  end
@@ -0,0 +1,38 @@
1
+ module CSSModules
2
+ module Transform
3
+ # Hash outputs will be within the range `0..HASH_LIMIT-1`
4
+ HASH_LIMIT = 10009
5
+ # How big of a chunk should we use for folding over the string?
6
+ SUM_SIZE = 4
7
+
8
+ # Generate a short, random-ish token for `input_string`.
9
+ # This has to be replicable in JS.
10
+ # Ruby's `#hash` is randomly seeded, so we can't reuse that!
11
+ # @param input_string [String] A string to hash
12
+ # @return [String] a deterministic output for `input_string`
13
+ def self.compute_hash(input_string)
14
+ bytes_count = 0
15
+ string_sum = 0
16
+
17
+ input_string.each_byte do |byte|
18
+ string_sum += byte * (256 ** bytes_count)
19
+ bytes_count += 1
20
+ bytes_count %= SUM_SIZE
21
+ end
22
+
23
+ string_sum % HASH_LIMIT
24
+ end
25
+
26
+ module DevelopmentTransform
27
+ def self.transform(module_name, selector_name)
28
+ "#{module_name}_#{Transform.compute_hash(module_name + selector_name)}_#{selector_name}"
29
+ end
30
+ end
31
+
32
+ module ProductionTransform
33
+ def self.transform(module_name, selector_name)
34
+ "#{module_name[0]}#{Transform.compute_hash(module_name + selector_name)}#{selector_name[0]}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module CSSModules
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: css_modules
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
@@ -78,9 +78,10 @@ files:
78
78
  - Rakefile
79
79
  - lib/css_modules.rb
80
80
  - lib/css_modules/assets/base64.js
81
- - lib/css_modules/assets/css_module.js
81
+ - lib/css_modules/assets/css_module.js.erb
82
82
  - lib/css_modules/engine.rb
83
83
  - lib/css_modules/rewrite.rb
84
+ - lib/css_modules/transform.rb
84
85
  - lib/css_modules/version.rb
85
86
  - lib/css_modules/view_helper.rb
86
87
  homepage: https://github.com/rmosolgo/css_modules
@@ -1,31 +0,0 @@
1
- // Usage:
2
- //
3
- // - Call with a module name + selector name to get a transformed (opaque) selector
4
- //
5
- // ```js
6
- // CSSModule("events_index", "header")
7
- // // => "..." (some opaque string that matches the stylesheet)
8
- // ```
9
- //
10
- // - Call with a module name to get a function for modulizing selectors
11
- //
12
- // ```js
13
- // var eventsModule = CSSModule("events_index")
14
- // var headerSelector = eventsModule("header")
15
- // var footerSelector = eventsModule("footer")
16
- // ```
17
- //
18
- // This behavior has to match `CSSModules::Rewrite` in Ruby
19
- // so that generated selectors match.
20
- function CSSModule(moduleName, selectorName) {
21
- // This matches `Rewrite`:
22
- var opaqueString = btoa(moduleName).replace(/[^a-zA-Z0-9]/g, "")
23
- var transformedModuleName = opaqueString + "_" + moduleName;
24
- if (selectorName) {
25
- return transformedModuleName + "_" + selectorName;
26
- } else {
27
- return function(selectorName) {
28
- return transformedModuleName + "_" + selectorName;
29
- };
30
- }
31
- };