sass 3.1.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -0,0 +1,887 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/../test_helper'
4
+ require File.dirname(__FILE__) + '/test_helper'
5
+
6
+ class SourcemapTest < Test::Unit::TestCase
7
+ def test_to_json_requires_args
8
+ _, sourcemap = render_with_sourcemap('')
9
+ assert_raise(ArgumentError) {sourcemap.to_json({})}
10
+ assert_raise(ArgumentError) {sourcemap.to_json({:css_path => 'foo'})}
11
+ assert_raise(ArgumentError) {sourcemap.to_json({:sourcemap_path => 'foo'})}
12
+ end
13
+
14
+ def test_simple_mapping_scss
15
+ assert_parses_with_sourcemap <<SCSS, <<CSS, <<JSON
16
+ a {
17
+ foo: bar;
18
+ /* SOME COMMENT */
19
+ font-size: 12px;
20
+ }
21
+ SCSS
22
+ a {
23
+ foo: bar;
24
+ /* SOME COMMENT */
25
+ font-size: 12px; }
26
+
27
+ /*# sourceMappingURL=test.css.map */
28
+ CSS
29
+ {
30
+ "version": 3,
31
+ "mappings": "AAAA,CAAE;EACA,GAAG,EAAE,GAAG;;EAER,SAAS,EAAE,IAAI",
32
+ "sources": ["test_simple_mapping_scss_inline.scss"],
33
+ "names": [],
34
+ "file": "test.css"
35
+ }
36
+ JSON
37
+ end
38
+
39
+ def test_simple_mapping_sass
40
+ assert_parses_with_sourcemap <<SASS, <<CSS, <<JSON, :syntax => :sass
41
+ a
42
+ foo: bar
43
+ /* SOME COMMENT */
44
+ :font-size 12px
45
+ SASS
46
+ a {
47
+ foo: bar;
48
+ /* SOME COMMENT */
49
+ font-size: 12px; }
50
+
51
+ /*# sourceMappingURL=test.css.map */
52
+ CSS
53
+ {
54
+ "version": 3,
55
+ "mappings": "AAAA,CAAC;EACC,GAAG,EAAE,GAAG;;EAEP,SAAS,EAAC,IAAI",
56
+ "sources": ["test_simple_mapping_sass_inline.sass"],
57
+ "names": [],
58
+ "file": "test.css"
59
+ }
60
+ JSON
61
+ end
62
+
63
+ def test_mapping_with_directory_scss
64
+ options = {:filename => "scss/style.scss", :output => "css/style.css"}
65
+ assert_parses_with_sourcemap <<SCSS, <<CSS, <<JSON, options
66
+ a {
67
+ foo: bar;
68
+ /* SOME COMMENT */
69
+ font-size: 12px;
70
+ }
71
+ SCSS
72
+ a {
73
+ foo: bar;
74
+ /* SOME COMMENT */
75
+ font-size: 12px; }
76
+
77
+ /*# sourceMappingURL=style.css.map */
78
+ CSS
79
+ {
80
+ "version": 3,
81
+ "mappings": "AAAA,CAAE;EACA,GAAG,EAAE,GAAG;;EAER,SAAS,EAAE,IAAI",
82
+ "sources": ["../scss/style.scss"],
83
+ "names": [],
84
+ "file": "style.css"
85
+ }
86
+ JSON
87
+ end
88
+
89
+ def test_mapping_with_directory_sass
90
+ options = {:filename => "sass/style.sass", :output => "css/style.css", :syntax => :sass}
91
+ assert_parses_with_sourcemap <<SASS, <<CSS, <<JSON, options
92
+ a
93
+ foo: bar
94
+ /* SOME COMMENT */
95
+ :font-size 12px
96
+ SASS
97
+ a {
98
+ foo: bar;
99
+ /* SOME COMMENT */
100
+ font-size: 12px; }
101
+
102
+ /*# sourceMappingURL=style.css.map */
103
+ CSS
104
+ {
105
+ "version": 3,
106
+ "mappings": "AAAA,CAAC;EACC,GAAG,EAAE,GAAG;;EAEP,SAAS,EAAC,IAAI",
107
+ "sources": ["../sass/style.sass"],
108
+ "names": [],
109
+ "file": "style.css"
110
+ }
111
+ JSON
112
+ end
113
+
114
+ unless Sass::Util.ruby1_8?
115
+ def test_simple_charset_mapping_scss
116
+ assert_parses_with_sourcemap <<SCSS, <<CSS, <<JSON
117
+ a {
118
+ fóó: bár;
119
+ }
120
+ SCSS
121
+ @charset "UTF-8";
122
+ a {
123
+ fóó: bár; }
124
+
125
+ /*# sourceMappingURL=test.css.map */
126
+ CSS
127
+ {
128
+ "version": 3,
129
+ "mappings": ";AAAA,CAAE;EACA,GAAG,EAAE,GAAG",
130
+ "sources": ["test_simple_charset_mapping_scss_inline.scss"],
131
+ "names": [],
132
+ "file": "test.css"
133
+ }
134
+ JSON
135
+ end
136
+
137
+ def test_simple_charset_mapping_sass
138
+ assert_parses_with_sourcemap <<SASS, <<CSS, <<JSON, :syntax => :sass
139
+ a
140
+ fóó: bár
141
+ SASS
142
+ @charset "UTF-8";
143
+ a {
144
+ fóó: bár; }
145
+
146
+ /*# sourceMappingURL=test.css.map */
147
+ CSS
148
+ {
149
+ "version": 3,
150
+ "mappings": ";AAAA,CAAC;EACC,GAAG,EAAE,GAAG",
151
+ "sources": ["test_simple_charset_mapping_sass_inline.sass"],
152
+ "names": [],
153
+ "file": "test.css"
154
+ }
155
+ JSON
156
+ end
157
+
158
+ def test_different_charset_than_encoding_scss
159
+ assert_parses_with_sourcemap(<<SCSS.force_encoding("IBM866"), <<CSS.force_encoding("IBM866"), <<JSON)
160
+ @charset "IBM866";
161
+ f\x86\x86 {
162
+ \x86: b;
163
+ }
164
+ SCSS
165
+ @charset "IBM866";
166
+ f\x86\x86 {
167
+ \x86: b; }
168
+
169
+ /*# sourceMappingURL=test.css.map */
170
+ CSS
171
+ {
172
+ "version": 3,
173
+ "mappings": ";AACA,GAAI;EACF,CAAC,EAAE,CAAC",
174
+ "sources": ["test_different_charset_than_encoding_scss_inline.scss"],
175
+ "names": [],
176
+ "file": "test.css"
177
+ }
178
+ JSON
179
+ end
180
+
181
+ def test_different_charset_than_encoding_sass
182
+ assert_parses_with_sourcemap(<<SASS.force_encoding("IBM866"), <<CSS.force_encoding("IBM866"), <<JSON, :syntax => :sass)
183
+ @charset "IBM866"
184
+ f\x86\x86
185
+ \x86: b
186
+ SASS
187
+ @charset "IBM866";
188
+ f\x86\x86 {
189
+ \x86: b; }
190
+
191
+ /*# sourceMappingURL=test.css.map */
192
+ CSS
193
+ {
194
+ "version": 3,
195
+ "mappings": ";AACA,GAAG;EACD,CAAC,EAAE,CAAC",
196
+ "sources": ["test_different_charset_than_encoding_sass_inline.sass"],
197
+ "names": [],
198
+ "file": "test.css"
199
+ }
200
+ JSON
201
+ end
202
+ end
203
+
204
+ def test_import_sourcemap_scss
205
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
206
+ @import {{1}}url(foo){{/1}},{{2}}url(moo) {{/2}}, {{3}}url(bar) {{/3}};
207
+ @import {{4}}url(baz) screen print{{/4}};
208
+ SCSS
209
+ {{1}}@import url(foo){{/1}};
210
+ {{2}}@import url(moo){{/2}};
211
+ {{3}}@import url(bar){{/3}};
212
+ {{4}}@import url(baz) screen print{{/4}};
213
+
214
+ /*# sourceMappingURL=test.css.map */
215
+ CSS
216
+ end
217
+
218
+ def test_import_sourcemap_sass
219
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
220
+ @import {{1}}foo.css{{/1}},{{2}}moo.css{{/2}}, {{3}}bar.css{{/3}}
221
+ @import {{4}}url(baz.css){{/4}}
222
+ @import {{5}}url(qux.css) screen print{{/5}}
223
+ SASS
224
+ {{1}}@import url(foo.css){{/1}};
225
+ {{2}}@import url(moo.css){{/2}};
226
+ {{3}}@import url(bar.css){{/3}};
227
+ {{4}}@import url(baz.css){{/4}};
228
+ {{5}}@import url(qux.css) screen print{{/5}};
229
+
230
+ /*# sourceMappingURL=test.css.map */
231
+ CSS
232
+ end
233
+
234
+ def test_media_sourcemap_scss
235
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
236
+ {{1}}@media screen, tv {{/1}}{
237
+ {{2}}body {{/2}}{
238
+ {{3}}max-width{{/3}}: {{4}}1070px{{/4}};
239
+ }
240
+ }
241
+ SCSS
242
+ {{1}}@media screen, tv{{/1}} {
243
+ {{2}}body{{/2}} {
244
+ {{3}}max-width{{/3}}: {{4}}1070px{{/4}}; } }
245
+
246
+ /*# sourceMappingURL=test.css.map */
247
+ CSS
248
+ end
249
+
250
+ def test_media_sourcemap_sass
251
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
252
+ {{1}}@media screen, tv{{/1}}
253
+ {{2}}body{{/2}}
254
+ {{3}}max-width{{/3}}: {{4}}1070px{{/4}}
255
+ SASS
256
+ {{1}}@media screen, tv{{/1}} {
257
+ {{2}}body{{/2}} {
258
+ {{3}}max-width{{/3}}: {{4}}1070px{{/4}}; } }
259
+
260
+ /*# sourceMappingURL=test.css.map */
261
+ CSS
262
+ end
263
+
264
+ def test_interpolation_and_vars_sourcemap_scss
265
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
266
+ $te: "te";
267
+ $teal: {{5}}teal{{/5}};
268
+ {{1}}p {{/1}}{
269
+ {{2}}con#{$te}nt{{/2}}: {{3}}"I a#{$te} #{5 + 10} pies!"{{/3}};
270
+ {{4}}color{{/4}}: $teal;
271
+ }
272
+
273
+ $name: foo;
274
+ $attr: border;
275
+ {{6}}p.#{$name} {{/6}}{
276
+ {{7}}#{$attr}-color{{/7}}: {{8}}blue{{/8}};
277
+ $font-size: 12px;
278
+ $line-height: 30px;
279
+ {{9}}font{{/9}}: {{10}}#{$font-size}/#{$line-height}{{/10}};
280
+ }
281
+ SCSS
282
+ {{1}}p{{/1}} {
283
+ {{2}}content{{/2}}: {{3}}"I ate 15 pies!"{{/3}};
284
+ {{4}}color{{/4}}: {{5}}teal{{/5}}; }
285
+
286
+ {{6}}p.foo{{/6}} {
287
+ {{7}}border-color{{/7}}: {{8}}blue{{/8}};
288
+ {{9}}font{{/9}}: {{10}}12px/30px{{/10}}; }
289
+
290
+ /*# sourceMappingURL=test.css.map */
291
+ CSS
292
+ end
293
+
294
+ def test_interpolation_and_vars_sourcemap_sass
295
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
296
+ $te: "te"
297
+ $teal: {{5}}teal{{/5}}
298
+ {{1}}p{{/1}}
299
+ {{2}}con#{$te}nt{{/2}}: {{3}}"I a#{$te} #{5 + 10} pies!"{{/3}}
300
+ {{4}}color{{/4}}: $teal
301
+
302
+ $name: foo
303
+ $attr: border
304
+ {{6}}p.#{$name}{{/6}}
305
+ {{7}}#{$attr}-color{{/7}}: {{8}}blue{{/8}}
306
+ $font-size: 12px
307
+ $line-height: 30px
308
+ {{9}}font{{/9}}: {{10}}#{$font-size}/#{$line-height}{{/10}}
309
+ SASS
310
+ {{1}}p{{/1}} {
311
+ {{2}}content{{/2}}: {{3}}"I ate 15 pies!"{{/3}};
312
+ {{4}}color{{/4}}: {{5}}teal{{/5}}; }
313
+
314
+ {{6}}p.foo{{/6}} {
315
+ {{7}}border-color{{/7}}: {{8}}blue{{/8}};
316
+ {{9}}font{{/9}}: {{10}}12px/30px{{/10}}; }
317
+
318
+ /*# sourceMappingURL=test.css.map */
319
+ CSS
320
+ end
321
+
322
+ def test_selectors_properties_sourcemap_scss
323
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
324
+ $width: 2px;
325
+ $translucent-red: rgba(255, 0, 0, 0.5);
326
+ {{1}}a {{/1}}{
327
+ {{8}}.special {{/8}}{
328
+ {{9}}color{{/9}}: {{10}}red{{/10}};
329
+ {{11}}&:hover {{/11}}{
330
+ {{12}}foo{{/12}}: {{13}}bar{{/13}};
331
+ {{14}}cursor{{/14}}: {{15}}e + -resize{{/15}};
332
+ {{16}}color{{/16}}: {{17}}opacify($translucent-red, 0.3){{/17}};
333
+ }
334
+ {{18}}&:after {{/18}}{
335
+ {{19}}content{{/19}}: {{20}}"I ate #{5 + 10} pies #{$width} thick!"{{/20}};
336
+ }
337
+ }
338
+ {{21}}&:active {{/21}}{
339
+ {{22}}color{{/22}}: {{23}}#010203 + #040506{{/23}};
340
+ {{24}}border{{/24}}: {{25}}$width solid black{{/25}};
341
+ }
342
+ /* SOME COMMENT */
343
+ {{2}}font{{/2}}: {{3}}2px/3px {{/3}}{
344
+ {{4}}family{{/4}}: {{5}}fantasy{{/5}};
345
+ {{6}}size{{/6}}: {{7}}1em + (2em * 3){{/7}};
346
+ }
347
+ }
348
+ SCSS
349
+ {{1}}a{{/1}} {
350
+ /* SOME COMMENT */
351
+ {{2}}font{{/2}}: {{3}}2px/3px{{/3}};
352
+ {{4}}font-family{{/4}}: {{5}}fantasy{{/5}};
353
+ {{6}}font-size{{/6}}: {{7}}7em{{/7}}; }
354
+ {{8}}a .special{{/8}} {
355
+ {{9}}color{{/9}}: {{10}}red{{/10}}; }
356
+ {{11}}a .special:hover{{/11}} {
357
+ {{12}}foo{{/12}}: {{13}}bar{{/13}};
358
+ {{14}}cursor{{/14}}: {{15}}e-resize{{/15}};
359
+ {{16}}color{{/16}}: {{17}}rgba(255, 0, 0, 0.8){{/17}}; }
360
+ {{18}}a .special:after{{/18}} {
361
+ {{19}}content{{/19}}: {{20}}"I ate 15 pies 2px thick!"{{/20}}; }
362
+ {{21}}a:active{{/21}} {
363
+ {{22}}color{{/22}}: {{23}}#050709{{/23}};
364
+ {{24}}border{{/24}}: {{25}}2px solid black{{/25}}; }
365
+
366
+ /*# sourceMappingURL=test.css.map */
367
+ CSS
368
+ end
369
+
370
+ def test_selectors_properties_sourcemap_sass
371
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
372
+ $width: 2px
373
+ $translucent-red: rgba(255, 0, 0, 0.5)
374
+ {{1}}a{{/1}}
375
+ {{8}}.special{{/8}}
376
+ {{9}}color{{/9}}: {{10}}red{{/10}}
377
+ {{11}}&:hover{{/11}}
378
+ {{12}}foo{{/12}}: {{13}}bar{{/13}}
379
+ {{14}}cursor{{/14}}: {{15}}e + -resize{{/15}}
380
+ {{16}}color{{/16}}: {{17}}opacify($translucent-red, 0.3){{/17}}
381
+ {{18}}&:after{{/18}}
382
+ {{19}}content{{/19}}: {{20}}"I ate #{5 + 10} pies #{$width} thick!"{{/20}}
383
+ {{21}}&:active{{/21}}
384
+ {{22}}color{{/22}}: {{23}}#010203 + #040506{{/23}}
385
+ {{24}}border{{/24}}: {{25}}$width solid black{{/25}}
386
+
387
+ /* SOME COMMENT */
388
+ {{2}}font{{/2}}: {{3}}2px/3px{{/3}}
389
+ {{4}}family{{/4}}: {{5}}fantasy{{/5}}
390
+ {{6}}size{{/6}}: {{7}}1em + (2em * 3){{/7}}
391
+ SASS
392
+ {{1}}a{{/1}} {
393
+ /* SOME COMMENT */
394
+ {{2}}font{{/2}}: {{3}}2px/3px{{/3}};
395
+ {{4}}font-family{{/4}}: {{5}}fantasy{{/5}};
396
+ {{6}}font-size{{/6}}: {{7}}7em{{/7}}; }
397
+ {{8}}a .special{{/8}} {
398
+ {{9}}color{{/9}}: {{10}}red{{/10}}; }
399
+ {{11}}a .special:hover{{/11}} {
400
+ {{12}}foo{{/12}}: {{13}}bar{{/13}};
401
+ {{14}}cursor{{/14}}: {{15}}e-resize{{/15}};
402
+ {{16}}color{{/16}}: {{17}}rgba(255, 0, 0, 0.8){{/17}}; }
403
+ {{18}}a .special:after{{/18}} {
404
+ {{19}}content{{/19}}: {{20}}"I ate 15 pies 2px thick!"{{/20}}; }
405
+ {{21}}a:active{{/21}} {
406
+ {{22}}color{{/22}}: {{23}}#050709{{/23}};
407
+ {{24}}border{{/24}}: {{25}}2px solid black{{/25}}; }
408
+
409
+ /*# sourceMappingURL=test.css.map */
410
+ CSS
411
+ end
412
+
413
+ def test_extend_sourcemap_scss
414
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
415
+ {{1}}.error {{/1}}{
416
+ {{2}}border{{/2}}: {{3}}1px #ff00aa{{/3}};
417
+ {{4}}background-color{{/4}}: {{5}}#fdd{{/5}};
418
+ }
419
+ {{6}}.seriousError {{/6}}{
420
+ @extend .error;
421
+ {{7}}border-width{{/7}}: {{8}}3px{{/8}};
422
+ }
423
+ SCSS
424
+ {{1}}.error, .seriousError{{/1}} {
425
+ {{2}}border{{/2}}: {{3}}1px #ff00aa{{/3}};
426
+ {{4}}background-color{{/4}}: {{5}}#fdd{{/5}}; }
427
+
428
+ {{6}}.seriousError{{/6}} {
429
+ {{7}}border-width{{/7}}: {{8}}3px{{/8}}; }
430
+
431
+ /*# sourceMappingURL=test.css.map */
432
+ CSS
433
+ end
434
+
435
+ def test_extend_sourcemap_sass
436
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
437
+ {{1}}.error{{/1}}
438
+ {{2}}border{{/2}}: {{3}}1px #f00{{/3}}
439
+ {{4}}background-color{{/4}}: {{5}}#fdd{{/5}}
440
+
441
+ {{6}}.seriousError{{/6}}
442
+ @extend .error
443
+ {{7}}border-width{{/7}}: {{8}}3px{{/8}}
444
+ SASS
445
+ {{1}}.error, .seriousError{{/1}} {
446
+ {{2}}border{{/2}}: {{3}}1px red{{/3}};
447
+ {{4}}background-color{{/4}}: {{5}}#ffdddd{{/5}}; }
448
+
449
+ {{6}}.seriousError{{/6}} {
450
+ {{7}}border-width{{/7}}: {{8}}3px{{/8}}; }
451
+
452
+ /*# sourceMappingURL=test.css.map */
453
+ CSS
454
+ end
455
+
456
+ def test_for_sourcemap_scss
457
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
458
+ @for $i from 1 through 3 {
459
+ {{1}}{{4}}{{7}}.item-#{$i} {{/1}}{{/4}}{{/7}}{ {{2}}{{5}}{{8}}width{{/2}}{{/5}}{{/8}}: {{3}}{{6}}{{9}}2em * $i{{/3}}{{/6}}{{/9}}; }
460
+ }
461
+ SCSS
462
+ {{1}}.item-1{{/1}} {
463
+ {{2}}width{{/2}}: {{3}}2em{{/3}}; }
464
+
465
+ {{4}}.item-2{{/4}} {
466
+ {{5}}width{{/5}}: {{6}}4em{{/6}}; }
467
+
468
+ {{7}}.item-3{{/7}} {
469
+ {{8}}width{{/8}}: {{9}}6em{{/9}}; }
470
+
471
+ /*# sourceMappingURL=test.css.map */
472
+ CSS
473
+ end
474
+
475
+ def test_for_sourcemap_sass
476
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
477
+ @for $i from 1 through 3
478
+ {{1}}{{4}}{{7}}.item-#{$i}{{/1}}{{/4}}{{/7}}
479
+ {{2}}{{5}}{{8}}width{{/2}}{{/5}}{{/8}}: {{3}}{{6}}{{9}}2em * $i{{/3}}{{/6}}{{/9}}
480
+ SASS
481
+ {{1}}.item-1{{/1}} {
482
+ {{2}}width{{/2}}: {{3}}2em{{/3}}; }
483
+
484
+ {{4}}.item-2{{/4}} {
485
+ {{5}}width{{/5}}: {{6}}4em{{/6}}; }
486
+
487
+ {{7}}.item-3{{/7}} {
488
+ {{8}}width{{/8}}: {{9}}6em{{/9}}; }
489
+
490
+ /*# sourceMappingURL=test.css.map */
491
+ CSS
492
+ end
493
+
494
+ def test_while_sourcemap_scss
495
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
496
+ $i: 6;
497
+ @while $i > 0 {
498
+ {{1}}{{4}}{{7}}.item-#{$i} {{/1}}{{/4}}{{/7}}{ {{2}}{{5}}{{8}}width{{/2}}{{/5}}{{/8}}: {{3}}{{6}}{{9}}2em * $i{{/3}}{{/6}}{{/9}}; }
499
+ $i: $i - 2 !global;
500
+ }
501
+ SCSS
502
+ {{1}}.item-6{{/1}} {
503
+ {{2}}width{{/2}}: {{3}}12em{{/3}}; }
504
+
505
+ {{4}}.item-4{{/4}} {
506
+ {{5}}width{{/5}}: {{6}}8em{{/6}}; }
507
+
508
+ {{7}}.item-2{{/7}} {
509
+ {{8}}width{{/8}}: {{9}}4em{{/9}}; }
510
+
511
+ /*# sourceMappingURL=test.css.map */
512
+ CSS
513
+ end
514
+
515
+ def test_while_sourcemap_sass
516
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
517
+ $i: 6
518
+ @while $i > 0
519
+ {{1}}{{4}}{{7}}.item-#{$i}{{/1}}{{/4}}{{/7}}
520
+ {{2}}{{5}}{{8}}width{{/2}}{{/5}}{{/8}}: {{3}}{{6}}{{9}}2em * $i{{/3}}{{/6}}{{/9}}
521
+ $i: $i - 2 !global
522
+ SASS
523
+ {{1}}.item-6{{/1}} {
524
+ {{2}}width{{/2}}: {{3}}12em{{/3}}; }
525
+
526
+ {{4}}.item-4{{/4}} {
527
+ {{5}}width{{/5}}: {{6}}8em{{/6}}; }
528
+
529
+ {{7}}.item-2{{/7}} {
530
+ {{8}}width{{/8}}: {{9}}4em{{/9}}; }
531
+
532
+ /*# sourceMappingURL=test.css.map */
533
+ CSS
534
+ end
535
+
536
+ def test_each_sourcemap_scss
537
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
538
+ @each $animal in puma, sea-slug, egret, salamander {
539
+ {{1}}{{4}}{{7}}{{10}}.#{$animal}-icon {{/1}}{{/4}}{{/7}}{{/10}}{
540
+ {{2}}{{5}}{{8}}{{11}}background-image{{/2}}{{/5}}{{/8}}{{/11}}: {{3}}{{6}}{{9}}{{12}}url('/images/#{$animal}.png'){{/3}}{{/6}}{{/9}}{{/12}};
541
+ }
542
+ }
543
+ SCSS
544
+ {{1}}.puma-icon{{/1}} {
545
+ {{2}}background-image{{/2}}: {{3}}url("/images/puma.png"){{/3}}; }
546
+
547
+ {{4}}.sea-slug-icon{{/4}} {
548
+ {{5}}background-image{{/5}}: {{6}}url("/images/sea-slug.png"){{/6}}; }
549
+
550
+ {{7}}.egret-icon{{/7}} {
551
+ {{8}}background-image{{/8}}: {{9}}url("/images/egret.png"){{/9}}; }
552
+
553
+ {{10}}.salamander-icon{{/10}} {
554
+ {{11}}background-image{{/11}}: {{12}}url("/images/salamander.png"){{/12}}; }
555
+
556
+ /*# sourceMappingURL=test.css.map */
557
+ CSS
558
+ end
559
+
560
+ def test_each_sourcemap_sass
561
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
562
+ @each $animal in puma, sea-slug, egret, salamander
563
+ {{1}}{{4}}{{7}}{{10}}.#{$animal}-icon{{/1}}{{/4}}{{/7}}{{/10}}
564
+ {{2}}{{5}}{{8}}{{11}}background-image{{/2}}{{/5}}{{/8}}{{/11}}: {{3}}{{6}}{{9}}{{12}}url('/images/#{$animal}.png'){{/3}}{{/6}}{{/9}}{{/12}}
565
+ SASS
566
+ {{1}}.puma-icon{{/1}} {
567
+ {{2}}background-image{{/2}}: {{3}}url("/images/puma.png"){{/3}}; }
568
+
569
+ {{4}}.sea-slug-icon{{/4}} {
570
+ {{5}}background-image{{/5}}: {{6}}url("/images/sea-slug.png"){{/6}}; }
571
+
572
+ {{7}}.egret-icon{{/7}} {
573
+ {{8}}background-image{{/8}}: {{9}}url("/images/egret.png"){{/9}}; }
574
+
575
+ {{10}}.salamander-icon{{/10}} {
576
+ {{11}}background-image{{/11}}: {{12}}url("/images/salamander.png"){{/12}}; }
577
+
578
+ /*# sourceMappingURL=test.css.map */
579
+ CSS
580
+ end
581
+
582
+ def test_mixin_sourcemap_scss
583
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
584
+ @mixin large-text {
585
+ font: {
586
+ {{2}}size{{/2}}: {{3}}20px{{/3}};
587
+ {{4}}weight{{/4}}: {{5}}bold{{/5}};
588
+ }
589
+ {{6}}color{{/6}}: {{7}}#ff0000{{/7}};
590
+ }
591
+
592
+ {{1}}.page-title {{/1}}{
593
+ @include large-text;
594
+ {{8}}padding{{/8}}: {{9}}4px{{/9}};
595
+ }
596
+
597
+ @mixin dashed-border($color, $width: {{14}}1in{{/14}}) {
598
+ border: {
599
+ {{11}}{{18}}color{{/11}}{{/18}}: $color;
600
+ {{13}}{{20}}width{{/13}}{{/20}}: $width;
601
+ {{15}}{{22}}style{{/15}}{{/22}}: {{16}}{{23}}dashed{{/16}}{{/23}};
602
+ }
603
+ }
604
+
605
+ {{10}}p {{/10}}{ @include dashed-border({{12}}blue{{/12}}); }
606
+ {{17}}h1 {{/17}}{ @include dashed-border({{19}}blue{{/19}}, {{21}}2in{{/21}}); }
607
+
608
+ @mixin box-shadow($shadows...) {
609
+ {{25}}-moz-box-shadow{{/25}}: {{26}}$shadows{{/26}};
610
+ {{27}}-webkit-box-shadow{{/27}}: {{28}}$shadows{{/28}};
611
+ {{29}}box-shadow{{/29}}: {{30}}$shadows{{/30}};
612
+ }
613
+
614
+ {{24}}.shadows {{/24}}{
615
+ @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
616
+ }
617
+ SCSS
618
+ {{1}}.page-title{{/1}} {
619
+ {{2}}font-size{{/2}}: {{3}}20px{{/3}};
620
+ {{4}}font-weight{{/4}}: {{5}}bold{{/5}};
621
+ {{6}}color{{/6}}: {{7}}#ff0000{{/7}};
622
+ {{8}}padding{{/8}}: {{9}}4px{{/9}}; }
623
+
624
+ {{10}}p{{/10}} {
625
+ {{11}}border-color{{/11}}: {{12}}blue{{/12}};
626
+ {{13}}border-width{{/13}}: {{14}}1in{{/14}};
627
+ {{15}}border-style{{/15}}: {{16}}dashed{{/16}}; }
628
+
629
+ {{17}}h1{{/17}} {
630
+ {{18}}border-color{{/18}}: {{19}}blue{{/19}};
631
+ {{20}}border-width{{/20}}: {{21}}2in{{/21}};
632
+ {{22}}border-style{{/22}}: {{23}}dashed{{/23}}; }
633
+
634
+ {{24}}.shadows{{/24}} {
635
+ {{25}}-moz-box-shadow{{/25}}: {{26}}0px 4px 5px #666666, 2px 6px 10px #999999{{/26}};
636
+ {{27}}-webkit-box-shadow{{/27}}: {{28}}0px 4px 5px #666666, 2px 6px 10px #999999{{/28}};
637
+ {{29}}box-shadow{{/29}}: {{30}}0px 4px 5px #666666, 2px 6px 10px #999999{{/30}}; }
638
+
639
+ /*# sourceMappingURL=test.css.map */
640
+ CSS
641
+ end
642
+
643
+ def test_mixin_sourcemap_sass
644
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
645
+ =large-text
646
+ :font
647
+ {{2}}size{{/2}}: {{3}}20px{{/3}}
648
+ {{4}}weight{{/4}}: {{5}}bold{{/5}}
649
+ {{6}}color{{/6}}: {{7}}#ff0000{{/7}}
650
+
651
+ {{1}}.page-title{{/1}}
652
+ +large-text
653
+ {{8}}padding{{/8}}: {{9}}4px{{/9}}
654
+
655
+ =dashed-border($color, $width: {{14}}1in{{/14}})
656
+ border:
657
+ {{11}}{{18}}color{{/11}}{{/18}}: $color
658
+ {{13}}{{20}}width{{/13}}{{/20}}: $width
659
+ {{15}}{{22}}style{{/15}}{{/22}}: {{16}}{{23}}dashed{{/16}}{{/23}}
660
+
661
+ {{10}}p{{/10}}
662
+ +dashed-border({{12}}blue{{/12}})
663
+
664
+ {{17}}h1{{/17}}
665
+ +dashed-border({{19}}blue{{/19}}, {{21}}2in{{/21}})
666
+
667
+ =box-shadow($shadows...)
668
+ {{25}}-moz-box-shadow{{/25}}: {{26}}$shadows{{/26}}
669
+ {{27}}-webkit-box-shadow{{/27}}: {{28}}$shadows{{/28}}
670
+ {{29}}box-shadow{{/29}}: {{30}}$shadows{{/30}}
671
+
672
+ {{24}}.shadows{{/24}}
673
+ +box-shadow(0px 4px 5px #666, 2px 6px 10px #999)
674
+ SASS
675
+ {{1}}.page-title{{/1}} {
676
+ {{2}}font-size{{/2}}: {{3}}20px{{/3}};
677
+ {{4}}font-weight{{/4}}: {{5}}bold{{/5}};
678
+ {{6}}color{{/6}}: {{7}}red{{/7}};
679
+ {{8}}padding{{/8}}: {{9}}4px{{/9}}; }
680
+
681
+ {{10}}p{{/10}} {
682
+ {{11}}border-color{{/11}}: {{12}}blue{{/12}};
683
+ {{13}}border-width{{/13}}: {{14}}1in{{/14}};
684
+ {{15}}border-style{{/15}}: {{16}}dashed{{/16}}; }
685
+
686
+ {{17}}h1{{/17}} {
687
+ {{18}}border-color{{/18}}: {{19}}blue{{/19}};
688
+ {{20}}border-width{{/20}}: {{21}}2in{{/21}};
689
+ {{22}}border-style{{/22}}: {{23}}dashed{{/23}}; }
690
+
691
+ {{24}}.shadows{{/24}} {
692
+ {{25}}-moz-box-shadow{{/25}}: {{26}}0px 4px 5px #666666, 2px 6px 10px #999999{{/26}};
693
+ {{27}}-webkit-box-shadow{{/27}}: {{28}}0px 4px 5px #666666, 2px 6px 10px #999999{{/28}};
694
+ {{29}}box-shadow{{/29}}: {{30}}0px 4px 5px #666666, 2px 6px 10px #999999{{/30}}; }
695
+
696
+ /*# sourceMappingURL=test.css.map */
697
+ CSS
698
+ end
699
+
700
+ def test_function_sourcemap_scss
701
+ assert_parses_with_mapping <<'SCSS', <<'CSS'
702
+ $grid-width: 20px;
703
+ $gutter-width: 5px;
704
+
705
+ @function grid-width($n) {
706
+ @return $n * $grid-width + ($n - 1) * $gutter-width;
707
+ }
708
+ {{1}}sidebar {{/1}}{ {{2}}width{{/2}}: {{3}}grid-width(5){{/3}}; }
709
+ SCSS
710
+ {{1}}sidebar{{/1}} {
711
+ {{2}}width{{/2}}: {{3}}120px{{/3}}; }
712
+
713
+ /*# sourceMappingURL=test.css.map */
714
+ CSS
715
+ end
716
+
717
+ def test_function_sourcemap_sass
718
+ assert_parses_with_mapping <<'SASS', <<'CSS', :syntax => :sass
719
+ $grid-width: 20px
720
+ $gutter-width: 5px
721
+
722
+ @function grid-width($n)
723
+ @return $n * $grid-width + ($n - 1) * $gutter-width
724
+
725
+ {{1}}sidebar{{/1}}
726
+ {{2}}width{{/2}}: {{3}}grid-width(5){{/3}}
727
+ SASS
728
+ {{1}}sidebar{{/1}} {
729
+ {{2}}width{{/2}}: {{3}}120px{{/3}}; }
730
+
731
+ /*# sourceMappingURL=test.css.map */
732
+ CSS
733
+ end
734
+
735
+ # Regression tests
736
+
737
+ def test_properties_sass
738
+ assert_parses_with_mapping <<SASS, <<CSS, :syntax => :sass
739
+ {{1}}.foo{{/1}}
740
+ :{{2}}name{{/2}} {{3}}value{{/3}}
741
+ {{4}}name{{/4}}: {{5}}value{{/5}}
742
+ :{{6}}name{{/6}} {{7}}value{{/7}}
743
+ {{8}}name{{/8}}: {{9}}value{{/9}}
744
+ SASS
745
+ {{1}}.foo{{/1}} {
746
+ {{2}}name{{/2}}: {{3}}value{{/3}};
747
+ {{4}}name{{/4}}: {{5}}value{{/5}};
748
+ {{6}}name{{/6}}: {{7}}value{{/7}};
749
+ {{8}}name{{/8}}: {{9}}value{{/9}}; }
750
+
751
+ /*# sourceMappingURL=test.css.map */
752
+ CSS
753
+ end
754
+
755
+ private
756
+
757
+ ANNOTATION_REGEX = /\{\{(\/?)([^}]+)\}\}/
758
+
759
+ def build_ranges(text, file_name = nil)
760
+ ranges = Hash.new {|h, k| h[k] = []}
761
+ start_positions = {}
762
+ text.split("\n").each_with_index do |line_text, line|
763
+ line += 1 # lines shoud be 1-based
764
+ while (match = line_text.match(ANNOTATION_REGEX))
765
+ closing = !match[1].empty?
766
+ name = match[2]
767
+ match_offsets = match.offset(0)
768
+ offset = match_offsets[0] + 1 # Offsets are 1-based in source maps.
769
+ assert(!closing || start_positions[name], "Closing annotation #{name} found before opening one.")
770
+ position = Sass::Source::Position.new(line, offset)
771
+ if closing
772
+ ranges[name] << Sass::Source::Range.new(
773
+ start_positions[name], position, file_name,
774
+ Sass::Importers::Filesystem.new('.'))
775
+ start_positions.delete name
776
+ else
777
+ assert(!start_positions[name], "Overlapping range annotation #{name} encountered on line #{line}")
778
+ start_positions[name] = position
779
+ end
780
+ line_text.slice!(match_offsets[0], match_offsets[1] - match_offsets[0])
781
+ end
782
+ end
783
+ ranges
784
+ end
785
+
786
+ def build_mapping_from_annotations(source, css, source_file_name)
787
+ source_ranges = build_ranges(source, source_file_name)
788
+ target_ranges = build_ranges(css)
789
+ map = Sass::Source::Map.new
790
+ Sass::Util.flatten(source_ranges.map do |(name, sources)|
791
+ assert(sources.length == 1, "#{sources.length} source ranges encountered for annotation #{name}")
792
+ assert(target_ranges[name], "No target ranges for annotation #{name}")
793
+ target_ranges[name].map {|target_range| [sources.first, target_range]}
794
+ end, 1).
795
+ sort_by {|(_, target)| [target.start_pos.line, target.start_pos.offset]}.
796
+ each {|(s2, target)| map.add(s2, target)}
797
+ map
798
+ end
799
+
800
+ def assert_parses_with_mapping(source, css, options={})
801
+ options[:syntax] ||= :scss
802
+ input_filename = filename_for_test(options[:syntax])
803
+ mapping = build_mapping_from_annotations(source, css, input_filename)
804
+ source.gsub!(ANNOTATION_REGEX, "")
805
+ css.gsub!(ANNOTATION_REGEX, "")
806
+ rendered, sourcemap = render_with_sourcemap(source, options)
807
+ assert_equal css.rstrip, rendered.rstrip
808
+ assert_sourcemaps_equal source, css, mapping, sourcemap
809
+ end
810
+
811
+ def assert_positions_equal(expected, actual, lines, message = nil)
812
+ prefix = message ? message + ": " : ""
813
+ assert_equal(expected.line, actual.line, prefix +
814
+ "Expected #{expected.inspect} but was #{actual.inspect}")
815
+ assert_equal(expected.offset, actual.offset, prefix +
816
+ "Expected #{expected.inspect} but was #{actual.inspect}\n" +
817
+ lines[actual.line - 1] + "\n" + ("-" * (actual.offset - 1)) + "^")
818
+ end
819
+
820
+ def assert_ranges_equal(expected, actual, lines, prefix)
821
+ assert_positions_equal(expected.start_pos, actual.start_pos, lines, prefix + " start position")
822
+ assert_positions_equal(expected.end_pos, actual.end_pos, lines, prefix + " end position")
823
+ assert_equal(expected.file, actual.file)
824
+ end
825
+
826
+ def assert_sourcemaps_equal(source, css, expected, actual)
827
+ assert_equal(expected.data.length, actual.data.length, <<MESSAGE)
828
+ Wrong number of mappings. Expected:
829
+ #{dump_sourcemap_as_expectation(source, css, expected).gsub(/^/, '| ')}
830
+
831
+ Actual:
832
+ #{dump_sourcemap_as_expectation(source, css, actual).gsub(/^/, '| ')}
833
+ MESSAGE
834
+ source_lines = source.split("\n")
835
+ css_lines = css.split("\n")
836
+ expected.data.zip(actual.data) do |expected_mapping, actual_mapping|
837
+ assert_ranges_equal(expected_mapping.input, actual_mapping.input, source_lines, "Input")
838
+ assert_ranges_equal(expected_mapping.output, actual_mapping.output, css_lines, "Output")
839
+ end
840
+ end
841
+
842
+ def assert_parses_with_sourcemap(source, css, sourcemap_json, options={})
843
+ rendered, sourcemap = render_with_sourcemap(source, options)
844
+ css_path = options[:output] || "test.css"
845
+ sourcemap_path = Sass::Util.sourcemap_name(css_path)
846
+ rendered_json = sourcemap.to_json(:css_path => css_path, :sourcemap_path => sourcemap_path)
847
+
848
+ assert_equal css.rstrip, rendered.rstrip
849
+ assert_equal sourcemap_json.rstrip, rendered_json
850
+ end
851
+
852
+ def render_with_sourcemap(source, options={})
853
+ options[:syntax] ||= :scss
854
+ munge_filename options
855
+ engine = Sass::Engine.new(source, options)
856
+ engine.options[:cache] = false
857
+ sourcemap_path = Sass::Util.sourcemap_name(options[:output] || "test.css")
858
+ engine.render_with_sourcemap File.basename(sourcemap_path)
859
+ end
860
+
861
+ def dump_sourcemap_as_expectation(source, css, sourcemap)
862
+ mappings_to_annotations(source, sourcemap.data.map {|d| d.input}) + "\n\n" +
863
+ "=" * 20 + " maps to:\n\n" +
864
+ mappings_to_annotations(css, sourcemap.data.map {|d| d.output})
865
+ end
866
+
867
+ def mappings_to_annotations(source, ranges)
868
+ additional_offsets = Hash.new(0)
869
+ lines = source.split("\n")
870
+
871
+ add_annotation = lambda do |pos, str|
872
+ line_num = pos.line - 1
873
+ line = lines[line_num]
874
+ offset = pos.offset + additional_offsets[line_num] - 1
875
+ line << " " * (offset - line.length) if offset > line.length
876
+ line.insert(offset, str)
877
+ additional_offsets[line_num] += str.length
878
+ end
879
+
880
+ ranges.each_with_index do |range, i|
881
+ add_annotation[range.start_pos, "{{#{i + 1}}}"]
882
+ add_annotation[range.end_pos, "{{/#{i + 1}}}"]
883
+ end
884
+
885
+ return lines.join("\n")
886
+ end
887
+ end