sassc 2.1.0.pre1-x86-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +11 -0
  5. data/CHANGELOG.md +66 -0
  6. data/CODE_OF_CONDUCT.md +10 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +68 -0
  10. data/Rakefile +30 -0
  11. data/lib/sassc.rb +57 -0
  12. data/lib/sassc/dependency.rb +17 -0
  13. data/lib/sassc/engine.rb +139 -0
  14. data/lib/sassc/error.rb +37 -0
  15. data/lib/sassc/functions_handler.rb +75 -0
  16. data/lib/sassc/import_handler.rb +50 -0
  17. data/lib/sassc/importer.rb +31 -0
  18. data/lib/sassc/native.rb +70 -0
  19. data/lib/sassc/native/lib_c.rb +21 -0
  20. data/lib/sassc/native/native_context_api.rb +147 -0
  21. data/lib/sassc/native/native_functions_api.rb +164 -0
  22. data/lib/sassc/native/sass2scss_api.rb +10 -0
  23. data/lib/sassc/native/sass_input_style.rb +13 -0
  24. data/lib/sassc/native/sass_output_style.rb +12 -0
  25. data/lib/sassc/native/sass_value.rb +97 -0
  26. data/lib/sassc/native/string_list.rb +10 -0
  27. data/lib/sassc/sass_2_scss.rb +9 -0
  28. data/lib/sassc/script.rb +19 -0
  29. data/lib/sassc/script/functions.rb +8 -0
  30. data/lib/sassc/script/value.rb +137 -0
  31. data/lib/sassc/script/value/bool.rb +32 -0
  32. data/lib/sassc/script/value/color.rb +95 -0
  33. data/lib/sassc/script/value/list.rb +136 -0
  34. data/lib/sassc/script/value/map.rb +69 -0
  35. data/lib/sassc/script/value/number.rb +389 -0
  36. data/lib/sassc/script/value/string.rb +96 -0
  37. data/lib/sassc/script/value_conversion.rb +69 -0
  38. data/lib/sassc/script/value_conversion/base.rb +13 -0
  39. data/lib/sassc/script/value_conversion/bool.rb +13 -0
  40. data/lib/sassc/script/value_conversion/color.rb +18 -0
  41. data/lib/sassc/script/value_conversion/list.rb +25 -0
  42. data/lib/sassc/script/value_conversion/map.rb +21 -0
  43. data/lib/sassc/script/value_conversion/number.rb +13 -0
  44. data/lib/sassc/script/value_conversion/string.rb +17 -0
  45. data/lib/sassc/util.rb +231 -0
  46. data/lib/sassc/util/normalized_map.rb +117 -0
  47. data/lib/sassc/version.rb +5 -0
  48. data/sassc.gemspec +57 -0
  49. data/test/custom_importer_test.rb +127 -0
  50. data/test/engine_test.rb +314 -0
  51. data/test/error_test.rb +29 -0
  52. data/test/fixtures/paths.scss +10 -0
  53. data/test/functions_test.rb +303 -0
  54. data/test/native_test.rb +213 -0
  55. data/test/output_style_test.rb +107 -0
  56. data/test/sass_2_scss_test.rb +14 -0
  57. data/test/test_helper.rb +45 -0
  58. metadata +242 -0
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+
5
+ module SassC
6
+ class ErrorTest < MiniTest::Test
7
+ def render(data, opts={})
8
+ Engine.new(data, opts).render
9
+ end
10
+
11
+ def test_first_backtrace_is_sass
12
+ filename = "app/assets/stylesheets/application.scss"
13
+
14
+ begin
15
+ template = <<-SCSS
16
+ .foo {
17
+ baz: bang;
18
+ padding top: 10px;
19
+ }
20
+ SCSS
21
+
22
+ render(template, filename: filename)
23
+ rescue SassC::SyntaxError => err
24
+ expected = "#{filename}:3"
25
+ assert_equal expected, err.backtrace.first
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ div {
2
+ url: url(asset-path("foo.svg"));
3
+ url: url(image-path("foo.png"));
4
+ url: url(video-path("foo.mov"));
5
+ url: url(audio-path("foo.mp3"));
6
+ url: url(font-path("foo.woff"));
7
+ url: url(javascript-path('foo.js'));
8
+ url: url(javascript-path("foo.js"));
9
+ url: url(stylesheet-path("foo.css"));
10
+ }
@@ -0,0 +1,303 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+ require "stringio"
5
+
6
+ module SassC
7
+ class FunctionsTest < MiniTest::Test
8
+ include FixtureHelper
9
+
10
+ def setup
11
+ @real_stderr, $stderr = $stderr, StringIO.new
12
+ end
13
+
14
+ def teardown
15
+ $stderr = @real_stderr
16
+ end
17
+
18
+ def test_functions_may_return_sass_string_type
19
+ assert_sass <<-SCSS, <<-CSS
20
+ div { url: url(sass_return_path("foo.svg")); }
21
+ SCSS
22
+ div { url: url("foo.svg"); }
23
+ CSS
24
+ end
25
+
26
+ def test_functions_work_with_varying_quotes_and_string_types
27
+ assert_sass <<-SCSS, <<-CSS
28
+ div {
29
+ url: url(asset-path("foo.svg"));
30
+ url: url(image-path("foo.png"));
31
+ url: url(video-path("foo.mov"));
32
+ url: url(audio-path("foo.mp3"));
33
+ url: url(font-path("foo.woff"));
34
+ url: url(javascript-path('foo.js'));
35
+ url: url(javascript-path("foo.js"));
36
+ url: url(stylesheet-path("foo.css"));
37
+ }
38
+ SCSS
39
+ div {
40
+ url: url(asset-path("foo.svg"));
41
+ url: url(image-path("foo.png"));
42
+ url: url(video-path("foo.mov"));
43
+ url: url(audio-path("foo.mp3"));
44
+ url: url(font-path("foo.woff"));
45
+ url: url("/js/foo.js");
46
+ url: url("/js/foo.js");
47
+ url: url(/css/foo.css);
48
+ }
49
+ CSS
50
+ end
51
+
52
+ def test_function_with_no_return_value
53
+ assert_sass <<-SCSS, <<-CSS
54
+ div {url: url(no-return-path('foo.svg'));}
55
+ SCSS
56
+ div { url: url(); }
57
+ CSS
58
+ end
59
+
60
+ def test_function_that_returns_a_color
61
+ assert_sass <<-SCSS, <<-CSS
62
+ div { background: returns-a-color(); }
63
+ SCSS
64
+ div { background: black; }
65
+ CSS
66
+ end
67
+
68
+ def test_function_that_returns_a_number
69
+ assert_sass <<-SCSS, <<-CSS
70
+ div { width: returns-a-number(); }
71
+ SCSS
72
+ div { width: -312rem; }
73
+ CSS
74
+ end
75
+
76
+ def test_function_that_takes_a_number
77
+ assert_sass <<-SCSS, <<-CSS
78
+ div { display: inspect-number(42.1px); }
79
+ SCSS
80
+ div { display: 42.1px; }
81
+ CSS
82
+ end
83
+
84
+ def test_function_that_returns_a_bool
85
+ assert_sass <<-SCSS, <<-CSS
86
+ div { width: returns-a-bool(); }
87
+ SCSS
88
+ div { width: true; }
89
+ CSS
90
+ end
91
+
92
+ def test_function_that_takes_a_bool
93
+ assert_sass <<-SCSS, <<-CSS
94
+ div { display: inspect-bool(true)}
95
+ SCSS
96
+ div { display: true; }
97
+ CSS
98
+ end
99
+
100
+ def test_function_with_optional_arguments
101
+ assert_sass <<-SCSS, <<-EXPECTED_CSS
102
+ div {
103
+ url: optional_arguments('first');
104
+ url: optional_arguments('second', 'qux');
105
+ }
106
+ SCSS
107
+ div {
108
+ url: "first/bar";
109
+ url: "second/qux";
110
+ }
111
+ EXPECTED_CSS
112
+ end
113
+
114
+ def test_functions_may_accept_sass_color_type
115
+ assert_sass <<-SCSS, <<-EXPECTED_CSS
116
+ div { color: nice_color_argument(red); }
117
+ SCSS
118
+ div { color: rgb(255, 0, 0); }
119
+ EXPECTED_CSS
120
+ end
121
+
122
+ def test_function_with_unsupported_tag
123
+ skip('What are other unsupported tags?')
124
+ engine = Engine.new("div {url: function_with_unsupported_tag(());}")
125
+
126
+ exception = assert_raises(SassC::SyntaxError) do
127
+ engine.render
128
+ end
129
+
130
+ assert_match /Sass argument of type sass_list unsupported/, exception.message
131
+ assert_equal "[SassC::FunctionsHandler] Sass argument of type sass_list unsupported", stderr_output
132
+ end
133
+
134
+ def test_function_with_error
135
+ engine = Engine.new("div {url: function_that_raises_errors();}")
136
+
137
+ exception = assert_raises(SassC::SyntaxError) do
138
+ engine.render
139
+ end
140
+
141
+ assert_match /Error: error in C function function_that_raises_errors/, exception.message
142
+ assert_match /Intentional wrong thing happened somewhere inside the custom function/, exception.message
143
+ assert_equal "[SassC::FunctionsHandler] Intentional wrong thing happened somewhere inside the custom function", stderr_output
144
+ end
145
+
146
+ def test_function_that_returns_a_sass_value
147
+ assert_sass <<-SCSS, <<-CSS
148
+ div { background: returns-sass-value(); }
149
+ SCSS
150
+ div { background: black; }
151
+ CSS
152
+ end
153
+
154
+ def test_function_that_returns_a_sass_map
155
+ assert_sass <<-SCSS, <<-CSS
156
+ $my-map: returns-sass-map();
157
+ div { background: map-get( $my-map, color ); }
158
+ SCSS
159
+ div { background: black; }
160
+ CSS
161
+ end
162
+
163
+ def test_function_that_takes_a_sass_map
164
+ assert_sass <<-SCSS, <<-CSS
165
+ div { background-color: map-get( inspect-map(( color: black, number: 1.23px, string: "abc", map: ( x: 'y' ))), color ); }
166
+ SCSS
167
+ div { background-color: black; }
168
+ CSS
169
+ end
170
+
171
+ def test_function_that_returns_a_sass_list
172
+ assert_sass <<-SCSS, <<-CSS
173
+ $my-list: returns-sass-list();
174
+ div { width: nth( $my-list, 2 ); }
175
+ SCSS
176
+ div { width: 20; }
177
+ CSS
178
+ end
179
+
180
+ def test_function_that_takes_a_sass_list
181
+ assert_sass <<-SCSS, <<-CSS
182
+ div { width: nth(inspect-list((10 20 30)), 2); }
183
+ SCSS
184
+ div { width: 20; }
185
+ CSS
186
+ end
187
+
188
+ private
189
+
190
+ def assert_sass(sass, expected_css)
191
+ engine = Engine.new(sass)
192
+ assert_equal expected_css.strip.gsub!(/\s+/, " "), # poor man's String#squish
193
+ engine.render.strip.gsub!(/\s+/, " ")
194
+ end
195
+
196
+ def stderr_output
197
+ $stderr.string.gsub("\u0000\n", '').chomp
198
+ end
199
+
200
+ module Script::Functions
201
+
202
+ def javascript_path(path)
203
+ SassC::Script::Value::String.new("/js/#{path.value}", :string)
204
+ end
205
+
206
+ def stylesheet_path(path)
207
+ SassC::Script::Value::String.new("/css/#{path.value}", :identifier)
208
+ end
209
+
210
+ def no_return_path(path)
211
+ nil
212
+ end
213
+
214
+ def sass_return_path(path)
215
+ SassC::Script::Value::String.new("#{path.value}", :string)
216
+ end
217
+
218
+ def optional_arguments(path, optional = nil)
219
+ optional ||= SassC::Script::Value::String.new("bar")
220
+ SassC::Script::Value::String.new("#{path.value}/#{optional.value}", :string)
221
+ end
222
+
223
+ def function_that_raises_errors
224
+ raise StandardError, "Intentional wrong thing happened somewhere inside the custom function"
225
+ end
226
+
227
+ def function_with_unsupported_tag(value)
228
+ end
229
+
230
+ def nice_color_argument(color)
231
+ return SassC::Script::Value::String.new(color.to_s, :identifier)
232
+ end
233
+
234
+ def returns_a_color
235
+ return SassC::Script::Value::Color.new(red: 0, green: 0, blue: 0)
236
+ end
237
+
238
+ def returns_a_number
239
+ return SassC::Script::Value::Number.new(-312,'rem')
240
+ end
241
+
242
+ def returns_a_bool
243
+ return SassC::Script::Value::Bool.new(true)
244
+ end
245
+
246
+ def inspect_bool ( argument )
247
+ raise StandardError.new "passed value is not a Sass::Script::Value::Bool" unless argument.is_a? SassC::Script::Value::Bool
248
+ return argument
249
+ end
250
+
251
+ def inspect_number ( argument )
252
+ raise StandardError.new "passed value is not a Sass::Script::Value::Number" unless argument.is_a? SassC::Script::Value::Number
253
+ return argument
254
+ end
255
+
256
+ def inspect_map ( argument )
257
+ argument.to_h.each_pair do |key, value|
258
+ raise StandardError.new "key #{key.inspect} is not a string" unless key.is_a? SassC::Script::Value::String
259
+
260
+ valueClass = case key.value
261
+ when 'string'
262
+ SassC::Script::Value::String
263
+ when 'number'
264
+ SassC::Script::Value::Number
265
+ when 'color'
266
+ SassC::Script::Value::Color
267
+ when 'map'
268
+ SassC::Script::Value::Map
269
+ end
270
+
271
+ raise StandardError.new "unknown key #{key.inspect}" unless valueClass
272
+ raise StandardError.new "value for #{key.inspect} is not a #{valueClass}" unless value.is_a? valueClass
273
+ end
274
+ return argument
275
+ end
276
+
277
+ def inspect_list(argument)
278
+ raise StandardError.new "passed value is not a Sass::Script::Value::List" unless argument.is_a? SassC::Script::Value::List
279
+ return argument
280
+ end
281
+
282
+ def returns_sass_value
283
+ return SassC::Script::Value::Color.new(red: 0, green: 0, blue: 0)
284
+ end
285
+
286
+ def returns_sass_map
287
+ key = SassC::Script::Value::String.new("color", "string")
288
+ value = SassC::Script::Value::Color.new(red: 0, green: 0, blue: 0)
289
+ values = {}
290
+ values[key] = value
291
+ map = SassC::Script::Value::Map.new values
292
+ return map
293
+ end
294
+
295
+ def returns_sass_list
296
+ numbers = [10, 20, 30].map { |n| SassC::Script::Value::Number.new(n, '') }
297
+ SassC::Script::Value::List.new(numbers, separator: :space)
298
+ end
299
+
300
+ end
301
+
302
+ end
303
+ end
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_helper"
4
+
5
+ module SassC
6
+ module NativeTest
7
+ SAMPLE_SASS_STRING = "$size: 30px; .hi { width: $size; }"
8
+ SPECIAL_SASS_STRING = "$sißßßßßße: 30px; .hßß©i { width: $size; }"
9
+ SAMPLE_CSS_OUTPUT = ".hi {\n width: 30px; }\n"
10
+ BAD_SASS_STRING = "$size = 30px;"
11
+
12
+ class General < MiniTest::Test
13
+ def test_it_reports_the_libsass_version
14
+ assert_equal "3.6.0", Native.version
15
+ end
16
+ end
17
+
18
+ class DataContext < MiniTest::Test
19
+ def teardown
20
+ Native.delete_data_context(@data_context) if @data_context
21
+ end
22
+
23
+ def test_compile_status_is_zero_when_successful
24
+ @data_context = Native.make_data_context(SAMPLE_SASS_STRING)
25
+ context = Native.data_context_get_context(@data_context)
26
+
27
+ status = Native.compile_data_context(@data_context)
28
+ assert_equal 0, status
29
+
30
+ status = Native.context_get_error_status(context)
31
+ assert_equal 0, status
32
+ end
33
+
34
+ def test_compiled_css_is_correct
35
+ @data_context = Native.make_data_context(SAMPLE_SASS_STRING)
36
+ context = Native.data_context_get_context(@data_context)
37
+ Native.compile_data_context(@data_context)
38
+
39
+ css = Native.context_get_output_string(context)
40
+ assert_equal SAMPLE_CSS_OUTPUT, css
41
+ end
42
+
43
+ def test_compile_status_is_one_if_failed
44
+ @data_context = Native.make_data_context(BAD_SASS_STRING)
45
+ context = Native.data_context_get_context(@data_context)
46
+
47
+ status = Native.compile_data_context(@data_context)
48
+ refute_equal 0, status
49
+
50
+ status = Native.context_get_error_status(context)
51
+ refute_equal 0, status
52
+ end
53
+
54
+ def test_multibyte_characters_work
55
+ @data_context = Native.make_data_context(SPECIAL_SASS_STRING)
56
+ context = Native.data_context_get_context(@data_context)
57
+
58
+ status = Native.compile_data_context(@data_context)
59
+ refute_equal 0, status
60
+ end
61
+
62
+ def test_custom_function
63
+ data_context = Native.make_data_context("foo { margin: foo(); }")
64
+ context = Native.data_context_get_context(data_context)
65
+ options = Native.context_get_options(context)
66
+
67
+ random_thing = FFI::MemoryPointer.from_string("hi")
68
+
69
+ funct = FFI::Function.new(:pointer, [:pointer, :pointer]) do |s_args, cookie|
70
+ Native.make_number(43, "px")
71
+ end
72
+
73
+ callback = Native.make_function(
74
+ "foo()",
75
+ funct,
76
+ random_thing
77
+ )
78
+
79
+ list = Native.make_function_list(1)
80
+ Native::function_set_list_entry(list, 0, callback);
81
+ Native::option_set_c_functions(options, list)
82
+
83
+ assert_equal Native.option_get_c_functions(options), list
84
+
85
+ first_list_entry = Native.function_get_list_entry(list, 0)
86
+ assert_equal Native.function_get_function(first_list_entry),
87
+ funct
88
+ assert_equal Native.function_get_signature(first_list_entry),
89
+ "foo()"
90
+ assert_equal Native.function_get_cookie(first_list_entry),
91
+ random_thing
92
+
93
+ string = Native.make_string("hello")
94
+ assert_equal :sass_string, Native.value_get_tag(string)
95
+ assert_equal "hello", Native.string_get_value(string)
96
+
97
+ number = Native.make_number(123.4, "rem")
98
+ assert_equal 123.4, Native.number_get_value(number)
99
+ assert_equal "rem", Native.number_get_unit(number)
100
+
101
+ Native.compile_data_context(data_context)
102
+
103
+ css = Native.context_get_output_string(context)
104
+ assert_equal "foo {\n margin: 43px; }\n", css
105
+ end
106
+ end
107
+
108
+ class FileContext < MiniTest::Test
109
+ include TempFileTest
110
+
111
+ def teardown
112
+ Native.delete_file_context(@file_context) if @file_context
113
+ end
114
+
115
+ def test_compile_status_is_zero_when_successful
116
+ temp_file("style.scss", SAMPLE_SASS_STRING)
117
+
118
+ @file_context = Native.make_file_context("style.scss")
119
+ context = Native.file_context_get_context(@file_context)
120
+
121
+ status = Native.compile_file_context(@file_context)
122
+ assert_equal 0, status
123
+
124
+ status = Native.context_get_error_status(context)
125
+ assert_equal 0, status
126
+ end
127
+
128
+ def test_compiled_css_is_correct
129
+ temp_file("style.scss", SAMPLE_SASS_STRING)
130
+
131
+ @file_context = Native.make_file_context("style.scss")
132
+ context = Native.file_context_get_context(@file_context)
133
+ Native.compile_file_context(@file_context)
134
+
135
+ css = Native.context_get_output_string(context)
136
+ assert_equal SAMPLE_CSS_OUTPUT, css
137
+ end
138
+
139
+ def test_invalid_file_name
140
+ temp_file("style.scss", SAMPLE_SASS_STRING)
141
+
142
+ @file_context = Native.make_file_context("style.jajaja")
143
+ context = Native.file_context_get_context(@file_context)
144
+ status = Native.compile_file_context(@file_context)
145
+
146
+ refute_equal 0, status
147
+
148
+ error = Native.context_get_error_message(context)
149
+
150
+ assert_match "Error: File to read not found or unreadable: style.jajaja",
151
+ error
152
+ end
153
+
154
+ def test_file_import
155
+ temp_file("not_included.scss", "$size: 30px;")
156
+ temp_file("import_parent.scss", "$size: 30px;")
157
+ temp_file("import.scss", "@import 'import_parent'; $size: 30px;")
158
+ temp_file("styles.scss", "@import 'import.scss'; .hi { width: $size; }")
159
+
160
+ @file_context = Native.make_file_context("styles.scss")
161
+ context = Native.file_context_get_context(@file_context)
162
+ status = Native.compile_file_context(@file_context)
163
+
164
+ assert_equal 0, status
165
+
166
+ css = Native.context_get_output_string(context)
167
+ assert_equal SAMPLE_CSS_OUTPUT, css
168
+
169
+ included_files = Native.context_get_included_files(context)
170
+ included_files.sort!
171
+
172
+ assert_match /import.scss/, included_files[0]
173
+ assert_match /import_parent.scss/, included_files[1]
174
+ assert_match /styles.scss/, included_files[2]
175
+ end
176
+
177
+ def test_custom_importer
178
+ temp_file("not_included.scss", "$size: $var + 25;")
179
+ temp_file("styles.scss", "@import 'import.scss'; .hi { width: $size; }")
180
+
181
+ @file_context = Native.make_file_context("styles.scss")
182
+ context = Native.file_context_get_context(@file_context)
183
+ options = Native.context_get_options(context)
184
+
185
+ funct = FFI::Function.new(:pointer, [:pointer, :pointer, :pointer]) do |url, prev, cookie|
186
+ list = Native.make_import_list(2)
187
+
188
+ str = "$var: 5px;\0"
189
+ data = Native::LibC.malloc(str.size)
190
+ data.write_string(str)
191
+
192
+ entry0 = Native.make_import_entry("fake_includ.scss", data, nil)
193
+ entry1 = Native.make_import_entry("not_included.scss", nil, nil)
194
+ Native.import_set_list_entry(list, 0, entry0)
195
+ Native.import_set_list_entry(list, 1, entry1)
196
+ list
197
+ end
198
+
199
+ callback = Native.make_importer(funct, nil)
200
+ list = Native.make_function_list(1)
201
+ Native::function_set_list_entry(list, 0, callback)
202
+
203
+ Native.option_set_c_importers(options, list)
204
+
205
+ status = Native.compile_file_context(@file_context)
206
+ assert_equal 0, status
207
+
208
+ css = Native.context_get_output_string(context)
209
+ assert_equal SAMPLE_CSS_OUTPUT, css
210
+ end
211
+ end
212
+ end
213
+ end