sassc 2.1.0.pre1-x86-linux

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 (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