SassyJSON 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +11 -0
- data/README.md +96 -0
- data/lib/SassyJSON.rb +14 -0
- data/src/SassyJSON.scss +2 -0
- data/src/decode/api/_json.scss +26 -0
- data/src/decode/decode.scss +28 -0
- data/src/decode/helpers/all/_throw.scss +11 -0
- data/src/decode/helpers/all/_value.scss +49 -0
- data/src/decode/helpers/color/_color.scss +45 -0
- data/src/decode/helpers/color/_get-color-value.scss +18 -0
- data/src/decode/helpers/color/_hex-to-dec.scss +20 -0
- data/src/decode/helpers/color/_hex.scss +39 -0
- data/src/decode/helpers/color/_hsl.scss +46 -0
- data/src/decode/helpers/color/_rgb.scss +46 -0
- data/src/decode/helpers/map/_consume.scss +33 -0
- data/src/decode/helpers/number/_find-digits.scss +40 -0
- data/src/decode/helpers/number/_find-exponent.scss +46 -0
- data/src/decode/helpers/number/_find-integer.scss +38 -0
- data/src/decode/helpers/number/_pow.scss +22 -0
- data/src/decode/helpers/string/_find-ending-quote.scss +36 -0
- data/src/decode/helpers/string/_length.scss +39 -0
- data/src/decode/helpers/string/_strip-token.scss +16 -0
- data/src/decode/types/_bool.scss +40 -0
- data/src/decode/types/_list.scss +54 -0
- data/src/decode/types/_map.scss +78 -0
- data/src/decode/types/_null.scss +19 -0
- data/src/decode/types/_number.scss +63 -0
- data/src/decode/types/_string.scss +41 -0
- data/src/encode/api/_json.scss +17 -0
- data/src/encode/encode.scss +17 -0
- data/src/encode/helpers/_quote.scss +9 -0
- data/src/encode/mixins/_json.scss +34 -0
- data/src/encode/types/_bool.scss +9 -0
- data/src/encode/types/_color.scss +9 -0
- data/src/encode/types/_list.scss +13 -0
- data/src/encode/types/_map.scss +13 -0
- data/src/encode/types/_null.scss +9 -0
- data/src/encode/types/_number.scss +9 -0
- data/src/encode/types/_string.scss +9 -0
- metadata +119 -0
data/CHANGELOG.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
* `1.0.6`: released a Ruby gem
|
4
|
+
* `1.0.5`: improved the encoding mixin
|
5
|
+
* `1.0.4`: fixed an error in map parsing
|
6
|
+
* `1.0.3`: slightly edited the mixin to dump JSON to CSS
|
7
|
+
* `1.0.2`: fixed an issue with string parsing
|
8
|
+
* `1.0.1`: fixed an issue with alpha color parsing
|
9
|
+
* `1.0.0`: Stable API. `json-encode` and `json-decode`
|
10
|
+
* `0.0.2`: added `json-decode` and test
|
11
|
+
* `0.0.1`: initial commit
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# SassyJSON [![NPM version](https://badge.fury.io/js/sassyjson.png)](http://badge.fury.io/js/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 currently available in [npm](https://npmjs.org/).
|
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. You can copy its content directly into [Sassmeister](http://sassmeister.com/) to play with the code.
|
30
|
+
|
31
|
+
## Example
|
32
|
+
|
33
|
+
### Encoding Sass to JSON
|
34
|
+
|
35
|
+
#### Sass
|
36
|
+
|
37
|
+
``` scss
|
38
|
+
$map: ((a: (1 2 ( b : 1 )), b: ( #444444, false, ( a: 1, b: test ) ), c: (2 3 4 string)));
|
39
|
+
|
40
|
+
@include json-encode($map);
|
41
|
+
```
|
42
|
+
|
43
|
+
#### CSS
|
44
|
+
|
45
|
+
``` css
|
46
|
+
/*! json-encode: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}' */
|
47
|
+
|
48
|
+
body::before {
|
49
|
+
content: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
50
|
+
}
|
51
|
+
|
52
|
+
head {
|
53
|
+
font-family: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
54
|
+
}
|
55
|
+
|
56
|
+
@media -json-encode {
|
57
|
+
json {
|
58
|
+
json: '{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}';
|
59
|
+
}
|
60
|
+
}
|
61
|
+
```
|
62
|
+
|
63
|
+
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`.
|
64
|
+
|
65
|
+
### Decoding JSON to Sass
|
66
|
+
|
67
|
+
``` scss
|
68
|
+
$json-decode: json-decode('{"a": [1, 2, {"b": 1}], "b": ["#444444", false, {"a": 1, "b": "test"}], "c": [2, 3, 4, "string"]}');
|
69
|
+
// ("a": 1 2 ("b": 1), "b": #444444 false ("a": 1, "b": "test"), "c": 2 3 4 "string")
|
70
|
+
```
|
71
|
+
|
72
|
+
## Requirements
|
73
|
+
|
74
|
+
All you need is a clean version of Sass 3.3. Otherwise it's just pure Sass madness.
|
75
|
+
|
76
|
+
## Development
|
77
|
+
|
78
|
+
### You need
|
79
|
+
|
80
|
+
* [NodeJS](http://nodejs.org)
|
81
|
+
* [Ruby](https://www.ruby-lang.org/)
|
82
|
+
* Sass 3.3 via `gem instals sass --pre`
|
83
|
+
* `grunt-cli` via `npm install -g grunt-cli`
|
84
|
+
|
85
|
+
### How to
|
86
|
+
|
87
|
+
1. Fork this repository
|
88
|
+
2. Run `npm install`
|
89
|
+
3. `grunt dev`
|
90
|
+
4. Make your changes + write tests
|
91
|
+
5. Commit + Pull request
|
92
|
+
|
93
|
+
## Credits
|
94
|
+
|
95
|
+
* [Fabrice Weinberg](http://twitter.com/fweinb)
|
96
|
+
* [Hugo Giraudel](http://twitter.com/hugogiraudel)
|
data/lib/SassyJSON.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'compass'
|
2
|
+
extension_path = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
3
|
+
Compass::Frameworks.register('SassyJSON', :path => extension_path)
|
4
|
+
|
5
|
+
# Version is a number. If a version contains alphas, it will be created as a prerelease version
|
6
|
+
# Date is in the form of YYYY-MM-DD
|
7
|
+
module SassyJSON
|
8
|
+
VERSION = "1.0.6"
|
9
|
+
DATE = "2014-01-19"
|
10
|
+
end
|
11
|
+
|
12
|
+
module Sass::Script::Functions
|
13
|
+
|
14
|
+
end
|
data/src/SassyJSON.scss
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
// Parse a JSON string
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param $json: JSON string to parse
|
4
|
+
// --------------------------------------------------------------------------------
|
5
|
+
// @throw "Input string may not be null"
|
6
|
+
// --------------------------------------------------------------------------------
|
7
|
+
// @return [literal|false]
|
8
|
+
|
9
|
+
@function json-decode($json) {
|
10
|
+
$length: str-length($json);
|
11
|
+
$pointer: 1;
|
12
|
+
$value: null;
|
13
|
+
|
14
|
+
@if $json == null {
|
15
|
+
@return _throw("Input string may not be null.", $pointer);
|
16
|
+
}
|
17
|
+
|
18
|
+
@while $value != false // Stop if error
|
19
|
+
and $pointer <= $length {
|
20
|
+
$read: _json-decode--value($json, $pointer);
|
21
|
+
$pointer: nth($read, 1);
|
22
|
+
$value: nth($read, 2);
|
23
|
+
}
|
24
|
+
|
25
|
+
@return $value;
|
26
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
// Helpers
|
2
|
+
@import "helpers/all/throw";
|
3
|
+
@import "helpers/all/value";
|
4
|
+
@import "helpers/map/consume";
|
5
|
+
@import "helpers/number/pow";
|
6
|
+
@import "helpers/number/find-digits";
|
7
|
+
@import "helpers/number/find-integer";
|
8
|
+
@import "helpers/number/find-exponent";
|
9
|
+
@import "helpers/color/color";
|
10
|
+
@import "helpers/color/get-color-value";
|
11
|
+
@import "helpers/color/rgb";
|
12
|
+
@import "helpers/color/hsl";
|
13
|
+
@import "helpers/color/hex";
|
14
|
+
@import "helpers/color/hex-to-dec";
|
15
|
+
@import "helpers/string/length";
|
16
|
+
@import "helpers/string/strip-token";
|
17
|
+
@import "helpers/string/find-ending-quote";
|
18
|
+
|
19
|
+
// Type specific decoding functions
|
20
|
+
@import "types/bool";
|
21
|
+
@import "types/null";
|
22
|
+
@import "types/list";
|
23
|
+
@import "types/map";
|
24
|
+
@import "types/number";
|
25
|
+
@import "types/string";
|
26
|
+
|
27
|
+
// Public API
|
28
|
+
@import "api/json";
|
@@ -0,0 +1,11 @@
|
|
1
|
+
// Logs an error at `$pointer` with `$string` message
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $string: error message
|
4
|
+
// @param [number] $pointer: pointer position
|
5
|
+
// --------------------------------------------------------------------------------
|
6
|
+
// @return [list] (pointer, false)
|
7
|
+
|
8
|
+
@function _throw($string, $pointer) {
|
9
|
+
@warn "ERROR::#{$pointer}::#{$string}";
|
10
|
+
@return $pointer, false;
|
11
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
// Delay parsing to type-specific function
|
2
|
+
// according to found character
|
3
|
+
// --------------------------------------------------------------------------------
|
4
|
+
// @param [string] $source: JSON complete source
|
5
|
+
// @param [number] $pointer: current pointer
|
6
|
+
// --------------------------------------------------------------------------------
|
7
|
+
// @throw "Unexpected token $token."
|
8
|
+
// @throw "Empty JSON string."
|
9
|
+
// --------------------------------------------------------------------------------
|
10
|
+
// @return [list|false] (new pointer, parsed value)
|
11
|
+
|
12
|
+
@function _json-decode--value($source, $pointer) {
|
13
|
+
$length: str-length($source);
|
14
|
+
|
15
|
+
@while $pointer <= $length {
|
16
|
+
$token: str-slice($source, $pointer, $pointer);
|
17
|
+
$pointer: $pointer + 1;
|
18
|
+
|
19
|
+
@if $token == '{' {
|
20
|
+
@return _json-decode--map($source, $pointer);
|
21
|
+
}
|
22
|
+
@else if $token == '[' {
|
23
|
+
@return _json-decode--list($source, $pointer);
|
24
|
+
}
|
25
|
+
@else if $token == 't' {
|
26
|
+
@return _json-decode--true($source, $pointer);
|
27
|
+
}
|
28
|
+
@else if $token == 'f' {
|
29
|
+
@return _json-decode--false($source, $pointer);
|
30
|
+
}
|
31
|
+
@else if $token == '"' {
|
32
|
+
@return _json-decode--string($source, $pointer);
|
33
|
+
}
|
34
|
+
@else if $token == 'n' {
|
35
|
+
@return _json-decode--null($source, $pointer);
|
36
|
+
}
|
37
|
+
@else if index('1' '2' '3' '4' '5' '6' '7' '8' '9' '0' '-' '.', $token) {
|
38
|
+
@return _json-decode--number($source, $pointer);
|
39
|
+
}
|
40
|
+
@else if $token == ' ' {
|
41
|
+
// @continue;
|
42
|
+
}
|
43
|
+
@else {
|
44
|
+
@return _throw("Unexpected token `" + $token + "`.", $pointer);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
@return _throw("Empty JSON string.", $pointer);
|
49
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
// Parses a JSON encoded string to see if it's a CSS color
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $string: JSON string
|
4
|
+
// --------------------------------------------------------------------------------
|
5
|
+
// @return [color|string] string or number, depending on the match
|
6
|
+
|
7
|
+
@function _color($string) {
|
8
|
+
@if type-of($string) == color {
|
9
|
+
@return $string;
|
10
|
+
}
|
11
|
+
|
12
|
+
$string: to-lower-case($string);
|
13
|
+
$keywords: "transparent" "black" "silver" "gray" "white" "maroon" "red" "purple" "fuchsia" "green" "lime" "olive" "yellow" "navy" "blue" "teal" "aqua" "aliceblue" "antiquewhite" "aqua" "aquamarine" "azure" "beige" "bisque" "black" "blanchedalmond" "blue" "blueviolet" "brown" "burlywood" "cadetblue" "chartreuse" "chocolate" "coral" "cornflowerblue" "cornsilk" "crimson" "cyan" "darkblue" "darkcyan" "darkgoldenrod" "darkgray" "darkgreen" "darkgrey" "darkkhaki" "darkmagenta" "darkolivegreen" "darkorange" "darkorchid" "darkred" "darksalmon" "darkseagreen" "darkslateblue" "darkslategray" "darkslategrey" "darkturquoise" "darkviolet" "deeppink" "deepskyblue" "dimgray" "dimgrey" "dodgerblue" "firebrick" "floralwhite" "forestgreen" "fuchsia" "gainsboro" "ghostwhite" "gold" "goldenrod" "gray" "green" "greenyellow" "grey" "honeydew" "hotpink" "indianred" "indigo" "ivory" "khaki" "lavender" "lavenderblush" "lawngreen" "lemonchiffon" "lightblue" "lightcoral" "lightcyan" "lightgoldenrodyellow" "lightgray" "lightgreen" "lightgrey" "lightpink" "lightsalmon" "lightseagreen" "lightskyblue" "lightslategray" "lightslategrey" "lightsteelblue" "lightyellow" "lime" "limegreen" "linen" "magenta" "maroon" "mediumaquamarine" "mediumblue" "mediumorchid" "mediumpurple" "mediumseagreen" "mediumslateblue" "mediumspringgreen" "mediumturquoise" "mediumvioletred" "midnightblue" "mintcream" "mistyrose" "moccasin" "navajowhite" "navy" "oldlace" "olive" "olivedrab" "orange" "orangered" "orchid" "palegoldenrod" "palegreen" "paleturquoise" "palevioletred" "papayawhip" "peachpuff" "peru" "pink" "plum" "powderblue" "purple" "red" "rosybrown" "royalblue" "saddlebrown" "salmon" "sandybrown" "seagreen" "seashell" "sienna" "silver" "skyblue" "slateblue" "slategray" "slategrey" "snow" "springgreen" "steelblue" "tan" "teal" "thistle" "tomato" "turquoise" "violet" "wheat" "white" "whitesmoke" "yellow" "yellowgreen";
|
14
|
+
$colors: transparent black silver gray white maroon red purple fuchsia green lime olive yellow navy blue teal aqua aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen;
|
15
|
+
|
16
|
+
// Deal with inherit keyword
|
17
|
+
@if $string == "inherit" {
|
18
|
+
@return unquote($string);
|
19
|
+
}
|
20
|
+
|
21
|
+
// Deal with color keywords
|
22
|
+
@if index($keywords, $string) {
|
23
|
+
@return nth($colors, index($keywords, $string));
|
24
|
+
}
|
25
|
+
|
26
|
+
// Deal with hexadecimal triplets
|
27
|
+
@else if str-slice($string, 1, 1) == '#' {
|
28
|
+
@return _from-hex($string);
|
29
|
+
}
|
30
|
+
|
31
|
+
// Deal with rgb(a) colors
|
32
|
+
@else if str-slice($string, 1, 3) == 'rgb' {
|
33
|
+
@return _from-rgb($string);
|
34
|
+
}
|
35
|
+
|
36
|
+
// Deal with hsl(a) colors
|
37
|
+
@else if str-slice($string, 1, 3) == 'hsl' {
|
38
|
+
@return _from-hsl($string);
|
39
|
+
}
|
40
|
+
|
41
|
+
// Return string
|
42
|
+
@else {
|
43
|
+
@return $string;
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
// Cast a stringified number / stringified percentage into number type
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $string: JSON string
|
4
|
+
// --------------------------------------------------------------------------------
|
5
|
+
// @return [number] unitless number or percentage
|
6
|
+
|
7
|
+
@function _get-color-value($string) {
|
8
|
+
$first: str-slice($string, 1, 1);
|
9
|
+
@if $first == '.' {
|
10
|
+
$string: '0' + $string;
|
11
|
+
}
|
12
|
+
$last: str-slice($string, -1, -1);
|
13
|
+
@return if(
|
14
|
+
$last == '%',
|
15
|
+
nth(_json-decode--number(str-slice($string, 1, -2), 2), 2) * 1%,
|
16
|
+
nth(_json-decode--number($string, 2), 2)
|
17
|
+
);
|
18
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
// Convert an hexadecimal number to a decimal number
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $string: hexadecimal value
|
4
|
+
// --------------------------------------------------------------------------------
|
5
|
+
// @return [number] decimal number
|
6
|
+
|
7
|
+
@function _hex-to-dec($string){
|
8
|
+
$hex: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f";
|
9
|
+
$string: to-lower-case($string);
|
10
|
+
$length: str-length($string);
|
11
|
+
|
12
|
+
$dec: 0;
|
13
|
+
@for $i from 1 through $length {
|
14
|
+
$factor: 1 + ( 15 * ( $length - $i ));
|
15
|
+
$index: index($hex, str-slice($string, $i, $i));
|
16
|
+
$dec: $dec + $factor * ($index - 1);
|
17
|
+
}
|
18
|
+
|
19
|
+
@return $dec;
|
20
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
// Cast a JSON encoded string into a hexadecimal color
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $string: JSON string
|
4
|
+
// --------------------------------------------------------------------------------
|
5
|
+
// @return [color|string] string or hex color depending on the match
|
6
|
+
|
7
|
+
@function _from-hex($string) {
|
8
|
+
$r: ""; $g: ""; $b: "";
|
9
|
+
$hex: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f";
|
10
|
+
$length: str-length($string);
|
11
|
+
$max: if($length == 4, 1, 2);
|
12
|
+
|
13
|
+
// Check for length accuracy
|
14
|
+
@if $length != 4 and $length != 7 {
|
15
|
+
@return $string;
|
16
|
+
}
|
17
|
+
|
18
|
+
// Loop from the second character (omitting #)
|
19
|
+
@for $i from 2 through $length {
|
20
|
+
$c: to-lower-case(str-slice($string, $i, $i));
|
21
|
+
|
22
|
+
// If wrong character, return
|
23
|
+
@if not index($hex, $c) {
|
24
|
+
@return $string;
|
25
|
+
}
|
26
|
+
|
27
|
+
@if str-length($r) < $max { $r: $r + $c }
|
28
|
+
@else if str-length($g) < $max { $g: $g + $c }
|
29
|
+
@else if str-length($b) < $max { $b: $b + $c }
|
30
|
+
}
|
31
|
+
|
32
|
+
@if $length == 4 {
|
33
|
+
$r: $r + $r;
|
34
|
+
$g: $g + $g;
|
35
|
+
$b: $b + $b;
|
36
|
+
}
|
37
|
+
|
38
|
+
@return rgb(_hex-to-dec($r), _hex-to-dec($g), _hex-to-dec($b));
|
39
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
// Cast a JSON encoded string into a hsl(a) color
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $string: JSON string
|
4
|
+
// --------------------------------------------------------------------------------
|
5
|
+
// @return [color|string] string or hsl(a) color, depending on the match
|
6
|
+
|
7
|
+
@function _from-hsl($string) {
|
8
|
+
$frags: ();
|
9
|
+
$is-alpha: str-slice($string, 4, 4) == 'a';
|
10
|
+
$start: str-index($string, "(");
|
11
|
+
$length: str-length($string);
|
12
|
+
|
13
|
+
@for $i from $start through $length {
|
14
|
+
$token: str-slice($string, $i, $i);
|
15
|
+
@if $token == ' ' {
|
16
|
+
// @continue;
|
17
|
+
}
|
18
|
+
@else if $token == '(' or $token == ',' {
|
19
|
+
$frags: append($frags, "");
|
20
|
+
}
|
21
|
+
@else if $token == ')' {
|
22
|
+
@if length($frags) != if($is-alpha, 4, 3) { @return $string; } // Parsing error
|
23
|
+
$hue: _get-color-value(nth($frags, 1));
|
24
|
+
$saturation: _get-color-value(nth($frags, 2));
|
25
|
+
$lightness: _get-color-value(nth($frags, 3));
|
26
|
+
|
27
|
+
@if not $hue or not $saturation or not $lightness {
|
28
|
+
@return $string;
|
29
|
+
}
|
30
|
+
|
31
|
+
@if $is-alpha {
|
32
|
+
@if length($frags) != 4 { @return $string; } // No alpha channel found
|
33
|
+
$alpha: _get-color-value(nth($frags, 4));
|
34
|
+
@if not $alpha { @return $string; } // Error parsing alpha channel
|
35
|
+
@return hsla($hue, $saturation, $lightness, $alpha);
|
36
|
+
}
|
37
|
+
|
38
|
+
@return hsl($hue, $saturation, $lightness);
|
39
|
+
}
|
40
|
+
@else {
|
41
|
+
$frags: set-nth($frags, length($frags), nth($frags, length($frags)) + $token);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
@return $string;
|
46
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
// Cast a JSON encoded string into a rgb(a) color
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $string: JSON string
|
4
|
+
// --------------------------------------------------------------------------------
|
5
|
+
// @return [color|string] string or rgb(a) color depending on the match
|
6
|
+
|
7
|
+
@function _from-rgb($string) {
|
8
|
+
$frags: ();
|
9
|
+
$is-alpha: str-slice($string, 4, 4) == 'a';
|
10
|
+
$start: str-index($string, "(");
|
11
|
+
$length: str-length($string);
|
12
|
+
|
13
|
+
@for $i from $start through $length {
|
14
|
+
$token: str-slice($string, $i, $i);
|
15
|
+
@if $token == ' ' {
|
16
|
+
// @continue;
|
17
|
+
}
|
18
|
+
@else if $token == '(' or $token == ',' {
|
19
|
+
$frags: append($frags, "");
|
20
|
+
}
|
21
|
+
@else if $token == ')' {
|
22
|
+
@if length($frags) != if($is-alpha, 4, 3) { @return $string; } // Parsing error
|
23
|
+
$red: _get-color-value(nth($frags, 1));
|
24
|
+
$green: _get-color-value(nth($frags, 2));
|
25
|
+
$blue: _get-color-value(nth($frags, 3));
|
26
|
+
|
27
|
+
@if not $red or not $green or not $blue {
|
28
|
+
@return $string;
|
29
|
+
}
|
30
|
+
|
31
|
+
@if $is-alpha {
|
32
|
+
@if length($frags) != 4 { @return $string; } // No alpha channel found
|
33
|
+
$alpha: _get-color-value(nth($frags, 4));
|
34
|
+
@if not $alpha { @return $string; } // Error parsing alpha channel
|
35
|
+
@return rgba($red, $green, $blue, $alpha);
|
36
|
+
}
|
37
|
+
|
38
|
+
@return rgb($red, $green, $blue);
|
39
|
+
}
|
40
|
+
@else {
|
41
|
+
$frags: set-nth($frags, length($frags), nth($frags, length($frags)) + $token);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
@return $string;
|
46
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
// Move pointer to position of token
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $source: JSON complete source
|
4
|
+
// @param [number] $pointer: current pointer
|
5
|
+
// @param [string] $token: token to reach
|
6
|
+
// --------------------------------------------------------------------------------
|
7
|
+
// @throw "Expected $token; found {x}."
|
8
|
+
// @throw "Expected $token but reached end of stream."
|
9
|
+
// --------------------------------------------------------------------------------
|
10
|
+
// @return [number|false] new pointer
|
11
|
+
|
12
|
+
@function _consume($source, $pointer, $token) {
|
13
|
+
$length: str-length($source);
|
14
|
+
|
15
|
+
@while $pointer <= $length {
|
16
|
+
$char: str-slice($source, $pointer, $pointer);
|
17
|
+
$pointer: $pointer + 1;
|
18
|
+
|
19
|
+
@if $char == $token {
|
20
|
+
@return $pointer;
|
21
|
+
}
|
22
|
+
|
23
|
+
@else if $char == " " {
|
24
|
+
// @continue;
|
25
|
+
}
|
26
|
+
|
27
|
+
@else {
|
28
|
+
@return _throw("Expected `" + $token + "; ` found `" + $char + "`.", $pointer);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
@return _throw("Expected `" + $token + "` but reached end of stream.", $pointer);
|
33
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
// Parses a JSON encoded number to find the digits
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $source: JSON complete source
|
4
|
+
// @param [number] $pointer: current pointer
|
5
|
+
// --------------------------------------------------------------------------------
|
6
|
+
// @throw "Unexpected token $token."
|
7
|
+
// --------------------------------------------------------------------------------
|
8
|
+
// @return [list|false] (new pointer, parsed number)
|
9
|
+
|
10
|
+
@function _find-digits($source, $pointer) {
|
11
|
+
$length: str-length($source);
|
12
|
+
$strings: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9';
|
13
|
+
$numbers: 0 1 2 3 4 5 6 7 8 9;
|
14
|
+
$result: null;
|
15
|
+
$runs: 1;
|
16
|
+
|
17
|
+
@while $pointer <= $length {
|
18
|
+
$token: to-lower-case(str-slice($source, $pointer, $pointer));
|
19
|
+
$index: index($strings, $token);
|
20
|
+
|
21
|
+
@if $token == '.' {
|
22
|
+
// @continue;
|
23
|
+
}
|
24
|
+
@else if $index and $index > 0 {
|
25
|
+
$number: nth($numbers, $index);
|
26
|
+
$runs: $runs * 10;
|
27
|
+
$result: if($result == null, $number, $result * 10 + $number);
|
28
|
+
}
|
29
|
+
@else {
|
30
|
+
@if index('e' '.' ',' ']' '}' ' ', $token) {
|
31
|
+
@return $pointer, if($result != null, $result / $runs, $result);
|
32
|
+
}
|
33
|
+
@return _throw("Unexpected token `" + $token + "`.", $pointer);
|
34
|
+
}
|
35
|
+
|
36
|
+
$pointer: $pointer + 1;
|
37
|
+
}
|
38
|
+
|
39
|
+
@return $pointer, if($result != null, $result / $runs, $result);
|
40
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
// Parses a JSON encoded number to find the exponent part
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $source: JSON complete source
|
4
|
+
// @param [number] $pointer: current pointer
|
5
|
+
// --------------------------------------------------------------------------------
|
6
|
+
// @throw "Unexpected token $token."
|
7
|
+
// --------------------------------------------------------------------------------
|
8
|
+
// @return [list|false] (new pointer, parsed number)
|
9
|
+
|
10
|
+
@function _find-exponent($source, $pointer) {
|
11
|
+
$length: str-length($source);
|
12
|
+
$strings: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9';
|
13
|
+
$numbers: 0 1 2 3 4 5 6 7 8 9;
|
14
|
+
$result: null;
|
15
|
+
$minus: false;
|
16
|
+
|
17
|
+
@while $pointer <= $length {
|
18
|
+
$token: to-lower-case(str-slice($source, $pointer, $pointer));
|
19
|
+
$index: index($strings, $token);
|
20
|
+
|
21
|
+
@if $token == 'e' {
|
22
|
+
// @continue;
|
23
|
+
}
|
24
|
+
@else if $token == '-' {
|
25
|
+
$minus: true;
|
26
|
+
}
|
27
|
+
@else if $token == '+' {
|
28
|
+
$minus: false;
|
29
|
+
}
|
30
|
+
@else if $index and $index > 0 {
|
31
|
+
$number: nth($numbers, $index);
|
32
|
+
$result: if($result == null, $number, $result * 10 + $number);
|
33
|
+
}
|
34
|
+
@else {
|
35
|
+
@if not index(" ", ", ", "]", "}", $token) {
|
36
|
+
@return _throw("Unexpected token `" + $token + "`.", $pointer);
|
37
|
+
}
|
38
|
+
|
39
|
+
@return $pointer, if($minus and $result != null, $result * -1, $result);
|
40
|
+
}
|
41
|
+
|
42
|
+
$pointer: $pointer + 1;
|
43
|
+
}
|
44
|
+
|
45
|
+
@return $pointer, if($minus and $result != null, $result * -1, $result);
|
46
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
// Parses a JSON encoded number to find the integer part
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [string] $source: JSON complete source
|
4
|
+
// @param [number] $pointer: current pointer
|
5
|
+
// --------------------------------------------------------------------------------
|
6
|
+
// @throw "Unexpected token $token."
|
7
|
+
// --------------------------------------------------------------------------------
|
8
|
+
// @return [list|false] (new pointer, parsed number)
|
9
|
+
|
10
|
+
@function _find-integer($source, $pointer) {
|
11
|
+
$length: str-length($source);
|
12
|
+
$strings: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9';
|
13
|
+
$numbers: 0 1 2 3 4 5 6 7 8 9;
|
14
|
+
$result: 0;
|
15
|
+
|
16
|
+
@while $pointer <= $length {
|
17
|
+
$token: to-lower-case(str-slice($source, $pointer, $pointer));
|
18
|
+
$index: index($strings, $token);
|
19
|
+
|
20
|
+
@if $token == '-' {
|
21
|
+
// do nothing
|
22
|
+
}
|
23
|
+
@else if $index {
|
24
|
+
$number: nth($numbers, $index);
|
25
|
+
$result: $result * 10 + $number;
|
26
|
+
}
|
27
|
+
@else {
|
28
|
+
@if index('e' '.' ',' ']' '}' ' ', $token) {
|
29
|
+
@return $pointer, $result;
|
30
|
+
}
|
31
|
+
@return _throw("Unexpected token `" + $token + "`.", $pointer);
|
32
|
+
}
|
33
|
+
|
34
|
+
$pointer: $pointer + 1;
|
35
|
+
}
|
36
|
+
|
37
|
+
@return $pointer, $result;
|
38
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// Power function
|
2
|
+
// --------------------------------------------------------------------------------
|
3
|
+
// @param [number] $x: number
|
4
|
+
// @param [number] $n: power
|
5
|
+
// --------------------------------------------------------------------------------
|
6
|
+
// @return [number] $x ^ $n
|
7
|
+
|
8
|
+
@function _pow($x, $n) {
|
9
|
+
$ret: 1;
|
10
|
+
|
11
|
+
@if $n >= 0 {
|
12
|
+
@for $i from 1 through $n {
|
13
|
+
$ret: $ret * $x;
|
14
|
+
}
|
15
|
+
} @else {
|
16
|
+
@for $i from $n to 0 {
|
17
|
+
$ret: $ret / $x;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
@return $ret;
|
22
|
+
}
|