drnic-haml 2.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.
- data/.yardopts +5 -0
- data/CONTRIBUTING +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +347 -0
- data/REVISION +1 -0
- data/Rakefile +371 -0
- data/VERSION +1 -0
- data/VERSION_NAME +1 -0
- data/bin/css2sass +7 -0
- data/bin/haml +9 -0
- data/bin/html2haml +7 -0
- data/bin/sass +8 -0
- data/extra/haml-mode.el +663 -0
- data/extra/sass-mode.el +205 -0
- data/extra/update_watch.rb +13 -0
- data/init.rb +8 -0
- data/lib/haml.rb +40 -0
- data/lib/haml/buffer.rb +307 -0
- data/lib/haml/engine.rb +301 -0
- data/lib/haml/error.rb +22 -0
- data/lib/haml/exec.rb +470 -0
- data/lib/haml/filters.rb +341 -0
- data/lib/haml/helpers.rb +560 -0
- data/lib/haml/helpers/action_view_extensions.rb +40 -0
- data/lib/haml/helpers/action_view_mods.rb +176 -0
- data/lib/haml/herb.rb +96 -0
- data/lib/haml/html.rb +308 -0
- data/lib/haml/precompiler.rb +997 -0
- data/lib/haml/shared.rb +78 -0
- data/lib/haml/template.rb +51 -0
- data/lib/haml/template/patch.rb +58 -0
- data/lib/haml/template/plugin.rb +71 -0
- data/lib/haml/util.rb +244 -0
- data/lib/haml/version.rb +64 -0
- data/lib/sass.rb +24 -0
- data/lib/sass/css.rb +423 -0
- data/lib/sass/engine.rb +491 -0
- data/lib/sass/environment.rb +79 -0
- data/lib/sass/error.rb +162 -0
- data/lib/sass/files.rb +133 -0
- data/lib/sass/plugin.rb +170 -0
- data/lib/sass/plugin/merb.rb +57 -0
- data/lib/sass/plugin/rails.rb +23 -0
- data/lib/sass/repl.rb +58 -0
- data/lib/sass/script.rb +55 -0
- data/lib/sass/script/bool.rb +17 -0
- data/lib/sass/script/color.rb +183 -0
- data/lib/sass/script/funcall.rb +50 -0
- data/lib/sass/script/functions.rb +199 -0
- data/lib/sass/script/lexer.rb +191 -0
- data/lib/sass/script/literal.rb +177 -0
- data/lib/sass/script/node.rb +14 -0
- data/lib/sass/script/number.rb +381 -0
- data/lib/sass/script/operation.rb +45 -0
- data/lib/sass/script/parser.rb +222 -0
- data/lib/sass/script/string.rb +12 -0
- data/lib/sass/script/unary_operation.rb +34 -0
- data/lib/sass/script/variable.rb +31 -0
- data/lib/sass/tree/comment_node.rb +84 -0
- data/lib/sass/tree/debug_node.rb +30 -0
- data/lib/sass/tree/directive_node.rb +70 -0
- data/lib/sass/tree/for_node.rb +48 -0
- data/lib/sass/tree/if_node.rb +54 -0
- data/lib/sass/tree/import_node.rb +69 -0
- data/lib/sass/tree/mixin_def_node.rb +29 -0
- data/lib/sass/tree/mixin_node.rb +48 -0
- data/lib/sass/tree/node.rb +252 -0
- data/lib/sass/tree/prop_node.rb +106 -0
- data/lib/sass/tree/root_node.rb +56 -0
- data/lib/sass/tree/rule_node.rb +220 -0
- data/lib/sass/tree/variable_node.rb +34 -0
- data/lib/sass/tree/while_node.rb +31 -0
- data/rails/init.rb +1 -0
- data/test/benchmark.rb +99 -0
- data/test/haml/engine_test.rb +1129 -0
- data/test/haml/helper_test.rb +282 -0
- data/test/haml/html2haml_test.rb +258 -0
- data/test/haml/markaby/standard.mab +52 -0
- data/test/haml/mocks/article.rb +6 -0
- data/test/haml/results/content_for_layout.xhtml +12 -0
- data/test/haml/results/eval_suppressed.xhtml +9 -0
- data/test/haml/results/filters.xhtml +62 -0
- data/test/haml/results/helpers.xhtml +93 -0
- data/test/haml/results/helpful.xhtml +10 -0
- data/test/haml/results/just_stuff.xhtml +68 -0
- data/test/haml/results/list.xhtml +12 -0
- data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
- data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
- data/test/haml/results/original_engine.xhtml +20 -0
- data/test/haml/results/partial_layout.xhtml +5 -0
- data/test/haml/results/partials.xhtml +21 -0
- data/test/haml/results/render_layout.xhtml +3 -0
- data/test/haml/results/silent_script.xhtml +74 -0
- data/test/haml/results/standard.xhtml +162 -0
- data/test/haml/results/tag_parsing.xhtml +23 -0
- data/test/haml/results/very_basic.xhtml +5 -0
- data/test/haml/results/whitespace_handling.xhtml +89 -0
- data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
- data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
- data/test/haml/rhtml/action_view.rhtml +62 -0
- data/test/haml/rhtml/standard.rhtml +54 -0
- data/test/haml/spec_test.rb +44 -0
- data/test/haml/template_test.rb +217 -0
- data/test/haml/templates/_av_partial_1.haml +9 -0
- data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
- data/test/haml/templates/_av_partial_2.haml +5 -0
- data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
- data/test/haml/templates/_layout.erb +3 -0
- data/test/haml/templates/_layout_for_partial.haml +3 -0
- data/test/haml/templates/_partial.haml +8 -0
- data/test/haml/templates/_text_area.haml +3 -0
- data/test/haml/templates/action_view.haml +47 -0
- data/test/haml/templates/action_view_ugly.haml +47 -0
- data/test/haml/templates/breakage.haml +8 -0
- data/test/haml/templates/content_for_layout.haml +8 -0
- data/test/haml/templates/eval_suppressed.haml +11 -0
- data/test/haml/templates/filters.haml +66 -0
- data/test/haml/templates/helpers.haml +95 -0
- data/test/haml/templates/helpful.haml +11 -0
- data/test/haml/templates/just_stuff.haml +83 -0
- data/test/haml/templates/list.haml +12 -0
- data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
- data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
- data/test/haml/templates/original_engine.haml +17 -0
- data/test/haml/templates/partial_layout.haml +3 -0
- data/test/haml/templates/partialize.haml +1 -0
- data/test/haml/templates/partials.haml +12 -0
- data/test/haml/templates/render_layout.haml +2 -0
- data/test/haml/templates/silent_script.haml +40 -0
- data/test/haml/templates/standard.haml +42 -0
- data/test/haml/templates/standard_ugly.haml +42 -0
- data/test/haml/templates/tag_parsing.haml +21 -0
- data/test/haml/templates/very_basic.haml +4 -0
- data/test/haml/templates/whitespace_handling.haml +87 -0
- data/test/haml/util_test.rb +92 -0
- data/test/linked_rails.rb +12 -0
- data/test/sass/css2sass_test.rb +294 -0
- data/test/sass/engine_test.rb +956 -0
- data/test/sass/functions_test.rb +126 -0
- data/test/sass/more_results/more1.css +9 -0
- data/test/sass/more_results/more1_with_line_comments.css +26 -0
- data/test/sass/more_results/more_import.css +29 -0
- data/test/sass/more_templates/_more_partial.sass +2 -0
- data/test/sass/more_templates/more1.sass +23 -0
- data/test/sass/more_templates/more_import.sass +11 -0
- data/test/sass/plugin_test.rb +229 -0
- data/test/sass/results/alt.css +4 -0
- data/test/sass/results/basic.css +9 -0
- data/test/sass/results/compact.css +5 -0
- data/test/sass/results/complex.css +87 -0
- data/test/sass/results/compressed.css +1 -0
- data/test/sass/results/expanded.css +19 -0
- data/test/sass/results/import.css +29 -0
- data/test/sass/results/line_numbers.css +49 -0
- data/test/sass/results/mixins.css +95 -0
- data/test/sass/results/multiline.css +24 -0
- data/test/sass/results/nested.css +22 -0
- data/test/sass/results/parent_ref.css +13 -0
- data/test/sass/results/script.css +16 -0
- data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
- data/test/sass/results/subdir/subdir.css +3 -0
- data/test/sass/results/units.css +11 -0
- data/test/sass/script_test.rb +261 -0
- data/test/sass/templates/_partial.sass +2 -0
- data/test/sass/templates/alt.sass +16 -0
- data/test/sass/templates/basic.sass +23 -0
- data/test/sass/templates/bork1.sass +2 -0
- data/test/sass/templates/bork2.sass +2 -0
- data/test/sass/templates/bork3.sass +2 -0
- data/test/sass/templates/compact.sass +17 -0
- data/test/sass/templates/complex.sass +307 -0
- data/test/sass/templates/compressed.sass +15 -0
- data/test/sass/templates/expanded.sass +17 -0
- data/test/sass/templates/import.sass +11 -0
- data/test/sass/templates/importee.sass +19 -0
- data/test/sass/templates/line_numbers.sass +13 -0
- data/test/sass/templates/mixins.sass +76 -0
- data/test/sass/templates/multiline.sass +20 -0
- data/test/sass/templates/nested.sass +25 -0
- data/test/sass/templates/nested_bork1.sass +2 -0
- data/test/sass/templates/nested_bork2.sass +2 -0
- data/test/sass/templates/nested_bork3.sass +2 -0
- data/test/sass/templates/parent_ref.sass +25 -0
- data/test/sass/templates/script.sass +101 -0
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
- data/test/sass/templates/subdir/subdir.sass +6 -0
- data/test/sass/templates/units.sass +11 -0
- data/test/test_helper.rb +44 -0
- metadata +298 -0
data/lib/haml/version.rb
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'haml/util'
|
|
2
|
+
|
|
3
|
+
module Haml
|
|
4
|
+
# Handles Haml version-reporting.
|
|
5
|
+
# Haml not only reports the standard three version numbers,
|
|
6
|
+
# but its Git revision hash as well,
|
|
7
|
+
# if it was installed from Git.
|
|
8
|
+
module Version
|
|
9
|
+
include Haml::Util
|
|
10
|
+
|
|
11
|
+
# Returns a hash representing the version of Haml.
|
|
12
|
+
# The `:major`, `:minor`, and `:teeny` keys have their respective numbers as Fixnums.
|
|
13
|
+
# The `:name` key has the name of the version.
|
|
14
|
+
# The `:string` key contains a human-readable string representation of the version.
|
|
15
|
+
# The `:number` key is the major, minor, and teeny keys separated by periods.
|
|
16
|
+
# If Haml is checked out from Git, the `:rev` key will have the revision hash.
|
|
17
|
+
# For example:
|
|
18
|
+
#
|
|
19
|
+
# {
|
|
20
|
+
# :string => "2.1.0.9616393",
|
|
21
|
+
# :rev => "9616393b8924ef36639c7e82aa88a51a24d16949",
|
|
22
|
+
# :number => "2.1.0",
|
|
23
|
+
# :major => 2, :minor => 1, :teeny => 0
|
|
24
|
+
# }
|
|
25
|
+
#
|
|
26
|
+
# @return [Hash<Symbol, String/Fixnum>] The version hash
|
|
27
|
+
def version
|
|
28
|
+
return @@version if defined?(@@version)
|
|
29
|
+
|
|
30
|
+
numbers = File.read(scope('VERSION')).strip.split('.').map { |n| n.to_i }
|
|
31
|
+
name = File.read(scope('VERSION_NAME')).strip
|
|
32
|
+
@@version = {
|
|
33
|
+
:major => numbers[0],
|
|
34
|
+
:minor => numbers[1],
|
|
35
|
+
:teeny => numbers[2],
|
|
36
|
+
:name => name
|
|
37
|
+
}
|
|
38
|
+
@@version[:number] = [:major, :minor, :teeny].map { |comp| @@version[comp] }.compact.join('.')
|
|
39
|
+
@@version[:string] = @@version[:number].dup
|
|
40
|
+
|
|
41
|
+
if File.exists?(scope('REVISION'))
|
|
42
|
+
rev = File.read(scope('REVISION')).strip
|
|
43
|
+
rev = nil if rev !~ /^([a-f0-9]+|\(.*\))$/
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if (rev.nil? || rev == '(unknown)') && File.exists?(scope('.git/HEAD'))
|
|
47
|
+
rev = File.read(scope('.git/HEAD')).strip
|
|
48
|
+
if rev =~ /^ref: (.*)$/
|
|
49
|
+
rev = File.read(scope(".git/#{$1}")).strip
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if rev
|
|
54
|
+
@@version[:rev] = rev
|
|
55
|
+
unless rev[0] == ?(
|
|
56
|
+
@@version[:string] << "." << rev[0...7]
|
|
57
|
+
end
|
|
58
|
+
@@version[:string] << " (#{name})"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@@version
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
data/lib/sass.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
dir = File.dirname(__FILE__)
|
|
2
|
+
$LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
|
|
3
|
+
|
|
4
|
+
require 'haml/version'
|
|
5
|
+
|
|
6
|
+
# The module that contains everything Sass-related:
|
|
7
|
+
#
|
|
8
|
+
# * {Sass::Engine} is the class used to render Sass within Ruby code.
|
|
9
|
+
# * {Sass::Plugin} is interfaces with web frameworks (Rails and Merb in particular).
|
|
10
|
+
# * {Sass::SyntaxError} is raised when Sass encounters an error.
|
|
11
|
+
# * {Sass::CSS} handles conversion of CSS to Sass.
|
|
12
|
+
#
|
|
13
|
+
# Also see the {file:SASS_REFERENCE.md full Sass reference}.
|
|
14
|
+
module Sass
|
|
15
|
+
extend Haml::Version
|
|
16
|
+
|
|
17
|
+
# A string representing the version of Sass.
|
|
18
|
+
# A more fine-grained representation is available from {Sass.version}.
|
|
19
|
+
VERSION = version[:string] unless defined?(Sass::VERSION)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
require 'haml/util'
|
|
23
|
+
require 'sass/engine'
|
|
24
|
+
require 'sass/plugin' if defined?(Merb::Plugins)
|
data/lib/sass/css.rb
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../sass'
|
|
2
|
+
require 'sass/tree/node'
|
|
3
|
+
require 'strscan'
|
|
4
|
+
|
|
5
|
+
module Sass
|
|
6
|
+
module Tree
|
|
7
|
+
class Node
|
|
8
|
+
# Converts a node to Sass code that will generate it.
|
|
9
|
+
#
|
|
10
|
+
# @param tabs [Fixnum] The amount of tabulation to use for the Sass code
|
|
11
|
+
# @param opts [Hash<Symbol, Object>] An options hash (see {Sass::CSS#initialize})
|
|
12
|
+
# @return [String] The Sass code corresponding to the node
|
|
13
|
+
def to_sass(tabs = 0, opts = {})
|
|
14
|
+
result = ''
|
|
15
|
+
|
|
16
|
+
children.each do |child|
|
|
17
|
+
result << "#{' ' * tabs}#{child.to_sass(0, opts)}\n"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
result
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class RuleNode
|
|
25
|
+
# @see Node#to_sass
|
|
26
|
+
def to_sass(tabs, opts = {})
|
|
27
|
+
str = "\n#{' ' * tabs}#{rules.first}#{children.any? { |c| c.is_a? PropNode } ? "\n" : ''}"
|
|
28
|
+
|
|
29
|
+
children.each do |child|
|
|
30
|
+
str << "#{child.to_sass(tabs + 1, opts)}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
str
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class PropNode
|
|
38
|
+
# @see Node#to_sass
|
|
39
|
+
def to_sass(tabs, opts = {})
|
|
40
|
+
"#{' ' * tabs}#{opts[:old] ? ':' : ''}#{name}#{opts[:old] ? '' : ':'} #{value}\n"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class DirectiveNode
|
|
45
|
+
# @see Node#to_sass
|
|
46
|
+
def to_sass(tabs, opts = {})
|
|
47
|
+
"#{' ' * tabs}#{value}#{children.map {|c| c.to_sass(tabs + 1, opts)}}\n"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# This class converts CSS documents into Sass templates.
|
|
53
|
+
# It works by parsing the CSS document into a {Sass::Tree} structure,
|
|
54
|
+
# and then applying various transformations to the structure
|
|
55
|
+
# to produce more concise and idiomatic Sass.
|
|
56
|
+
#
|
|
57
|
+
# Example usage:
|
|
58
|
+
#
|
|
59
|
+
# Sass::CSS.new("p { color: blue }").render #=> "p\n color: blue"
|
|
60
|
+
class CSS
|
|
61
|
+
# @param template [String] The CSS code
|
|
62
|
+
# @option options :old [Boolean] (false)
|
|
63
|
+
# Whether or not to output old property syntax
|
|
64
|
+
# (`:color blue` as opposed to `color: blue`).
|
|
65
|
+
# @option options :filename [String]
|
|
66
|
+
# The filename of the CSS file being processed.
|
|
67
|
+
# Used for error reporting
|
|
68
|
+
def initialize(template, options = {})
|
|
69
|
+
if template.is_a? IO
|
|
70
|
+
template = template.read
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
@line = 1
|
|
74
|
+
@options = options.dup
|
|
75
|
+
# Backwards compatibility
|
|
76
|
+
@options[:old] = true if @options[:alternate] == false
|
|
77
|
+
@template = StringScanner.new(template)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Converts the CSS template into Sass code.
|
|
81
|
+
#
|
|
82
|
+
# @return [String] The resulting Sass code
|
|
83
|
+
# @raise [Sass::SyntaxError] if there's an error parsing the CSS template
|
|
84
|
+
def render
|
|
85
|
+
Haml::Util.check_encoding(@template.string) do |msg, line|
|
|
86
|
+
raise Sass::SyntaxError.new(msg, :line => line)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
build_tree.to_sass(0, @options).strip + "\n"
|
|
90
|
+
rescue Sass::SyntaxError => err
|
|
91
|
+
err.modify_backtrace(:filename => @options[:filename] || '(css)', :line => @line)
|
|
92
|
+
raise err
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
# Parses the CSS template and applies various transformations
|
|
98
|
+
#
|
|
99
|
+
# @return [Tree::Node] The root node of the parsed tree
|
|
100
|
+
def build_tree
|
|
101
|
+
root = Tree::Node.new
|
|
102
|
+
whitespace
|
|
103
|
+
rules root
|
|
104
|
+
expand_commas root
|
|
105
|
+
parent_ref_rules root
|
|
106
|
+
remove_parent_refs root
|
|
107
|
+
flatten_rules root
|
|
108
|
+
fold_commas root
|
|
109
|
+
root
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Parses a set of CSS rules.
|
|
113
|
+
#
|
|
114
|
+
# @param root [Tree::Node] The parent node of the rules
|
|
115
|
+
def rules(root)
|
|
116
|
+
while r = rule
|
|
117
|
+
root << r
|
|
118
|
+
whitespace
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Parses a single CSS rule.
|
|
123
|
+
#
|
|
124
|
+
# @return [Tree::Node] The parsed rule
|
|
125
|
+
def rule
|
|
126
|
+
rule = ""
|
|
127
|
+
loop do
|
|
128
|
+
token = scan(/(?:[^\{\};\/\s]|\/[^*])+/)
|
|
129
|
+
if token.nil?
|
|
130
|
+
return if rule.empty?
|
|
131
|
+
break
|
|
132
|
+
end
|
|
133
|
+
rule << token
|
|
134
|
+
break unless @template.match?(/\s|\/\*/)
|
|
135
|
+
whitespace
|
|
136
|
+
rule << " "
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
rule.strip!
|
|
140
|
+
directive = rule[0] == ?@
|
|
141
|
+
|
|
142
|
+
if directive
|
|
143
|
+
node = Tree::DirectiveNode.new(rule)
|
|
144
|
+
return node if scan(/;/)
|
|
145
|
+
|
|
146
|
+
assert_match /\{/
|
|
147
|
+
whitespace
|
|
148
|
+
|
|
149
|
+
rules(node)
|
|
150
|
+
return node
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
assert_match /\{/
|
|
154
|
+
node = Tree::RuleNode.new(rule)
|
|
155
|
+
properties(node)
|
|
156
|
+
return node
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Parses a set of CSS properties within a rule.
|
|
160
|
+
#
|
|
161
|
+
# @param rule [Tree::RuleNode] The parent node of the properties
|
|
162
|
+
def properties(rule)
|
|
163
|
+
while scan(/[^:\}\s]+/)
|
|
164
|
+
name = @template[0]
|
|
165
|
+
whitespace
|
|
166
|
+
|
|
167
|
+
assert_match /:/
|
|
168
|
+
|
|
169
|
+
value = ''
|
|
170
|
+
while scan(/[^;\s\}]+/)
|
|
171
|
+
value << @template[0] << whitespace
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
assert_match /(;|(?=\}))/
|
|
175
|
+
rule << Tree::PropNode.new(name, value, nil)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
assert_match /\}/
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Moves the scanner over a section of whitespace or comments.
|
|
182
|
+
#
|
|
183
|
+
# @return [String] The ignored whitespace
|
|
184
|
+
def whitespace
|
|
185
|
+
space = scan(/\s*/) || ''
|
|
186
|
+
|
|
187
|
+
# If we've hit a comment,
|
|
188
|
+
# go past it and look for more whitespace
|
|
189
|
+
if scan(/\/\*/)
|
|
190
|
+
scan_until(/\*\//)
|
|
191
|
+
return space + whitespace
|
|
192
|
+
end
|
|
193
|
+
return space
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Moves the scanner over a regular expression,
|
|
197
|
+
# raising an exception if it doesn't match.
|
|
198
|
+
#
|
|
199
|
+
# @param re [Regexp] The regular expression to assert
|
|
200
|
+
def assert_match(re)
|
|
201
|
+
if scan(re)
|
|
202
|
+
whitespace
|
|
203
|
+
return
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
pos = @template.pos
|
|
207
|
+
|
|
208
|
+
after = @template.string[[pos - 15, 0].max...pos].gsub(/.*\n/m, '')
|
|
209
|
+
after = "..." + after if pos >= 15
|
|
210
|
+
|
|
211
|
+
# Display basic regexps as plain old strings
|
|
212
|
+
string = re.source.gsub(/\\(.)/, '\1')
|
|
213
|
+
expected = re.source == Regexp.escape(string) ? string.inspect : re.inspect
|
|
214
|
+
|
|
215
|
+
was = @template.rest[0...15].gsub(/\n.*/m, '')
|
|
216
|
+
was += "..." if @template.rest.size >= 15
|
|
217
|
+
raise Sass::SyntaxError.new(
|
|
218
|
+
"Invalid CSS after #{after.inspect}: expected #{expected}, was #{was.inspect}")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Identical to `@template.scan`, except that it increments the line count.
|
|
222
|
+
# `@template.scan` should never be called directly;
|
|
223
|
+
# this should be used instead.
|
|
224
|
+
def scan(re)
|
|
225
|
+
str = @template.scan(re)
|
|
226
|
+
@line += str.count "\n" if str
|
|
227
|
+
str
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Identical to `@template.scan_until`, except that it increments the line count.
|
|
231
|
+
# `@template.scan_until` should never be called directly;
|
|
232
|
+
# this should be used instead.
|
|
233
|
+
def scan_until(re)
|
|
234
|
+
str = @template.scan_until(re)
|
|
235
|
+
@line += str.count "\n" if str
|
|
236
|
+
str
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Transform
|
|
240
|
+
#
|
|
241
|
+
# foo, bar, baz
|
|
242
|
+
# color: blue
|
|
243
|
+
#
|
|
244
|
+
# into
|
|
245
|
+
#
|
|
246
|
+
# foo
|
|
247
|
+
# color: blue
|
|
248
|
+
# bar
|
|
249
|
+
# color: blue
|
|
250
|
+
# baz
|
|
251
|
+
# color: blue
|
|
252
|
+
#
|
|
253
|
+
# @param root [Tree::Node] The parent node
|
|
254
|
+
def expand_commas(root)
|
|
255
|
+
root.children.map! do |child|
|
|
256
|
+
next child unless Tree::RuleNode === child && child.rules.first.include?(',')
|
|
257
|
+
child.rules.first.split(',').map do |rule|
|
|
258
|
+
node = Tree::RuleNode.new(rule.strip)
|
|
259
|
+
node.children = child.children
|
|
260
|
+
node
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
root.children.flatten!
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Make rules use parent refs so that
|
|
267
|
+
#
|
|
268
|
+
# foo
|
|
269
|
+
# color: green
|
|
270
|
+
# foo.bar
|
|
271
|
+
# color: blue
|
|
272
|
+
#
|
|
273
|
+
# becomes
|
|
274
|
+
#
|
|
275
|
+
# foo
|
|
276
|
+
# color: green
|
|
277
|
+
# &.bar
|
|
278
|
+
# color: blue
|
|
279
|
+
#
|
|
280
|
+
# This has the side effect of nesting rules,
|
|
281
|
+
# so that
|
|
282
|
+
#
|
|
283
|
+
# foo
|
|
284
|
+
# color: green
|
|
285
|
+
# foo bar
|
|
286
|
+
# color: red
|
|
287
|
+
# foo baz
|
|
288
|
+
# color: blue
|
|
289
|
+
#
|
|
290
|
+
# becomes
|
|
291
|
+
#
|
|
292
|
+
# foo
|
|
293
|
+
# color: green
|
|
294
|
+
# & bar
|
|
295
|
+
# color: red
|
|
296
|
+
# & baz
|
|
297
|
+
# color: blue
|
|
298
|
+
#
|
|
299
|
+
# @param root [Tree::Node] The parent node
|
|
300
|
+
def parent_ref_rules(root)
|
|
301
|
+
current_rule = nil
|
|
302
|
+
root.children.select { |c| Tree::RuleNode === c }.each do |child|
|
|
303
|
+
root.children.delete child
|
|
304
|
+
first, rest = child.rules.first.scan(/^(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?$/).first
|
|
305
|
+
|
|
306
|
+
if current_rule.nil? || current_rule.rules.first != first
|
|
307
|
+
current_rule = Tree::RuleNode.new(first)
|
|
308
|
+
root << current_rule
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
if rest
|
|
312
|
+
child.rules = ["&" + rest]
|
|
313
|
+
current_rule << child
|
|
314
|
+
else
|
|
315
|
+
current_rule.children += child.children
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
root.children.each { |v| parent_ref_rules(v) }
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Remove useless parent refs so that
|
|
323
|
+
#
|
|
324
|
+
# foo
|
|
325
|
+
# & bar
|
|
326
|
+
# color: blue
|
|
327
|
+
#
|
|
328
|
+
# becomes
|
|
329
|
+
#
|
|
330
|
+
# foo
|
|
331
|
+
# bar
|
|
332
|
+
# color: blue
|
|
333
|
+
#
|
|
334
|
+
# @param root [Tree::Node] The parent node
|
|
335
|
+
def remove_parent_refs(root)
|
|
336
|
+
root.children.each do |child|
|
|
337
|
+
if child.is_a?(Tree::RuleNode)
|
|
338
|
+
child.rules.first.gsub! /^& +/, ''
|
|
339
|
+
remove_parent_refs child
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Flatten rules so that
|
|
345
|
+
#
|
|
346
|
+
# foo
|
|
347
|
+
# bar
|
|
348
|
+
# color: red
|
|
349
|
+
#
|
|
350
|
+
# becomes
|
|
351
|
+
#
|
|
352
|
+
# foo bar
|
|
353
|
+
# color: red
|
|
354
|
+
#
|
|
355
|
+
# and
|
|
356
|
+
#
|
|
357
|
+
# foo
|
|
358
|
+
# &.bar
|
|
359
|
+
# color: blue
|
|
360
|
+
#
|
|
361
|
+
# becomes
|
|
362
|
+
#
|
|
363
|
+
# foo.bar
|
|
364
|
+
# color: blue
|
|
365
|
+
#
|
|
366
|
+
# @param root [Tree::Node] The parent node
|
|
367
|
+
def flatten_rules(root)
|
|
368
|
+
root.children.each { |child| flatten_rule(child) if child.is_a?(Tree::RuleNode) }
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Flattens a single rule
|
|
372
|
+
#
|
|
373
|
+
# @param rule [Tree::RuleNode] The candidate for flattening
|
|
374
|
+
# @see #flatten_rules
|
|
375
|
+
def flatten_rule(rule)
|
|
376
|
+
while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
|
|
377
|
+
child = rule.children.first
|
|
378
|
+
|
|
379
|
+
if child.rules.first[0] == ?&
|
|
380
|
+
rule.rules = [child.rules.first.gsub(/^&/, rule.rules.first)]
|
|
381
|
+
else
|
|
382
|
+
rule.rules = ["#{rule.rules.first} #{child.rules.first}"]
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
rule.children = child.children
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
flatten_rules(rule)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Transform
|
|
392
|
+
#
|
|
393
|
+
# foo
|
|
394
|
+
# bar
|
|
395
|
+
# color: blue
|
|
396
|
+
# baz
|
|
397
|
+
# color: blue
|
|
398
|
+
#
|
|
399
|
+
# into
|
|
400
|
+
#
|
|
401
|
+
# foo
|
|
402
|
+
# bar, baz
|
|
403
|
+
# color: blue
|
|
404
|
+
#
|
|
405
|
+
# @param rule [Tree::RuleNode] The candidate for flattening
|
|
406
|
+
def fold_commas(root)
|
|
407
|
+
prev_rule = nil
|
|
408
|
+
root.children.map! do |child|
|
|
409
|
+
next child unless child.is_a?(Tree::RuleNode)
|
|
410
|
+
|
|
411
|
+
if prev_rule && prev_rule.children == child.children
|
|
412
|
+
prev_rule.rules.first << ", #{child.rules.first}"
|
|
413
|
+
next nil
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
fold_commas(child)
|
|
417
|
+
prev_rule = child
|
|
418
|
+
child
|
|
419
|
+
end
|
|
420
|
+
root.children.compact!
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
end
|