#|
Copyright 2017 Dmitry Arkhipov
Distributed under the Boost Software License, Version 1.0. (See
accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
|#
import common ;
import feature ;
import generators ;
import modules ;
import sequence ;
import toolset ;
import "class" : new ;
#| tag::doc[]
= Sass
This tool converts SASS and SCSS files into CSS. This tool explicitly supports
both the version written in C (sassc) and the original Ruby implementation
(scss) but other variants might also work. In addition to tool-specific
features, described in this section, the tool recognizes features `<flags>`
and `<include>`.
|# # end::doc[]
feature.feature sass : : implicit propagated symmetric ;
#| tag::doc[]
== Feature: `sass-style`
Sets the output style. Available values are
* `nested`: each property is put on its own line, rules are indented based on
how deeply they are nested;
* `expanded`: each property is put on its own line, rules are not indented;
* `compact`: each rule is put on a single line, nested rules occupy adjacent
lines, while groups of unrelated rules are separated by newlines;
* `compressed`: takes minimum amount of space: all unnecessary whitespace is
removed, property values are compressed to have minimal representation.
The feature is `optional` and is not `propagated` to dependent targets. If no
style is specified, then, if property set contains property `<optimization>on`,
`compressed` style is selected. Otherwise, `nested` style is selected.
|# # end::doc[]
feature.subfeature sass
: style
: nested expanded compact compressed
: optional
;
#| tag::doc[]
== Feature: `sass-line-numbers`
Enables emitting comments showing original line numbers for rules. This can be
useful for debugging a stylesheet. Available values are `on` and `off`. The
feature is `optional` and is not `propagated` to dependent targets. If no value
for this feature is specified, then one is copied from the feature
`debug-symbols`.
|# end::doc[]
feature.subfeature sass : line-numbers : on off : optional ;
#| tag::doc[]
== Initialization
To use the `sass` tool you need to declare it in a configuration file with the
`using` rule. The initialization takes the following arguments:
* `command`: the command, with any extra arguments, to execute.
For example you could insert the following in your `user-config.jam`:
```
using sass : /usr/local/bin/psass -p2 ; # Perl libsass-based version
```
If no `command` is given, `sassc` is tried, after which `scss` is tried.
|# # end::doc[]
rule init ( command * )
{
if ! $(.initialized)
{
# Setup only if we were called via "using .. ;"
.initialized = true ;
# Register generators
generators.register [ new sass-generator sass.convert : SASS : CSS ] ;
}
# Setting up command
if ! $(command)
{
# If none was specified by the user, first try sassc, then scss
SASS = [ common.find-tool sassc ] ;
SASS ?= [ common.find-tool scss ] ;
}
else
{
# Otherwise we attempt to resolve each component of the command to
# account for script interpreter wrappers.
SASS = [ sequence.transform maybe-find-tool : $(command) ] ;
}
}
class sass-generator : generator
{
import property-set ;
rule run ( project name ? : property-set : sources + )
{
local style = [ $(property-set).get <sass-style> ] ;
local line-numbers = [ $(property-set).get <sass-line-numbers> ] ;
# Only one source file is sensible; we accept only sass and scss files
if ( ! $(sources[2]) ) && ( [ $(sources[1]).type ] in SASS )
{
# If no output name was given, guess it from sources
if ! $(name)
{
name = [ generator.determine-output-name $(sources) ] ;
}
# If output style was not given, then it is determined by
# <optimization> feature
if ! $(style)
{
switch [ $(property-set).get <optimization> ]
{
case "off" : style = nested ;
case * : style = compressed ;
}
}
# If line-numbers feature wasn't specified, copy it from
# <debug-symbols>
line-numbers ?= [ $(property-set).get <debug-symbols> ] ;
}
# We build a reduced property set so that we are not toolset dependent.
local raw-set
= <sass-style>$(style)
<sass-line-numbers>$(line-numbers)
;
raw-set +=
[ sequence.filter recognized-feature : [ $(property-set).raw ] ] ;
raw-set = [ feature.expand-composites $(raw-set) ] ;
raw-set += [ $(property-set).incidental ] ;
property-set = [ property-set.create $(raw-set) ] ;
return
[ generator.run $(project) $(name)
: $(property-set)
: $(sources)
] ;
}
local rule recognized-feature ( feature )
{
local result ;
if $(feature:G) in <include> <flags>
{
result = true ;
}
return $(result) ;
}
}
_ = " " ;
toolset.flags sass STYLE : <sass-style> ;
toolset.flags sass LINE_NUMBERS <sass-line-numbers>on : --line-numbers ;
toolset.flags sass INCLUDES : <include> ;
toolset.flags sass FLAGS : <flags> ;
actions convert
{
"$(SASS)" -t$(_)"$(STYLE)" $(LINE_NUMBERS) -I$(_)"$(INCLUDES)" $(FLAGS) "$(>)" $(_)"$(<)"
}
local rule maybe-find-tool ( command )
{
local tool = [ common.find-tool $(command) ] ;
tool ?= $(command) ;
return $(tool) ;
}