1#|
2Copyright 2017 Dmitry Arkhipov
3Distributed under the Boost Software License, Version 1.0. (See
4accompanying file LICENSE_1_0.txt or copy at
5http://www.boost.org/LICENSE_1_0.txt)
6|#
7
8import common ;
9import feature ;
10import generators ;
11import modules ;
12import sequence ;
13import toolset ;
14import "class" : new ;
15
16#| tag::doc[]
17
18= Sass
19
20This tool converts SASS and SCSS files into CSS. This tool explicitly supports
21both the version written in C (sassc) and the original Ruby implementation
22(scss) but other variants might also work.  In addition to tool-specific
23features, described in this section, the tool recognizes features `<flags>`
24and `<include>`.
25
26|# # end::doc[]
27
28feature.feature sass : : implicit propagated symmetric ;
29
30#| tag::doc[]
31
32== Feature: `sass-style`
33
34Sets the output style. Available values are
35
36* `nested`: each property is put on its own line, rules are indented based on
37  how deeply they are nested;
38* `expanded`: each property is put on its own line, rules are not indented;
39* `compact`: each rule is put on a single line, nested rules occupy adjacent
40  lines, while groups of unrelated rules are separated by newlines;
41* `compressed`: takes minimum amount of space: all unnecessary whitespace is
42  removed, property values are compressed to have minimal representation.
43
44The feature is `optional` and is not `propagated` to dependent targets. If no
45style is specified, then, if property set contains property `<optimization>on`,
46`compressed` style is selected.  Otherwise, `nested` style is selected.
47
48|# # end::doc[]
49
50feature.subfeature sass
51    : style
52    : nested expanded compact compressed
53    : optional
54    ;
55
56#| tag::doc[]
57
58== Feature: `sass-line-numbers`
59
60Enables emitting comments showing original line numbers for rules. This can be
61useful for debugging a stylesheet. Available values are `on` and `off`. The
62feature is `optional` and is not `propagated` to dependent targets. If no value
63for this feature is specified, then one is copied from the feature
64`debug-symbols`.
65
66|# # end::doc[]
67
68feature.subfeature sass : line-numbers : on off : optional ;
69
70#| tag::doc[]
71
72== Initialization
73
74To use the `sass` tool you need to declare it in a configuration file with the
75`using` rule. The initialization takes the following arguments:
76
77* `command`: the command, with any extra arguments, to execute.
78
79For example you could insert the following in your `user-config.jam`:
80
81```
82using sass : /usr/local/bin/psass -p2 ; # Perl libsass-based version
83```
84
85If no `command` is given, `sassc` is tried, after which `scss` is tried.
86
87|# # end::doc[]
88
89rule init ( command * )
90{
91    if ! $(.initialized)
92    {
93        # Setup only if we were called via "using .. ;"
94        .initialized = true ;
95
96        # Register generators
97        generators.register [ new sass-generator sass.convert : SASS : CSS ] ;
98    }
99
100    # Setting up command
101    if ! $(command)
102    {
103        # If none was specified by the user, first try sassc, then scss
104        SASS = [ common.find-tool sassc ] ;
105        SASS ?= [ common.find-tool scss ] ;
106    }
107    else
108    {
109        # Otherwise we attempt to resolve each component of the command to
110        # account for script interpreter wrappers.
111        SASS = [ sequence.transform maybe-find-tool : $(command) ] ;
112    }
113}
114
115class sass-generator : generator
116{
117    import property-set ;
118
119    rule run ( project name ? : property-set : sources + )
120    {
121        local style = [ $(property-set).get <sass-style> ] ;
122        local line-numbers = [ $(property-set).get <sass-line-numbers> ] ;
123
124        # Only one source file is sensible; we accept only sass and scss files
125        if ( ! $(sources[2]) ) && ( [ $(sources[1]).type ] in SASS )
126        {
127            # If no output name was given, guess it from sources
128            if ! $(name)
129            {
130                name = [ generator.determine-output-name $(sources) ] ;
131            }
132
133            # If output style was not given, then it is determined by
134            # <optimization> feature
135            if ! $(style)
136            {
137                switch [ $(property-set).get <optimization> ]
138                {
139                    case "off" : style = nested ;
140                    case *     : style = compressed ;
141                }
142            }
143
144            # If line-numbers feature wasn't specified, copy it from
145            # <debug-symbols>
146            line-numbers ?= [ $(property-set).get <debug-symbols> ] ;
147        }
148
149        # We build a reduced property set so that we are not toolset dependent.
150        local raw-set
151            = <sass-style>$(style)
152              <sass-line-numbers>$(line-numbers)
153            ;
154        raw-set +=
155            [ sequence.filter recognized-feature : [ $(property-set).raw ] ] ;
156        raw-set = [ feature.expand-composites $(raw-set) ] ;
157        raw-set += [ $(property-set).incidental ] ;
158        property-set = [ property-set.create $(raw-set) ] ;
159        return
160            [ generator.run $(project) $(name)
161            : $(property-set)
162            : $(sources)
163            ] ;
164    }
165
166    local rule recognized-feature ( feature )
167    {
168        local result ;
169        if $(feature:G) in <include> <flags>
170        {
171          result = true ;
172        }
173        return $(result) ;
174    }
175}
176
177_ = " " ;
178toolset.flags sass STYLE : <sass-style> ;
179toolset.flags sass LINE_NUMBERS <sass-line-numbers>on  : --line-numbers ;
180toolset.flags sass INCLUDES : <include> ;
181toolset.flags sass FLAGS : <flags> ;
182
183actions convert
184{
185  "$(SASS)" -t$(_)"$(STYLE)" $(LINE_NUMBERS) -I$(_)"$(INCLUDES)" $(FLAGS) "$(>)" $(_)"$(<)"
186}
187
188local rule maybe-find-tool ( command )
189{
190    local tool = [ common.find-tool $(command) ] ;
191    tool ?= $(command) ;
192    return $(tool) ;
193}
194