SassyJSON 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +18 -18
- data/README.md +112 -112
- data/lib/JsonImporter.rb +228 -228
- data/lib/SassyJSON.rb +12 -14
- data/stylesheets/SassyJSON.scss +5 -5
- data/stylesheets/decode/api/_json.scss +26 -26
- data/stylesheets/decode/decode.scss +28 -28
- data/stylesheets/decode/helpers/all/_throw.scss +11 -11
- data/stylesheets/decode/helpers/all/_value.scss +49 -49
- data/stylesheets/decode/helpers/color/_color.scss +50 -50
- data/stylesheets/decode/helpers/color/_get-color-value.scss +22 -22
- data/stylesheets/decode/helpers/color/_hex-to-dec.scss +19 -19
- data/stylesheets/decode/helpers/color/_hex.scss +39 -39
- data/stylesheets/decode/helpers/color/_hsl.scss +46 -46
- data/stylesheets/decode/helpers/color/_rgb.scss +46 -46
- data/stylesheets/decode/helpers/map/_consume.scss +33 -33
- data/stylesheets/decode/helpers/number/_find-digits.scss +39 -39
- data/stylesheets/decode/helpers/number/_find-exponent.scss +51 -51
- data/stylesheets/decode/helpers/number/_find-integer.scss +37 -37
- data/stylesheets/decode/helpers/number/_pow.scss +22 -22
- data/stylesheets/decode/helpers/string/_find-ending-quote.scss +57 -57
- data/stylesheets/decode/helpers/string/_length.scss +42 -42
- data/stylesheets/decode/helpers/string/_strip-token.scss +16 -16
- data/stylesheets/decode/types/_bool.scss +40 -40
- data/stylesheets/decode/types/_list.scss +54 -54
- data/stylesheets/decode/types/_map.scss +78 -78
- data/stylesheets/decode/types/_null.scss +19 -19
- data/stylesheets/decode/types/_number.scss +63 -63
- data/stylesheets/decode/types/_string.scss +41 -41
- data/stylesheets/encode/api/_json.scss +17 -17
- data/stylesheets/encode/encode.scss +17 -17
- data/stylesheets/encode/helpers/_quote.scss +9 -9
- data/stylesheets/encode/mixins/_json.scss +36 -36
- data/stylesheets/encode/types/_bool.scss +9 -9
- data/stylesheets/encode/types/_color.scss +9 -9
- data/stylesheets/encode/types/_list.scss +13 -13
- data/stylesheets/encode/types/_map.scss +13 -13
- data/stylesheets/encode/types/_null.scss +9 -9
- data/stylesheets/encode/types/_number.scss +9 -9
- data/stylesheets/encode/types/_string.scss +9 -9
- metadata +8 -10
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8c767cc7d4815295989917dffc2c37a090b40726
|
4
|
+
data.tar.gz: dd04982601e4a24085741e479024a7fe0afdff15
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6e98df2f7645642b6d9a650e84bf54a7a8cb6881725e3ab6d46cb5ad88153c64e5eb2614834267609ced30a6d97be6f06173fefc80f1bb1b5d15d00a91e14318
|
7
|
+
data.tar.gz: c5b1004ba0f86565ee51c367730d23a8cd7cff70188907de4234bbdb2ee4e1ad606d49195ec923902d5bdd22bb35fd43f51bee11678cd9264db0bba07e977744
|
data/CHANGELOG.md
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
# Changelog
|
2
|
-
|
3
|
-
* `1.1.1`: fixing a minor issue with the gem
|
4
|
-
* `1.1.0`: adding the ability to import a JSON file
|
5
|
-
* `1.0.11`: fixing an issue with scientific number parsing
|
6
|
-
* `1.0.10`: improving number and string helpers
|
7
|
-
* `1.0.9`: fixing a bug in `_find-exponent`
|
8
|
-
* `1.0.8`: fixing a major issue in Ruby Gem
|
9
|
-
* `1.0.7`: minor fixes and stable Ruby Gem
|
10
|
-
* `1.0.6`: released a Ruby Gem
|
11
|
-
* `1.0.5`: improved the encoding mixin
|
12
|
-
* `1.0.4`: fixed an error in map parsing
|
13
|
-
* `1.0.3`: slightly edited the mixin to dump JSON to CSS
|
14
|
-
* `1.0.2`: fixed an issue with string parsing
|
15
|
-
* `1.0.1`: fixed an issue with alpha color parsing
|
16
|
-
* `1.0.0`: Stable API. `json-encode` and `json-decode`
|
17
|
-
* `0.0.2`: added `json-decode` and test
|
18
|
-
* `0.0.1`: initial commit
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
* `1.1.1`: fixing a minor issue with the gem
|
4
|
+
* `1.1.0`: adding the ability to import a JSON file
|
5
|
+
* `1.0.11`: fixing an issue with scientific number parsing
|
6
|
+
* `1.0.10`: improving number and string helpers
|
7
|
+
* `1.0.9`: fixing a bug in `_find-exponent`
|
8
|
+
* `1.0.8`: fixing a major issue in Ruby Gem
|
9
|
+
* `1.0.7`: minor fixes and stable Ruby Gem
|
10
|
+
* `1.0.6`: released a Ruby Gem
|
11
|
+
* `1.0.5`: improved the encoding mixin
|
12
|
+
* `1.0.4`: fixed an error in map parsing
|
13
|
+
* `1.0.3`: slightly edited the mixin to dump JSON to CSS
|
14
|
+
* `1.0.2`: fixed an issue with string parsing
|
15
|
+
* `1.0.1`: fixed an issue with alpha color parsing
|
16
|
+
* `1.0.0`: Stable API. `json-encode` and `json-decode`
|
17
|
+
* `0.0.2`: added `json-decode` and test
|
18
|
+
* `0.0.1`: initial commit
|
data/README.md
CHANGED
@@ -1,112 +1,112 @@
|
|
1
|
-
# SassyJSON [![NPM version](https://badge.fury.io/js/sassyjson.png)](http://badge.fury.io/js/sassyjson) [![Gem Version](https://badge.fury.io/rb/SassyJSON.png)](http://badge.fury.io/rb/SassyJSON) [![Build Status](https://travis-ci.org/HugoGiraudel/SassyJSON.png?branch=master)](https://travis-ci.org/HugoGiraudel/SassyJSON)
|
2
|
-
|
3
|
-
SassyJSON is a Sass-powered API for JSON. It provides you the classic `json-encode` and `json-decode` directly from your Sass files. We'll leave you the only judges of the point of this.
|
4
|
-
|
5
|
-
## Install
|
6
|
-
|
7
|
-
SassyJSON is available on [npm](https://npmjs.org/) or as a [Ruby Gem](http://rubygems.org/gems/SassyJSON).
|
8
|
-
|
9
|
-
### Git
|
10
|
-
|
11
|
-
``` git
|
12
|
-
git clone https://github.com/HugoGiraudel/SassyJSON.git && cd SassyJSON
|
13
|
-
```
|
14
|
-
|
15
|
-
### npm
|
16
|
-
|
17
|
-
``` bash
|
18
|
-
npm install sassyjson --save-dev
|
19
|
-
```
|
20
|
-
|
21
|
-
### Compass extension
|
22
|
-
|
23
|
-
1. `gem install SassyJSON`
|
24
|
-
2. Add `require 'SassyJSON'` to your `config.rb`
|
25
|
-
3. Import it in your stylesheets with `@import 'SassyJSON'`
|
26
|
-
|
27
|
-
### Sass
|
28
|
-
|
29
|
-
If you only want to play around the code without cloning the repo or using npm, you can find a [single file](https://github.com/HugoGiraudel/SassyJSON/blob/master/dist/_SassyJSON.scss) containing the whole API in the [dist](https://github.com/HugoGiraudel/SassyJSON/tree/master/dist) folder.
|
30
|
-
|
31
|
-
Also, SassyJSON is available at [Sassmeister](http://sassmeister.com/).
|
32
|
-
|
33
|
-
## Example
|
34
|
-
|
35
|
-
### Encoding Sass to JSON
|
36
|
-
|
37
|
-
#### Sass
|
38
|
-
|
39
|
-
``` scss
|
40
|
-
$map: ((a: (1 2 ( b : 1 )), b: ( #444444, false, ( a: 1, b: test ) ), c: (2 3 4 string)));
|
41
|
-
|
42
|
-
@include json-encode($map);
|
43
|
-
```
|
44
|
-
|
45
|
-
#### CSS
|
46
|
-
|
47
|
-
``` css
|
48
|
-
/*! json-encode: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}' */
|
49
|
-
|
50
|
-
body::before {
|
51
|
-
content: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
52
|
-
}
|
53
|
-
|
54
|
-
head {
|
55
|
-
font-family: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
56
|
-
}
|
57
|
-
|
58
|
-
@media -json-encode {
|
59
|
-
json {
|
60
|
-
json: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
61
|
-
}
|
62
|
-
}
|
63
|
-
```
|
64
|
-
|
65
|
-
If you want to restrict the output to only one of the three drivers (comment, media query or regular output) you can pass a flag as the second parameter with one of the four following keywords: `all`, `comment`, `media` or `regular`. Default is `all`.
|
66
|
-
|
67
|
-
### Decoding JSON to Sass
|
68
|
-
|
69
|
-
``` scss
|
70
|
-
$json-decode: json-decode('{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}');
|
71
|
-
// ("a": 1 2 ("b": 1), "b": #444444 false ("a": 1, "b": "test"), "c": 2 3 4 "string")
|
72
|
-
```
|
73
|
-
|
74
|
-
## Importing and decoding a JSON file
|
75
|
-
|
76
|
-
To importe and decode an external `.json` file directly into a Sass variable:
|
77
|
-
|
78
|
-
``` scss
|
79
|
-
@import 'relative/path/to/file.json?variable-name'
|
80
|
-
// Do something with $variable-name
|
81
|
-
```
|
82
|
-
|
83
|
-
**Important:**
|
84
|
-
|
85
|
-
* the path to the JSON file is relative to importing file
|
86
|
-
* the get parameter is the variable name to use it in Sass
|
87
|
-
|
88
|
-
## Requirements
|
89
|
-
|
90
|
-
All you need is a clean version of Sass 3.3. Otherwise it's just pure Sass madness.
|
91
|
-
|
92
|
-
## Development
|
93
|
-
|
94
|
-
### You need
|
95
|
-
|
96
|
-
* [NodeJS](http://nodejs.org)
|
97
|
-
* [Ruby](https://www.ruby-lang.org/)
|
98
|
-
* Sass 3.3 via `gem install sass --pre`
|
99
|
-
* `grunt-cli` via `npm install -g grunt-cli`
|
100
|
-
|
101
|
-
### How to
|
102
|
-
|
103
|
-
1. Fork this repository
|
104
|
-
2. Run `npm install`
|
105
|
-
3. `grunt dev`
|
106
|
-
4. Make your changes + write tests
|
107
|
-
5. Commit + Pull request
|
108
|
-
|
109
|
-
## Credits
|
110
|
-
|
111
|
-
* [Fabrice Weinberg](http://twitter.com/fweinb)
|
112
|
-
* [Hugo Giraudel](http://twitter.com/hugogiraudel)
|
1
|
+
# SassyJSON [![NPM version](https://badge.fury.io/js/sassyjson.png)](http://badge.fury.io/js/sassyjson) [![Gem Version](https://badge.fury.io/rb/SassyJSON.png)](http://badge.fury.io/rb/SassyJSON) [![Build Status](https://travis-ci.org/HugoGiraudel/SassyJSON.png?branch=master)](https://travis-ci.org/HugoGiraudel/SassyJSON)
|
2
|
+
|
3
|
+
SassyJSON is a Sass-powered API for JSON. It provides you the classic `json-encode` and `json-decode` directly from your Sass files. We'll leave you the only judges of the point of this.
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
SassyJSON is available on [npm](https://npmjs.org/) or as a [Ruby Gem](http://rubygems.org/gems/SassyJSON).
|
8
|
+
|
9
|
+
### Git
|
10
|
+
|
11
|
+
``` git
|
12
|
+
git clone https://github.com/HugoGiraudel/SassyJSON.git && cd SassyJSON
|
13
|
+
```
|
14
|
+
|
15
|
+
### npm
|
16
|
+
|
17
|
+
``` bash
|
18
|
+
npm install sassyjson --save-dev
|
19
|
+
```
|
20
|
+
|
21
|
+
### Compass extension
|
22
|
+
|
23
|
+
1. `gem install SassyJSON`
|
24
|
+
2. Add `require 'SassyJSON'` to your `config.rb`
|
25
|
+
3. Import it in your stylesheets with `@import 'SassyJSON'`
|
26
|
+
|
27
|
+
### Sass
|
28
|
+
|
29
|
+
If you only want to play around the code without cloning the repo or using npm, you can find a [single file](https://github.com/HugoGiraudel/SassyJSON/blob/master/dist/_SassyJSON.scss) containing the whole API in the [dist](https://github.com/HugoGiraudel/SassyJSON/tree/master/dist) folder.
|
30
|
+
|
31
|
+
Also, SassyJSON is available at [Sassmeister](http://sassmeister.com/).
|
32
|
+
|
33
|
+
## Example
|
34
|
+
|
35
|
+
### Encoding Sass to JSON
|
36
|
+
|
37
|
+
#### Sass
|
38
|
+
|
39
|
+
``` scss
|
40
|
+
$map: ((a: (1 2 ( b : 1 )), b: ( #444444, false, ( a: 1, b: test ) ), c: (2 3 4 string)));
|
41
|
+
|
42
|
+
@include json-encode($map);
|
43
|
+
```
|
44
|
+
|
45
|
+
#### CSS
|
46
|
+
|
47
|
+
``` css
|
48
|
+
/*! json-encode: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}' */
|
49
|
+
|
50
|
+
body::before {
|
51
|
+
content: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
52
|
+
}
|
53
|
+
|
54
|
+
head {
|
55
|
+
font-family: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
56
|
+
}
|
57
|
+
|
58
|
+
@media -json-encode {
|
59
|
+
json {
|
60
|
+
json: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
61
|
+
}
|
62
|
+
}
|
63
|
+
```
|
64
|
+
|
65
|
+
If you want to restrict the output to only one of the three drivers (comment, media query or regular output) you can pass a flag as the second parameter with one of the four following keywords: `all`, `comment`, `media` or `regular`. Default is `all`.
|
66
|
+
|
67
|
+
### Decoding JSON to Sass
|
68
|
+
|
69
|
+
``` scss
|
70
|
+
$json-decode: json-decode('{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}');
|
71
|
+
// ("a": 1 2 ("b": 1), "b": #444444 false ("a": 1, "b": "test"), "c": 2 3 4 "string")
|
72
|
+
```
|
73
|
+
|
74
|
+
## Importing and decoding a JSON file
|
75
|
+
|
76
|
+
To importe and decode an external `.json` file directly into a Sass variable:
|
77
|
+
|
78
|
+
``` scss
|
79
|
+
@import 'relative/path/to/file.json?variable-name'
|
80
|
+
// Do something with $variable-name
|
81
|
+
```
|
82
|
+
|
83
|
+
**Important:**
|
84
|
+
|
85
|
+
* the path to the JSON file is relative to importing file
|
86
|
+
* the get parameter is the variable name to use it in Sass
|
87
|
+
|
88
|
+
## Requirements
|
89
|
+
|
90
|
+
All you need is a clean version of Sass 3.3. Otherwise it's just pure Sass madness.
|
91
|
+
|
92
|
+
## Development
|
93
|
+
|
94
|
+
### You need
|
95
|
+
|
96
|
+
* [NodeJS](http://nodejs.org)
|
97
|
+
* [Ruby](https://www.ruby-lang.org/)
|
98
|
+
* Sass 3.3 via `gem install sass --pre`
|
99
|
+
* `grunt-cli` via `npm install -g grunt-cli`
|
100
|
+
|
101
|
+
### How to
|
102
|
+
|
103
|
+
1. Fork this repository
|
104
|
+
2. Run `npm install`
|
105
|
+
3. `grunt dev`
|
106
|
+
4. Make your changes + write tests
|
107
|
+
5. Commit + Pull request
|
108
|
+
|
109
|
+
## Credits
|
110
|
+
|
111
|
+
* [Fabrice Weinberg](http://twitter.com/fweinb)
|
112
|
+
* [Hugo Giraudel](http://twitter.com/hugogiraudel)
|
data/lib/JsonImporter.rb
CHANGED
@@ -1,229 +1,229 @@
|
|
1
|
-
require 'sass'
|
2
|
-
|
3
|
-
|
4
|
-
# Monkey Path Sass
|
5
|
-
# Adapted from: https://github.com/chriseppstein/sass-css-importer
|
6
|
-
class Sass::Engine
|
7
|
-
alias initialize_without_json_importer initialize
|
8
|
-
|
9
|
-
def initialize(template, options={})
|
10
|
-
initialize_without_json_importer(template, options)
|
11
|
-
|
12
|
-
json_importer = self.options[:load_paths].find {|lp| lp.is_a?(Sass::Importers::JsonImporter) }
|
13
|
-
|
14
|
-
unless json_importer
|
15
|
-
root = File.dirname(options[:filename] || ".")
|
16
|
-
self.options[:load_paths] << Sass::Importers::JsonImporter.new(root)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
module Sass
|
22
|
-
module Importers
|
23
|
-
# The default importer, used for any strings found in the load path.
|
24
|
-
# Simply loads Sass files from the filesystem using the default logic.
|
25
|
-
class JsonImporter < Base
|
26
|
-
|
27
|
-
attr_accessor :root
|
28
|
-
|
29
|
-
# Creates a new filesystem importer that imports files relative to a given path.
|
30
|
-
#
|
31
|
-
# @param root [String] The root path.
|
32
|
-
# This importer will import files relative to this path.
|
33
|
-
def initialize(root)
|
34
|
-
@root = File.expand_path(root)
|
35
|
-
@same_name_warnings = Set.new
|
36
|
-
end
|
37
|
-
|
38
|
-
# Enable watching of json files in Sass 3.3+
|
39
|
-
def watched_directories
|
40
|
-
[root]
|
41
|
-
end
|
42
|
-
|
43
|
-
# Enable watching of json files in Sass 3.3+
|
44
|
-
def watched_file?(file)
|
45
|
-
file.start_with?(root+File::SEPARATOR) && File.extname(file) == ".json"
|
46
|
-
end
|
47
|
-
# @see Base#find_relative
|
48
|
-
def find_relative(name, base, options)
|
49
|
-
_find(File.dirname(base), name, options)
|
50
|
-
end
|
51
|
-
|
52
|
-
# @see Base#find
|
53
|
-
def find(name, options)
|
54
|
-
_find(@root, name, options)
|
55
|
-
end
|
56
|
-
|
57
|
-
# @see Base#mtime
|
58
|
-
def mtime(name, options)
|
59
|
-
name = strip_varname(name);
|
60
|
-
file, _ = Sass::Util.destructure(find_real_file(@root, name, options))
|
61
|
-
File.mtime(file) if file
|
62
|
-
rescue Errno::ENOENT
|
63
|
-
nil
|
64
|
-
end
|
65
|
-
|
66
|
-
# @see Base#key
|
67
|
-
def key(name, options)
|
68
|
-
name = strip_varname(name);
|
69
|
-
[self.class.name + ":" + File.dirname(File.expand_path(name)),
|
70
|
-
File.basename(name)]
|
71
|
-
end
|
72
|
-
|
73
|
-
# @see Base#to_s
|
74
|
-
def to_s
|
75
|
-
@root
|
76
|
-
end
|
77
|
-
|
78
|
-
def hash
|
79
|
-
@root.hash
|
80
|
-
end
|
81
|
-
|
82
|
-
def eql?(other)
|
83
|
-
root.eql?(other.root)
|
84
|
-
end
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
# If a full uri is passed, this removes the root from it
|
89
|
-
# otherwise returns the name unchanged
|
90
|
-
def remove_root(name)
|
91
|
-
if name.index(@root + "/") == 0
|
92
|
-
name[(@root.length + 1)..-1]
|
93
|
-
else
|
94
|
-
name
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# A hash from file extensions to the syntaxes for those extensions.
|
99
|
-
# The syntaxes must be `:sass` or `:scss`.
|
100
|
-
#
|
101
|
-
# This can be overridden by subclasses that want normal filesystem importing
|
102
|
-
# with unusual extensions.
|
103
|
-
#
|
104
|
-
# @return [{String => Symbol}]
|
105
|
-
def extensions
|
106
|
-
{'json' => :scss}
|
107
|
-
end
|
108
|
-
|
109
|
-
# Given an `@import`ed path, returns an array of possible
|
110
|
-
# on-disk filenames and their corresponding syntaxes for that path.
|
111
|
-
#
|
112
|
-
# @param name [String] The filename.
|
113
|
-
# @return [Array(String, Symbol)] An array of pairs.
|
114
|
-
# The first element of each pair is a filename to look for;
|
115
|
-
# the second element is the syntax that file would be in (`:sass` or `:scss`).
|
116
|
-
def possible_files(name)
|
117
|
-
name = escape_glob_characters(name)
|
118
|
-
dirname, basename, extname = split(name)
|
119
|
-
sorted_exts = extensions.sort
|
120
|
-
syntax = extensions[extname]
|
121
|
-
|
122
|
-
if syntax
|
123
|
-
ret = [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]]
|
124
|
-
else
|
125
|
-
ret = sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
|
126
|
-
end
|
127
|
-
|
128
|
-
# JRuby chokes when trying to import files from JARs when the path starts with './'.
|
129
|
-
ret.map {|f, s| [f.sub(%r{^\./}, ''), s]}
|
130
|
-
end
|
131
|
-
|
132
|
-
def escape_glob_characters(name)
|
133
|
-
name.gsub(/[\*\[\]\{\}\?]/) do |char|
|
134
|
-
"\\#{char}"
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
REDUNDANT_DIRECTORY = %r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}
|
139
|
-
# Given a base directory and an `@import`ed name,
|
140
|
-
# finds an existant file that matches the name.
|
141
|
-
#
|
142
|
-
# @param dir [String] The directory relative to which to search.
|
143
|
-
# @param name [String] The filename to search for.
|
144
|
-
# @return [(String, Symbol)] A filename-syntax pair.
|
145
|
-
def find_real_file(dir, name, options)
|
146
|
-
# on windows 'dir' can be in native File::ALT_SEPARATOR form
|
147
|
-
dir = dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
|
148
|
-
|
149
|
-
found = possible_files(remove_root(name)).map do |f, s|
|
150
|
-
path = (dir == "." || Pathname.new(f).absolute?) ? f : "#{escape_glob_characters(dir)}/#{f}"
|
151
|
-
Dir[path].map do |full_path|
|
152
|
-
full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
|
153
|
-
[Pathname.new(full_path).cleanpath.to_s, s]
|
154
|
-
end
|
155
|
-
end
|
156
|
-
found = Sass::Util.flatten(found, 1)
|
157
|
-
return if found.empty?
|
158
|
-
|
159
|
-
if found.size > 1 && !@same_name_warnings.include?(found.first.first)
|
160
|
-
found.each {|(f, _)| @same_name_warnings << f}
|
161
|
-
relative_to = Pathname.new(dir)
|
162
|
-
if options[:_line]
|
163
|
-
# If _line exists, we're here due to an actual import in an
|
164
|
-
# import_node and we want to print a warning for a user writing an
|
165
|
-
# ambiguous import.
|
166
|
-
candidates = found.map {|(f, _)| " " + Pathname.new(f).relative_path_from(relative_to).to_s}.join("\n")
|
167
|
-
Sass::Util.sass_warn <<WARNING
|
168
|
-
WARNING: On line #{options[:_line]}#{" of #{options[:filename]}" if options[:filename]}:
|
169
|
-
It's not clear which file to import for '@import "#{name}"'.
|
170
|
-
Candidates:
|
171
|
-
#{candidates}
|
172
|
-
For now I'll choose #{File.basename found.first.first}.
|
173
|
-
This will be an error in future versions of Sass.
|
174
|
-
WARNING
|
175
|
-
else
|
176
|
-
# Otherwise, we're here via StalenessChecker, and we want to print a
|
177
|
-
# warning for a user running `sass --watch` with two ambiguous files.
|
178
|
-
candidates = found.map {|(f, _)| " " + File.basename(f)}.join("\n")
|
179
|
-
Sass::Util.sass_warn <<WARNING
|
180
|
-
WARNING: In #{File.dirname(name)}:
|
181
|
-
There are multiple files that match the name "#{File.basename(name)}":
|
182
|
-
#{candidates}
|
183
|
-
WARNING
|
184
|
-
end
|
185
|
-
end
|
186
|
-
found.first
|
187
|
-
end
|
188
|
-
|
189
|
-
# Splits a filename into three parts, a directory part, a basename, and an extension
|
190
|
-
# Only the known extensions returned from the extensions method will be recognized as such.
|
191
|
-
def split(name)
|
192
|
-
extension = nil
|
193
|
-
dirname, basename = File.dirname(name), File.basename(name)
|
194
|
-
if basename =~ /^(.*)\.(#{extensions.keys.map{|e| Regexp.escape(e)}.join('|')})$/
|
195
|
-
basename = $1
|
196
|
-
extension = $2
|
197
|
-
end
|
198
|
-
[dirname, basename, extension]
|
199
|
-
end
|
200
|
-
|
201
|
-
private
|
202
|
-
|
203
|
-
def strip_varname(name)
|
204
|
-
name.include?(".json?") ? name[0..name.rindex("?")-1] : name
|
205
|
-
end
|
206
|
-
|
207
|
-
|
208
|
-
def _find(dir, name, options)
|
209
|
-
if name.include? ".json?"
|
210
|
-
quotePos = name.rindex("?");
|
211
|
-
path = name[0..quotePos-1]
|
212
|
-
varname = name[quotePos+1..-1]
|
213
|
-
|
214
|
-
full_filename, syntax = Sass::Util.destructure(find_real_file(dir, path, options))
|
215
|
-
return unless full_filename && File.readable?(full_filename)
|
216
|
-
|
217
|
-
options[:syntax] = syntax
|
218
|
-
options[:filename] = full_filename
|
219
|
-
options[:importer] = self
|
220
|
-
|
221
|
-
Sass::Engine.new("$#{varname} : json_decode('" + File.read(full_filename) + "');", options)
|
222
|
-
else
|
223
|
-
Sass::Engine.new("$hello:'test';", options)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
end
|
228
|
-
end
|
1
|
+
require 'sass'
|
2
|
+
|
3
|
+
|
4
|
+
# Monkey Path Sass
|
5
|
+
# Adapted from: https://github.com/chriseppstein/sass-css-importer
|
6
|
+
class Sass::Engine
|
7
|
+
alias initialize_without_json_importer initialize
|
8
|
+
|
9
|
+
def initialize(template, options={})
|
10
|
+
initialize_without_json_importer(template, options)
|
11
|
+
|
12
|
+
json_importer = self.options[:load_paths].find {|lp| lp.is_a?(Sass::Importers::JsonImporter) }
|
13
|
+
|
14
|
+
unless json_importer
|
15
|
+
root = File.dirname(options[:filename] || ".")
|
16
|
+
self.options[:load_paths] << Sass::Importers::JsonImporter.new(root)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Sass
|
22
|
+
module Importers
|
23
|
+
# The default importer, used for any strings found in the load path.
|
24
|
+
# Simply loads Sass files from the filesystem using the default logic.
|
25
|
+
class JsonImporter < Base
|
26
|
+
|
27
|
+
attr_accessor :root
|
28
|
+
|
29
|
+
# Creates a new filesystem importer that imports files relative to a given path.
|
30
|
+
#
|
31
|
+
# @param root [String] The root path.
|
32
|
+
# This importer will import files relative to this path.
|
33
|
+
def initialize(root)
|
34
|
+
@root = File.expand_path(root)
|
35
|
+
@same_name_warnings = Set.new
|
36
|
+
end
|
37
|
+
|
38
|
+
# Enable watching of json files in Sass 3.3+
|
39
|
+
def watched_directories
|
40
|
+
[root]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Enable watching of json files in Sass 3.3+
|
44
|
+
def watched_file?(file)
|
45
|
+
file.start_with?(root+File::SEPARATOR) && File.extname(file) == ".json"
|
46
|
+
end
|
47
|
+
# @see Base#find_relative
|
48
|
+
def find_relative(name, base, options)
|
49
|
+
_find(File.dirname(base), name, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @see Base#find
|
53
|
+
def find(name, options)
|
54
|
+
_find(@root, name, options)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @see Base#mtime
|
58
|
+
def mtime(name, options)
|
59
|
+
name = strip_varname(name);
|
60
|
+
file, _ = Sass::Util.destructure(find_real_file(@root, name, options))
|
61
|
+
File.mtime(file) if file
|
62
|
+
rescue Errno::ENOENT
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# @see Base#key
|
67
|
+
def key(name, options)
|
68
|
+
name = strip_varname(name);
|
69
|
+
[self.class.name + ":" + File.dirname(File.expand_path(name)),
|
70
|
+
File.basename(name)]
|
71
|
+
end
|
72
|
+
|
73
|
+
# @see Base#to_s
|
74
|
+
def to_s
|
75
|
+
@root
|
76
|
+
end
|
77
|
+
|
78
|
+
def hash
|
79
|
+
@root.hash
|
80
|
+
end
|
81
|
+
|
82
|
+
def eql?(other)
|
83
|
+
root.eql?(other.root)
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
# If a full uri is passed, this removes the root from it
|
89
|
+
# otherwise returns the name unchanged
|
90
|
+
def remove_root(name)
|
91
|
+
if name.index(@root + "/") == 0
|
92
|
+
name[(@root.length + 1)..-1]
|
93
|
+
else
|
94
|
+
name
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# A hash from file extensions to the syntaxes for those extensions.
|
99
|
+
# The syntaxes must be `:sass` or `:scss`.
|
100
|
+
#
|
101
|
+
# This can be overridden by subclasses that want normal filesystem importing
|
102
|
+
# with unusual extensions.
|
103
|
+
#
|
104
|
+
# @return [{String => Symbol}]
|
105
|
+
def extensions
|
106
|
+
{'json' => :scss}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Given an `@import`ed path, returns an array of possible
|
110
|
+
# on-disk filenames and their corresponding syntaxes for that path.
|
111
|
+
#
|
112
|
+
# @param name [String] The filename.
|
113
|
+
# @return [Array(String, Symbol)] An array of pairs.
|
114
|
+
# The first element of each pair is a filename to look for;
|
115
|
+
# the second element is the syntax that file would be in (`:sass` or `:scss`).
|
116
|
+
def possible_files(name)
|
117
|
+
name = escape_glob_characters(name)
|
118
|
+
dirname, basename, extname = split(name)
|
119
|
+
sorted_exts = extensions.sort
|
120
|
+
syntax = extensions[extname]
|
121
|
+
|
122
|
+
if syntax
|
123
|
+
ret = [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]]
|
124
|
+
else
|
125
|
+
ret = sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
|
126
|
+
end
|
127
|
+
|
128
|
+
# JRuby chokes when trying to import files from JARs when the path starts with './'.
|
129
|
+
ret.map {|f, s| [f.sub(%r{^\./}, ''), s]}
|
130
|
+
end
|
131
|
+
|
132
|
+
def escape_glob_characters(name)
|
133
|
+
name.gsub(/[\*\[\]\{\}\?]/) do |char|
|
134
|
+
"\\#{char}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
REDUNDANT_DIRECTORY = %r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}
|
139
|
+
# Given a base directory and an `@import`ed name,
|
140
|
+
# finds an existant file that matches the name.
|
141
|
+
#
|
142
|
+
# @param dir [String] The directory relative to which to search.
|
143
|
+
# @param name [String] The filename to search for.
|
144
|
+
# @return [(String, Symbol)] A filename-syntax pair.
|
145
|
+
def find_real_file(dir, name, options)
|
146
|
+
# on windows 'dir' can be in native File::ALT_SEPARATOR form
|
147
|
+
dir = dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
|
148
|
+
|
149
|
+
found = possible_files(remove_root(name)).map do |f, s|
|
150
|
+
path = (dir == "." || Pathname.new(f).absolute?) ? f : "#{escape_glob_characters(dir)}/#{f}"
|
151
|
+
Dir[path].map do |full_path|
|
152
|
+
full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
|
153
|
+
[Pathname.new(full_path).cleanpath.to_s, s]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
found = Sass::Util.flatten(found, 1)
|
157
|
+
return if found.empty?
|
158
|
+
|
159
|
+
if found.size > 1 && !@same_name_warnings.include?(found.first.first)
|
160
|
+
found.each {|(f, _)| @same_name_warnings << f}
|
161
|
+
relative_to = Pathname.new(dir)
|
162
|
+
if options[:_line]
|
163
|
+
# If _line exists, we're here due to an actual import in an
|
164
|
+
# import_node and we want to print a warning for a user writing an
|
165
|
+
# ambiguous import.
|
166
|
+
candidates = found.map {|(f, _)| " " + Pathname.new(f).relative_path_from(relative_to).to_s}.join("\n")
|
167
|
+
Sass::Util.sass_warn <<WARNING
|
168
|
+
WARNING: On line #{options[:_line]}#{" of #{options[:filename]}" if options[:filename]}:
|
169
|
+
It's not clear which file to import for '@import "#{name}"'.
|
170
|
+
Candidates:
|
171
|
+
#{candidates}
|
172
|
+
For now I'll choose #{File.basename found.first.first}.
|
173
|
+
This will be an error in future versions of Sass.
|
174
|
+
WARNING
|
175
|
+
else
|
176
|
+
# Otherwise, we're here via StalenessChecker, and we want to print a
|
177
|
+
# warning for a user running `sass --watch` with two ambiguous files.
|
178
|
+
candidates = found.map {|(f, _)| " " + File.basename(f)}.join("\n")
|
179
|
+
Sass::Util.sass_warn <<WARNING
|
180
|
+
WARNING: In #{File.dirname(name)}:
|
181
|
+
There are multiple files that match the name "#{File.basename(name)}":
|
182
|
+
#{candidates}
|
183
|
+
WARNING
|
184
|
+
end
|
185
|
+
end
|
186
|
+
found.first
|
187
|
+
end
|
188
|
+
|
189
|
+
# Splits a filename into three parts, a directory part, a basename, and an extension
|
190
|
+
# Only the known extensions returned from the extensions method will be recognized as such.
|
191
|
+
def split(name)
|
192
|
+
extension = nil
|
193
|
+
dirname, basename = File.dirname(name), File.basename(name)
|
194
|
+
if basename =~ /^(.*)\.(#{extensions.keys.map{|e| Regexp.escape(e)}.join('|')})$/
|
195
|
+
basename = $1
|
196
|
+
extension = $2
|
197
|
+
end
|
198
|
+
[dirname, basename, extension]
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
|
203
|
+
def strip_varname(name)
|
204
|
+
name.include?(".json?") ? name[0..name.rindex("?")-1] : name
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
def _find(dir, name, options)
|
209
|
+
if name.include? ".json?"
|
210
|
+
quotePos = name.rindex("?");
|
211
|
+
path = name[0..quotePos-1]
|
212
|
+
varname = name[quotePos+1..-1]
|
213
|
+
|
214
|
+
full_filename, syntax = Sass::Util.destructure(find_real_file(dir, path, options))
|
215
|
+
return unless full_filename && File.readable?(full_filename)
|
216
|
+
|
217
|
+
options[:syntax] = syntax
|
218
|
+
options[:filename] = full_filename
|
219
|
+
options[:importer] = self
|
220
|
+
|
221
|
+
Sass::Engine.new("$#{varname} : json_decode('" + File.read(full_filename) + "');", options)
|
222
|
+
else
|
223
|
+
Sass::Engine.new("$hello:'test';", options)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
end
|
229
229
|
end
|