oreorenasass 3.4.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 (268) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +11 -0
  3. data/CONTRIBUTING +3 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +221 -0
  6. data/Rakefile +370 -0
  7. data/VERSION +1 -0
  8. data/VERSION_NAME +1 -0
  9. data/bin/sass +13 -0
  10. data/bin/sass-convert +12 -0
  11. data/bin/scss +13 -0
  12. data/extra/update_watch.rb +13 -0
  13. data/init.rb +18 -0
  14. data/lib/sass/cache_stores/base.rb +88 -0
  15. data/lib/sass/cache_stores/chain.rb +34 -0
  16. data/lib/sass/cache_stores/filesystem.rb +60 -0
  17. data/lib/sass/cache_stores/memory.rb +47 -0
  18. data/lib/sass/cache_stores/null.rb +25 -0
  19. data/lib/sass/cache_stores.rb +15 -0
  20. data/lib/sass/callbacks.rb +67 -0
  21. data/lib/sass/css.rb +407 -0
  22. data/lib/sass/engine.rb +1181 -0
  23. data/lib/sass/environment.rb +191 -0
  24. data/lib/sass/error.rb +198 -0
  25. data/lib/sass/exec/base.rb +187 -0
  26. data/lib/sass/exec/sass_convert.rb +264 -0
  27. data/lib/sass/exec/sass_scss.rb +424 -0
  28. data/lib/sass/exec.rb +9 -0
  29. data/lib/sass/features.rb +47 -0
  30. data/lib/sass/importers/base.rb +182 -0
  31. data/lib/sass/importers/filesystem.rb +211 -0
  32. data/lib/sass/importers.rb +22 -0
  33. data/lib/sass/logger/base.rb +30 -0
  34. data/lib/sass/logger/log_level.rb +45 -0
  35. data/lib/sass/logger.rb +12 -0
  36. data/lib/sass/media.rb +210 -0
  37. data/lib/sass/plugin/compiler.rb +565 -0
  38. data/lib/sass/plugin/configuration.rb +118 -0
  39. data/lib/sass/plugin/generic.rb +15 -0
  40. data/lib/sass/plugin/merb.rb +48 -0
  41. data/lib/sass/plugin/rack.rb +60 -0
  42. data/lib/sass/plugin/rails.rb +47 -0
  43. data/lib/sass/plugin/staleness_checker.rb +199 -0
  44. data/lib/sass/plugin.rb +133 -0
  45. data/lib/sass/railtie.rb +10 -0
  46. data/lib/sass/repl.rb +57 -0
  47. data/lib/sass/root.rb +7 -0
  48. data/lib/sass/script/css_lexer.rb +33 -0
  49. data/lib/sass/script/css_parser.rb +34 -0
  50. data/lib/sass/script/functions.rb +2626 -0
  51. data/lib/sass/script/lexer.rb +449 -0
  52. data/lib/sass/script/parser.rb +637 -0
  53. data/lib/sass/script/tree/funcall.rb +306 -0
  54. data/lib/sass/script/tree/interpolation.rb +118 -0
  55. data/lib/sass/script/tree/list_literal.rb +77 -0
  56. data/lib/sass/script/tree/literal.rb +45 -0
  57. data/lib/sass/script/tree/map_literal.rb +64 -0
  58. data/lib/sass/script/tree/node.rb +109 -0
  59. data/lib/sass/script/tree/operation.rb +103 -0
  60. data/lib/sass/script/tree/selector.rb +26 -0
  61. data/lib/sass/script/tree/string_interpolation.rb +104 -0
  62. data/lib/sass/script/tree/unary_operation.rb +69 -0
  63. data/lib/sass/script/tree/variable.rb +57 -0
  64. data/lib/sass/script/tree.rb +16 -0
  65. data/lib/sass/script/value/arg_list.rb +36 -0
  66. data/lib/sass/script/value/base.rb +240 -0
  67. data/lib/sass/script/value/bool.rb +35 -0
  68. data/lib/sass/script/value/color.rb +680 -0
  69. data/lib/sass/script/value/helpers.rb +262 -0
  70. data/lib/sass/script/value/list.rb +113 -0
  71. data/lib/sass/script/value/map.rb +70 -0
  72. data/lib/sass/script/value/null.rb +44 -0
  73. data/lib/sass/script/value/number.rb +530 -0
  74. data/lib/sass/script/value/string.rb +97 -0
  75. data/lib/sass/script/value.rb +11 -0
  76. data/lib/sass/script.rb +66 -0
  77. data/lib/sass/scss/css_parser.rb +42 -0
  78. data/lib/sass/scss/parser.rb +1209 -0
  79. data/lib/sass/scss/rx.rb +141 -0
  80. data/lib/sass/scss/script_lexer.rb +15 -0
  81. data/lib/sass/scss/script_parser.rb +25 -0
  82. data/lib/sass/scss/static_parser.rb +368 -0
  83. data/lib/sass/scss.rb +16 -0
  84. data/lib/sass/selector/abstract_sequence.rb +109 -0
  85. data/lib/sass/selector/comma_sequence.rb +175 -0
  86. data/lib/sass/selector/pseudo.rb +256 -0
  87. data/lib/sass/selector/sequence.rb +600 -0
  88. data/lib/sass/selector/simple.rb +117 -0
  89. data/lib/sass/selector/simple_sequence.rb +325 -0
  90. data/lib/sass/selector.rb +326 -0
  91. data/lib/sass/shared.rb +76 -0
  92. data/lib/sass/source/map.rb +210 -0
  93. data/lib/sass/source/position.rb +39 -0
  94. data/lib/sass/source/range.rb +41 -0
  95. data/lib/sass/stack.rb +120 -0
  96. data/lib/sass/supports.rb +227 -0
  97. data/lib/sass/tree/at_root_node.rb +83 -0
  98. data/lib/sass/tree/charset_node.rb +22 -0
  99. data/lib/sass/tree/comment_node.rb +82 -0
  100. data/lib/sass/tree/content_node.rb +9 -0
  101. data/lib/sass/tree/css_import_node.rb +60 -0
  102. data/lib/sass/tree/debug_node.rb +18 -0
  103. data/lib/sass/tree/directive_node.rb +59 -0
  104. data/lib/sass/tree/each_node.rb +24 -0
  105. data/lib/sass/tree/error_node.rb +18 -0
  106. data/lib/sass/tree/extend_node.rb +43 -0
  107. data/lib/sass/tree/for_node.rb +36 -0
  108. data/lib/sass/tree/function_node.rb +39 -0
  109. data/lib/sass/tree/if_node.rb +52 -0
  110. data/lib/sass/tree/import_node.rb +74 -0
  111. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  112. data/lib/sass/tree/media_node.rb +48 -0
  113. data/lib/sass/tree/mixin_def_node.rb +38 -0
  114. data/lib/sass/tree/mixin_node.rb +52 -0
  115. data/lib/sass/tree/node.rb +238 -0
  116. data/lib/sass/tree/prop_node.rb +171 -0
  117. data/lib/sass/tree/return_node.rb +19 -0
  118. data/lib/sass/tree/root_node.rb +44 -0
  119. data/lib/sass/tree/rule_node.rb +145 -0
  120. data/lib/sass/tree/supports_node.rb +38 -0
  121. data/lib/sass/tree/trace_node.rb +33 -0
  122. data/lib/sass/tree/variable_node.rb +36 -0
  123. data/lib/sass/tree/visitors/base.rb +72 -0
  124. data/lib/sass/tree/visitors/check_nesting.rb +177 -0
  125. data/lib/sass/tree/visitors/convert.rb +334 -0
  126. data/lib/sass/tree/visitors/cssize.rb +369 -0
  127. data/lib/sass/tree/visitors/deep_copy.rb +107 -0
  128. data/lib/sass/tree/visitors/extend.rb +68 -0
  129. data/lib/sass/tree/visitors/perform.rb +539 -0
  130. data/lib/sass/tree/visitors/set_options.rb +139 -0
  131. data/lib/sass/tree/visitors/to_css.rb +381 -0
  132. data/lib/sass/tree/warn_node.rb +18 -0
  133. data/lib/sass/tree/while_node.rb +18 -0
  134. data/lib/sass/util/cross_platform_random.rb +19 -0
  135. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  136. data/lib/sass/util/normalized_map.rb +130 -0
  137. data/lib/sass/util/ordered_hash.rb +192 -0
  138. data/lib/sass/util/subset_map.rb +110 -0
  139. data/lib/sass/util/test.rb +9 -0
  140. data/lib/sass/util.rb +1318 -0
  141. data/lib/sass/version.rb +124 -0
  142. data/lib/sass.rb +102 -0
  143. data/rails/init.rb +1 -0
  144. data/test/sass/cache_test.rb +131 -0
  145. data/test/sass/callbacks_test.rb +61 -0
  146. data/test/sass/compiler_test.rb +232 -0
  147. data/test/sass/conversion_test.rb +2054 -0
  148. data/test/sass/css2sass_test.rb +477 -0
  149. data/test/sass/data/hsl-rgb.txt +319 -0
  150. data/test/sass/encoding_test.rb +219 -0
  151. data/test/sass/engine_test.rb +3301 -0
  152. data/test/sass/exec_test.rb +86 -0
  153. data/test/sass/extend_test.rb +1661 -0
  154. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  155. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  156. data/test/sass/functions_test.rb +1926 -0
  157. data/test/sass/importer_test.rb +412 -0
  158. data/test/sass/logger_test.rb +58 -0
  159. data/test/sass/mock_importer.rb +49 -0
  160. data/test/sass/more_results/more1.css +9 -0
  161. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  162. data/test/sass/more_results/more_import.css +29 -0
  163. data/test/sass/more_templates/_more_partial.sass +2 -0
  164. data/test/sass/more_templates/more1.sass +23 -0
  165. data/test/sass/more_templates/more_import.sass +11 -0
  166. data/test/sass/plugin_test.rb +554 -0
  167. data/test/sass/results/alt.css +4 -0
  168. data/test/sass/results/basic.css +9 -0
  169. data/test/sass/results/cached_import_option.css +3 -0
  170. data/test/sass/results/compact.css +5 -0
  171. data/test/sass/results/complex.css +86 -0
  172. data/test/sass/results/compressed.css +1 -0
  173. data/test/sass/results/expanded.css +19 -0
  174. data/test/sass/results/filename_fn.css +3 -0
  175. data/test/sass/results/if.css +3 -0
  176. data/test/sass/results/import.css +31 -0
  177. data/test/sass/results/import_charset.css +5 -0
  178. data/test/sass/results/import_charset_1_8.css +5 -0
  179. data/test/sass/results/import_charset_ibm866.css +5 -0
  180. data/test/sass/results/import_content.css +1 -0
  181. data/test/sass/results/line_numbers.css +49 -0
  182. data/test/sass/results/mixins.css +95 -0
  183. data/test/sass/results/multiline.css +24 -0
  184. data/test/sass/results/nested.css +22 -0
  185. data/test/sass/results/options.css +1 -0
  186. data/test/sass/results/parent_ref.css +13 -0
  187. data/test/sass/results/script.css +16 -0
  188. data/test/sass/results/scss_import.css +31 -0
  189. data/test/sass/results/scss_importee.css +2 -0
  190. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  191. data/test/sass/results/subdir/subdir.css +3 -0
  192. data/test/sass/results/units.css +11 -0
  193. data/test/sass/results/warn.css +0 -0
  194. data/test/sass/results/warn_imported.css +0 -0
  195. data/test/sass/script_conversion_test.rb +328 -0
  196. data/test/sass/script_test.rb +1054 -0
  197. data/test/sass/scss/css_test.rb +1215 -0
  198. data/test/sass/scss/rx_test.rb +156 -0
  199. data/test/sass/scss/scss_test.rb +3900 -0
  200. data/test/sass/scss/test_helper.rb +37 -0
  201. data/test/sass/source_map_test.rb +977 -0
  202. data/test/sass/superselector_test.rb +191 -0
  203. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  204. data/test/sass/templates/_double_import_loop2.sass +1 -0
  205. data/test/sass/templates/_filename_fn_import.scss +11 -0
  206. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  207. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  208. data/test/sass/templates/_imported_content.sass +3 -0
  209. data/test/sass/templates/_partial.sass +2 -0
  210. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  211. data/test/sass/templates/alt.sass +16 -0
  212. data/test/sass/templates/basic.sass +23 -0
  213. data/test/sass/templates/bork1.sass +2 -0
  214. data/test/sass/templates/bork2.sass +2 -0
  215. data/test/sass/templates/bork3.sass +2 -0
  216. data/test/sass/templates/bork4.sass +2 -0
  217. data/test/sass/templates/bork5.sass +3 -0
  218. data/test/sass/templates/cached_import_option.scss +3 -0
  219. data/test/sass/templates/compact.sass +17 -0
  220. data/test/sass/templates/complex.sass +305 -0
  221. data/test/sass/templates/compressed.sass +15 -0
  222. data/test/sass/templates/double_import_loop1.sass +1 -0
  223. data/test/sass/templates/expanded.sass +17 -0
  224. data/test/sass/templates/filename_fn.scss +18 -0
  225. data/test/sass/templates/if.sass +11 -0
  226. data/test/sass/templates/import.sass +12 -0
  227. data/test/sass/templates/import_charset.sass +9 -0
  228. data/test/sass/templates/import_charset_1_8.sass +6 -0
  229. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  230. data/test/sass/templates/import_content.sass +4 -0
  231. data/test/sass/templates/importee.less +2 -0
  232. data/test/sass/templates/importee.sass +19 -0
  233. data/test/sass/templates/line_numbers.sass +13 -0
  234. data/test/sass/templates/mixin_bork.sass +5 -0
  235. data/test/sass/templates/mixins.sass +76 -0
  236. data/test/sass/templates/multiline.sass +20 -0
  237. data/test/sass/templates/nested.sass +25 -0
  238. data/test/sass/templates/nested_bork1.sass +2 -0
  239. data/test/sass/templates/nested_bork2.sass +2 -0
  240. data/test/sass/templates/nested_bork3.sass +2 -0
  241. data/test/sass/templates/nested_bork4.sass +2 -0
  242. data/test/sass/templates/nested_import.sass +2 -0
  243. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  244. data/test/sass/templates/options.sass +2 -0
  245. data/test/sass/templates/parent_ref.sass +25 -0
  246. data/test/sass/templates/same_name_different_ext.sass +2 -0
  247. data/test/sass/templates/same_name_different_ext.scss +1 -0
  248. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  249. data/test/sass/templates/script.sass +101 -0
  250. data/test/sass/templates/scss_import.scss +12 -0
  251. data/test/sass/templates/scss_importee.scss +1 -0
  252. data/test/sass/templates/single_import_loop.sass +1 -0
  253. data/test/sass/templates/subdir/import_up1.scss +1 -0
  254. data/test/sass/templates/subdir/import_up2.scss +1 -0
  255. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  256. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  257. data/test/sass/templates/subdir/subdir.sass +6 -0
  258. data/test/sass/templates/units.sass +11 -0
  259. data/test/sass/templates/warn.sass +3 -0
  260. data/test/sass/templates/warn_imported.sass +4 -0
  261. data/test/sass/test_helper.rb +8 -0
  262. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  263. data/test/sass/util/normalized_map_test.rb +51 -0
  264. data/test/sass/util/subset_map_test.rb +91 -0
  265. data/test/sass/util_test.rb +467 -0
  266. data/test/sass/value_helpers_test.rb +179 -0
  267. data/test/test_helper.rb +109 -0
  268. metadata +386 -0
data/lib/sass/exec.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Sass
2
+ # This module handles the Sass executables (`sass` and `sass-convert`).
3
+ module Exec
4
+ end
5
+ end
6
+
7
+ require 'sass/exec/base'
8
+ require 'sass/exec/sass_scss'
9
+ require 'sass/exec/sass_convert'
@@ -0,0 +1,47 @@
1
+ require 'set'
2
+ module Sass
3
+ # Provides `Sass.has_feature?` which allows for simple feature detection
4
+ # by providing a feature name.
5
+ module Features
6
+ # This is the set of features that can be detected.
7
+ #
8
+ # When this is updated, the documentation of `feature-exists()` should be
9
+ # updated as well.
10
+ KNOWN_FEATURES = Set[*%w{
11
+ global-variable-shadowing
12
+ extend-selector-pseudoclass
13
+ units-level-3
14
+ at-error
15
+ }]
16
+
17
+ # Check if a feature exists by name. This is used to implement
18
+ # the Sass function `feature-exists($feature)`
19
+ #
20
+ # @param feature_name [String] The case sensitive name of the feature to
21
+ # check if it exists in this version of Sass.
22
+ # @return [Boolean] whether the feature of that name exists.
23
+ def has_feature?(feature_name)
24
+ KNOWN_FEATURES.include?(feature_name)
25
+ end
26
+
27
+ # Add a feature to Sass. Plugins can use this to easily expose their
28
+ # availability to end users. Plugins must prefix their feature
29
+ # names with a dash to distinguish them from official features.
30
+ #
31
+ # @example
32
+ # Sass.add_feature("-import-globbing")
33
+ # Sass.add_feature("-math-cos")
34
+ #
35
+ #
36
+ # @param feature_name [String] The case sensitive name of the feature to
37
+ # to add to Sass. Must begin with a dash.
38
+ def add_feature(feature_name)
39
+ unless feature_name[0] == ?-
40
+ raise ArgumentError.new("Plugin feature names must begin with a dash")
41
+ end
42
+ KNOWN_FEATURES << feature_name
43
+ end
44
+ end
45
+
46
+ extend Features
47
+ end
@@ -0,0 +1,182 @@
1
+ module Sass
2
+ module Importers
3
+ # The abstract base class for Sass importers.
4
+ # All importers should inherit from this.
5
+ #
6
+ # At the most basic level, an importer is given a string
7
+ # and must return a {Sass::Engine} containing some Sass code.
8
+ # This string can be interpreted however the importer wants;
9
+ # however, subclasses are encouraged to use the URI format
10
+ # for pathnames.
11
+ #
12
+ # Importers that have some notion of "relative imports"
13
+ # should take a single load path in their constructor,
14
+ # and interpret paths as relative to that.
15
+ # They should also implement the \{#find\_relative} method.
16
+ #
17
+ # Importers should be serializable via `Marshal.dump`.
18
+ #
19
+ # @abstract
20
+ class Base
21
+ # Find a Sass file relative to another file.
22
+ # Importers without a notion of "relative paths"
23
+ # should just return nil here.
24
+ #
25
+ # If the importer does have a notion of "relative paths",
26
+ # it should ignore its load path during this method.
27
+ #
28
+ # See \{#find} for important information on how this method should behave.
29
+ #
30
+ # The `:filename` option passed to the returned {Sass::Engine}
31
+ # should be of a format that could be passed to \{#find}.
32
+ #
33
+ # @param uri [String] The URI to import. This is not necessarily relative,
34
+ # but this method should only return true if it is.
35
+ # @param base [String] The base filename. If `uri` is relative,
36
+ # it should be interpreted as relative to `base`.
37
+ # `base` is guaranteed to be in a format importable by this importer.
38
+ # @param options [{Symbol => Object}] Options for the Sass file
39
+ # containing the `@import` that's currently being resolved.
40
+ # @return [Sass::Engine, nil] An Engine containing the imported file,
41
+ # or nil if it couldn't be found or was in the wrong format.
42
+ def find_relative(uri, base, options)
43
+ Sass::Util.abstract(self)
44
+ end
45
+
46
+ # Find a Sass file, if it exists.
47
+ #
48
+ # This is the primary entry point of the Importer.
49
+ # It corresponds directly to an `@import` statement in Sass.
50
+ # It should do three basic things:
51
+ #
52
+ # * Determine if the URI is in this importer's format.
53
+ # If not, return nil.
54
+ # * Determine if the file indicated by the URI actually exists and is readable.
55
+ # If not, return nil.
56
+ # * Read the file and place the contents in a {Sass::Engine}.
57
+ # Return that engine.
58
+ #
59
+ # If this importer's format allows for file extensions,
60
+ # it should treat them the same way as the default {Filesystem} importer.
61
+ # If the URI explicitly has a `.sass` or `.scss` filename,
62
+ # the importer should look for that exact file
63
+ # and import it as the syntax indicated.
64
+ # If it doesn't exist, the importer should return nil.
65
+ #
66
+ # If the URI doesn't have either of these extensions,
67
+ # the importer should look for files with the extensions.
68
+ # If no such files exist, it should return nil.
69
+ #
70
+ # The {Sass::Engine} to be returned should be passed `options`,
71
+ # with a few modifications. `:syntax` should be set appropriately,
72
+ # `:filename` should be set to `uri`,
73
+ # and `:importer` should be set to this importer.
74
+ #
75
+ # @param uri [String] The URI to import.
76
+ # @param options [{Symbol => Object}] Options for the Sass file
77
+ # containing the `@import` that's currently being resolved.
78
+ # This is safe for subclasses to modify destructively.
79
+ # Callers should only pass in a value they don't mind being destructively modified.
80
+ # @return [Sass::Engine, nil] An Engine containing the imported file,
81
+ # or nil if it couldn't be found or was in the wrong format.
82
+ def find(uri, options)
83
+ Sass::Util.abstract(self)
84
+ end
85
+
86
+ # Returns the time the given Sass file was last modified.
87
+ #
88
+ # If the given file has been deleted or the time can't be accessed
89
+ # for some other reason, this should return nil.
90
+ #
91
+ # @param uri [String] The URI of the file to check.
92
+ # Comes from a `:filename` option set on an engine returned by this importer.
93
+ # @param options [{Symbol => Objet}] Options for the Sass file
94
+ # containing the `@import` currently being checked.
95
+ # @return [Time, nil]
96
+ def mtime(uri, options)
97
+ Sass::Util.abstract(self)
98
+ end
99
+
100
+ # Get the cache key pair for the given Sass URI.
101
+ # The URI need not be checked for validity.
102
+ #
103
+ # The only strict requirement is that the returned pair of strings
104
+ # uniquely identify the file at the given URI.
105
+ # However, the first component generally corresponds roughly to the directory,
106
+ # and the second to the basename, of the URI.
107
+ #
108
+ # Note that keys must be unique *across importers*.
109
+ # Thus it's probably a good idea to include the importer name
110
+ # at the beginning of the first component.
111
+ #
112
+ # @param uri [String] A URI known to be valid for this importer.
113
+ # @param options [{Symbol => Object}] Options for the Sass file
114
+ # containing the `@import` currently being checked.
115
+ # @return [(String, String)] The key pair which uniquely identifies
116
+ # the file at the given URI.
117
+ def key(uri, options)
118
+ Sass::Util.abstract(self)
119
+ end
120
+
121
+ # Get the publicly-visible URL for an imported file. This URL is used by
122
+ # source maps to link to the source stylesheet. This may return `nil` to
123
+ # indicate that no public URL is available; however, this will cause
124
+ # sourcemap generation to fail if any CSS is generated from files imported
125
+ # from this importer.
126
+ #
127
+ # If an absolute "file:" URI can be produced for an imported file, that
128
+ # should be preferred to returning `nil`. However, a URL relative to
129
+ # `sourcemap_directory` should be preferred over an absolute "file:" URI.
130
+ #
131
+ # @param uri [String] A URI known to be valid for this importer.
132
+ # @param sourcemap_directory [String, NilClass] The absolute path to a
133
+ # directory on disk where the sourcemap will be saved. If uri refers to
134
+ # a file on disk that's accessible relative to sourcemap_directory, this
135
+ # may return a relative URL. This may be `nil` if the sourcemap's
136
+ # eventual location is unknown.
137
+ # @return [String?] The publicly-visible URL for this file, or `nil`
138
+ # indicating that no publicly-visible URL exists. This should be
139
+ # appropriately URL-escaped.
140
+ def public_url(uri, sourcemap_directory)
141
+ return if @public_url_warning_issued
142
+ @public_url_warning_issued = true
143
+ Sass::Util.sass_warn <<WARNING
144
+ WARNING: #{self.class.name} should define the #public_url method.
145
+ WARNING
146
+ nil
147
+ end
148
+
149
+ # A string representation of the importer.
150
+ # Should be overridden by subclasses.
151
+ #
152
+ # This is used to help debugging,
153
+ # and should usually just show the load path encapsulated by this importer.
154
+ #
155
+ # @return [String]
156
+ def to_s
157
+ Sass::Util.abstract(self)
158
+ end
159
+
160
+ # If the importer is based on files on the local filesystem
161
+ # this method should return folders which should be watched
162
+ # for changes.
163
+ #
164
+ # @return [Array<String>] List of absolute paths of directories to watch
165
+ def directories_to_watch
166
+ []
167
+ end
168
+
169
+ # If this importer is based on files on the local filesystem This method
170
+ # should return true if the file, when changed, should trigger a
171
+ # recompile.
172
+ #
173
+ # It is acceptable for non-sass files to be watched and trigger a recompile.
174
+ #
175
+ # @param filename [String] The absolute filename for a file that has changed.
176
+ # @return [Boolean] When the file changed should cause a recompile.
177
+ def watched_file?(filename)
178
+ false
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,211 @@
1
+ require 'set'
2
+
3
+ module Sass
4
+ module Importers
5
+ # The default importer, used for any strings found in the load path.
6
+ # Simply loads Sass files from the filesystem using the default logic.
7
+ class Filesystem < Base
8
+ attr_accessor :root
9
+
10
+ # Creates a new filesystem importer that imports files relative to a given path.
11
+ #
12
+ # @param root [String] The root path.
13
+ # This importer will import files relative to this path.
14
+ def initialize(root)
15
+ @root = File.expand_path(root)
16
+ @same_name_warnings = Set.new
17
+ end
18
+
19
+ # @see Base#find_relative
20
+ def find_relative(name, base, options)
21
+ _find(File.dirname(base), name, options)
22
+ end
23
+
24
+ # @see Base#find
25
+ def find(name, options)
26
+ _find(@root, name, options)
27
+ end
28
+
29
+ # @see Base#mtime
30
+ def mtime(name, options)
31
+ file, _ = Sass::Util.destructure(find_real_file(@root, name, options))
32
+ File.mtime(file) if file
33
+ rescue Errno::ENOENT
34
+ nil
35
+ end
36
+
37
+ # @see Base#key
38
+ def key(name, options)
39
+ [self.class.name + ":" + File.dirname(File.expand_path(name)),
40
+ File.basename(name)]
41
+ end
42
+
43
+ # @see Base#to_s
44
+ def to_s
45
+ @root
46
+ end
47
+
48
+ def hash
49
+ @root.hash
50
+ end
51
+
52
+ def eql?(other)
53
+ root.eql?(other.root)
54
+ end
55
+
56
+ # @see Base#directories_to_watch
57
+ def directories_to_watch
58
+ [root]
59
+ end
60
+
61
+ # @see Base#watched_file?
62
+ def watched_file?(filename)
63
+ filename =~ /\.s[ac]ss$/ &&
64
+ filename.start_with?(root + File::SEPARATOR)
65
+ end
66
+
67
+ def public_url(name, sourcemap_directory)
68
+ file_pathname = Sass::Util.cleanpath(Sass::Util.absolute_path(name, @root))
69
+ if sourcemap_directory.nil?
70
+ Sass::Util.file_uri_from_path(file_pathname)
71
+ else
72
+ sourcemap_pathname = Sass::Util.cleanpath(sourcemap_directory)
73
+ begin
74
+ Sass::Util.file_uri_from_path(file_pathname.relative_path_from(sourcemap_pathname))
75
+ rescue ArgumentError # when a relative path cannot be constructed
76
+ Sass::Util.file_uri_from_path(file_pathname)
77
+ end
78
+ end
79
+ end
80
+
81
+ protected
82
+
83
+ # If a full uri is passed, this removes the root from it
84
+ # otherwise returns the name unchanged
85
+ def remove_root(name)
86
+ if name.index(@root + "/") == 0
87
+ name[(@root.length + 1)..-1]
88
+ else
89
+ name
90
+ end
91
+ end
92
+
93
+ # A hash from file extensions to the syntaxes for those extensions.
94
+ # The syntaxes must be `:sass` or `:scss`.
95
+ #
96
+ # This can be overridden by subclasses that want normal filesystem importing
97
+ # with unusual extensions.
98
+ #
99
+ # @return [{String => Symbol}]
100
+ def extensions
101
+ {'sass' => :sass, 'scss' => :scss}
102
+ end
103
+
104
+ # Given an `@import`ed path, returns an array of possible
105
+ # on-disk filenames and their corresponding syntaxes for that path.
106
+ #
107
+ # @param name [String] The filename.
108
+ # @return [Array(String, Symbol)] An array of pairs.
109
+ # The first element of each pair is a filename to look for;
110
+ # the second element is the syntax that file would be in (`:sass` or `:scss`).
111
+ def possible_files(name)
112
+ name = escape_glob_characters(name)
113
+ dirname, basename, extname = split(name)
114
+ sorted_exts = extensions.sort
115
+ syntax = extensions[extname]
116
+
117
+ if syntax
118
+ ret = [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]]
119
+ else
120
+ ret = sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
121
+ end
122
+
123
+ # JRuby chokes when trying to import files from JARs when the path starts with './'.
124
+ ret.map {|f, s| [f.sub(/^\.\//, ''), s]}
125
+ end
126
+
127
+ def escape_glob_characters(name)
128
+ name.gsub(/[\*\[\]\{\}\?]/) do |char|
129
+ "\\#{char}"
130
+ end
131
+ end
132
+
133
+ REDUNDANT_DIRECTORY = /#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}/
134
+ # Given a base directory and an `@import`ed name,
135
+ # finds an existant file that matches the name.
136
+ #
137
+ # @param dir [String] The directory relative to which to search.
138
+ # @param name [String] The filename to search for.
139
+ # @return [(String, Symbol)] A filename-syntax pair.
140
+ def find_real_file(dir, name, options)
141
+ # On windows 'dir' or 'name' can be in native File::ALT_SEPARATOR form.
142
+ dir = dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
143
+ name = name.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
144
+
145
+ found = possible_files(remove_root(name)).map do |f, s|
146
+ path = (dir == "." || Sass::Util.pathname(f).absolute?) ? f :
147
+ "#{escape_glob_characters(dir)}/#{f}"
148
+ Dir[path].map do |full_path|
149
+ full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
150
+ [Sass::Util.cleanpath(full_path).to_s, s]
151
+ end
152
+ end
153
+ found = Sass::Util.flatten(found, 1)
154
+ return if found.empty?
155
+
156
+ if found.size > 1 && !@same_name_warnings.include?(found.first.first)
157
+ found.each {|(f, _)| @same_name_warnings << f}
158
+ relative_to = Sass::Util.pathname(dir)
159
+ if options[:_from_import_node]
160
+ # If _line exists, we're here due to an actual import in an
161
+ # import_node and we want to print a warning for a user writing an
162
+ # ambiguous import.
163
+ candidates = found.map do |(f, _)|
164
+ " " + Sass::Util.pathname(f).relative_path_from(relative_to).to_s
165
+ end.join("\n")
166
+ raise Sass::SyntaxError.new(<<MESSAGE)
167
+ It's not clear which file to import for '@import "#{name}"'.
168
+ Candidates:
169
+ #{candidates}
170
+ Please delete or rename all but one of these files.
171
+ MESSAGE
172
+ else
173
+ # Otherwise, we're here via StalenessChecker, and we want to print a
174
+ # warning for a user running `sass --watch` with two ambiguous files.
175
+ candidates = found.map {|(f, _)| " " + File.basename(f)}.join("\n")
176
+ Sass::Util.sass_warn <<WARNING
177
+ WARNING: In #{File.dirname(name)}:
178
+ There are multiple files that match the name "#{File.basename(name)}":
179
+ #{candidates}
180
+ WARNING
181
+ end
182
+ end
183
+ found.first
184
+ end
185
+
186
+ # Splits a filename into three parts, a directory part, a basename, and an extension
187
+ # Only the known extensions returned from the extensions method will be recognized as such.
188
+ def split(name)
189
+ extension = nil
190
+ dirname, basename = File.dirname(name), File.basename(name)
191
+ if basename =~ /^(.*)\.(#{extensions.keys.map {|e| Regexp.escape(e)}.join('|')})$/
192
+ basename = $1
193
+ extension = $2
194
+ end
195
+ [dirname, basename, extension]
196
+ end
197
+
198
+ private
199
+
200
+ def _find(dir, name, options)
201
+ full_filename, syntax = Sass::Util.destructure(find_real_file(dir, name, options))
202
+ return unless full_filename && File.readable?(full_filename)
203
+
204
+ options[:syntax] = syntax
205
+ options[:filename] = full_filename
206
+ options[:importer] = self
207
+ Sass::Engine.new(File.read(full_filename), options)
208
+ end
209
+ end
210
+ end
211
+ end