sassc4 2.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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.gitmodules +3 -0
- data/.travis.yml +16 -0
- data/CHANGELOG.md +97 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +80 -0
- data/Rakefile +51 -0
- data/ext/depend +4 -0
- data/ext/extconf.rb +92 -0
- data/ext/libsass/VERSION +1 -0
- data/ext/libsass/contrib/plugin.cpp +60 -0
- data/ext/libsass/include/sass/base.h +97 -0
- data/ext/libsass/include/sass/context.h +174 -0
- data/ext/libsass/include/sass/functions.h +139 -0
- data/ext/libsass/include/sass/values.h +145 -0
- data/ext/libsass/include/sass/version.h +12 -0
- data/ext/libsass/include/sass.h +15 -0
- data/ext/libsass/include/sass2scss.h +120 -0
- data/ext/libsass/src/MurmurHash2.hpp +91 -0
- data/ext/libsass/src/ast.cpp +953 -0
- data/ext/libsass/src/ast.hpp +1064 -0
- data/ext/libsass/src/ast2c.cpp +80 -0
- data/ext/libsass/src/ast2c.hpp +39 -0
- data/ext/libsass/src/ast_def_macros.hpp +140 -0
- data/ext/libsass/src/ast_fwd_decl.cpp +31 -0
- data/ext/libsass/src/ast_fwd_decl.hpp +274 -0
- data/ext/libsass/src/ast_helpers.hpp +316 -0
- data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
- data/ext/libsass/src/ast_sel_super.cpp +539 -0
- data/ext/libsass/src/ast_sel_unify.cpp +275 -0
- data/ext/libsass/src/ast_sel_weave.cpp +616 -0
- data/ext/libsass/src/ast_selectors.cpp +1070 -0
- data/ext/libsass/src/ast_selectors.hpp +523 -0
- data/ext/libsass/src/ast_supports.cpp +114 -0
- data/ext/libsass/src/ast_supports.hpp +121 -0
- data/ext/libsass/src/ast_values.cpp +1154 -0
- data/ext/libsass/src/ast_values.hpp +498 -0
- data/ext/libsass/src/b64/cencode.h +32 -0
- data/ext/libsass/src/b64/encode.h +79 -0
- data/ext/libsass/src/backtrace.cpp +50 -0
- data/ext/libsass/src/backtrace.hpp +29 -0
- data/ext/libsass/src/base64vlq.cpp +47 -0
- data/ext/libsass/src/base64vlq.hpp +30 -0
- data/ext/libsass/src/bind.cpp +312 -0
- data/ext/libsass/src/bind.hpp +15 -0
- data/ext/libsass/src/c2ast.cpp +64 -0
- data/ext/libsass/src/c2ast.hpp +14 -0
- data/ext/libsass/src/c99func.c +54 -0
- data/ext/libsass/src/cencode.c +106 -0
- data/ext/libsass/src/check_nesting.cpp +393 -0
- data/ext/libsass/src/check_nesting.hpp +70 -0
- data/ext/libsass/src/color_maps.cpp +652 -0
- data/ext/libsass/src/color_maps.hpp +323 -0
- data/ext/libsass/src/color_spaces.cpp +241 -0
- data/ext/libsass/src/color_spaces.hpp +227 -0
- data/ext/libsass/src/constants.cpp +199 -0
- data/ext/libsass/src/constants.hpp +200 -0
- data/ext/libsass/src/context.cpp +870 -0
- data/ext/libsass/src/context.hpp +140 -0
- data/ext/libsass/src/cssize.cpp +521 -0
- data/ext/libsass/src/cssize.hpp +71 -0
- data/ext/libsass/src/dart_helpers.hpp +199 -0
- data/ext/libsass/src/debug.hpp +43 -0
- data/ext/libsass/src/debugger.hpp +964 -0
- data/ext/libsass/src/emitter.cpp +297 -0
- data/ext/libsass/src/emitter.hpp +101 -0
- data/ext/libsass/src/environment.cpp +260 -0
- data/ext/libsass/src/environment.hpp +124 -0
- data/ext/libsass/src/error_handling.cpp +239 -0
- data/ext/libsass/src/error_handling.hpp +248 -0
- data/ext/libsass/src/eval.cpp +1543 -0
- data/ext/libsass/src/eval.hpp +110 -0
- data/ext/libsass/src/eval_selectors.cpp +75 -0
- data/ext/libsass/src/expand.cpp +875 -0
- data/ext/libsass/src/expand.hpp +98 -0
- data/ext/libsass/src/extender.cpp +1226 -0
- data/ext/libsass/src/extender.hpp +399 -0
- data/ext/libsass/src/extension.cpp +43 -0
- data/ext/libsass/src/extension.hpp +89 -0
- data/ext/libsass/src/file.cpp +531 -0
- data/ext/libsass/src/file.hpp +124 -0
- data/ext/libsass/src/fn_colors.cpp +836 -0
- data/ext/libsass/src/fn_colors.hpp +99 -0
- data/ext/libsass/src/fn_lists.cpp +285 -0
- data/ext/libsass/src/fn_lists.hpp +34 -0
- data/ext/libsass/src/fn_maps.cpp +94 -0
- data/ext/libsass/src/fn_maps.hpp +30 -0
- data/ext/libsass/src/fn_miscs.cpp +248 -0
- data/ext/libsass/src/fn_miscs.hpp +40 -0
- data/ext/libsass/src/fn_numbers.cpp +246 -0
- data/ext/libsass/src/fn_numbers.hpp +45 -0
- data/ext/libsass/src/fn_selectors.cpp +205 -0
- data/ext/libsass/src/fn_selectors.hpp +35 -0
- data/ext/libsass/src/fn_strings.cpp +268 -0
- data/ext/libsass/src/fn_strings.hpp +34 -0
- data/ext/libsass/src/fn_utils.cpp +159 -0
- data/ext/libsass/src/fn_utils.hpp +62 -0
- data/ext/libsass/src/inspect.cpp +1126 -0
- data/ext/libsass/src/inspect.hpp +101 -0
- data/ext/libsass/src/json.cpp +1436 -0
- data/ext/libsass/src/json.hpp +117 -0
- data/ext/libsass/src/kwd_arg_macros.hpp +28 -0
- data/ext/libsass/src/lexer.cpp +122 -0
- data/ext/libsass/src/lexer.hpp +304 -0
- data/ext/libsass/src/listize.cpp +70 -0
- data/ext/libsass/src/listize.hpp +37 -0
- data/ext/libsass/src/mapping.hpp +19 -0
- data/ext/libsass/src/memory/allocator.cpp +48 -0
- data/ext/libsass/src/memory/allocator.hpp +138 -0
- data/ext/libsass/src/memory/config.hpp +20 -0
- data/ext/libsass/src/memory/memory_pool.hpp +186 -0
- data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
- data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
- data/ext/libsass/src/memory.hpp +12 -0
- data/ext/libsass/src/operation.hpp +223 -0
- data/ext/libsass/src/operators.cpp +267 -0
- data/ext/libsass/src/operators.hpp +30 -0
- data/ext/libsass/src/ordered_map.hpp +112 -0
- data/ext/libsass/src/output.cpp +320 -0
- data/ext/libsass/src/output.hpp +47 -0
- data/ext/libsass/src/parser.cpp +3059 -0
- data/ext/libsass/src/parser.hpp +395 -0
- data/ext/libsass/src/parser_selectors.cpp +189 -0
- data/ext/libsass/src/permutate.hpp +164 -0
- data/ext/libsass/src/plugins.cpp +188 -0
- data/ext/libsass/src/plugins.hpp +57 -0
- data/ext/libsass/src/position.cpp +163 -0
- data/ext/libsass/src/position.hpp +147 -0
- data/ext/libsass/src/prelexer.cpp +1780 -0
- data/ext/libsass/src/prelexer.hpp +484 -0
- data/ext/libsass/src/remove_placeholders.cpp +86 -0
- data/ext/libsass/src/remove_placeholders.hpp +37 -0
- data/ext/libsass/src/sass.cpp +156 -0
- data/ext/libsass/src/sass.hpp +147 -0
- data/ext/libsass/src/sass2scss.cpp +895 -0
- data/ext/libsass/src/sass_context.cpp +742 -0
- data/ext/libsass/src/sass_context.hpp +129 -0
- data/ext/libsass/src/sass_functions.cpp +210 -0
- data/ext/libsass/src/sass_functions.hpp +50 -0
- data/ext/libsass/src/sass_values.cpp +362 -0
- data/ext/libsass/src/sass_values.hpp +82 -0
- data/ext/libsass/src/settings.hpp +19 -0
- data/ext/libsass/src/source.cpp +69 -0
- data/ext/libsass/src/source.hpp +95 -0
- data/ext/libsass/src/source_data.hpp +32 -0
- data/ext/libsass/src/source_map.cpp +202 -0
- data/ext/libsass/src/source_map.hpp +65 -0
- data/ext/libsass/src/stylesheet.cpp +22 -0
- data/ext/libsass/src/stylesheet.hpp +57 -0
- data/ext/libsass/src/to_value.cpp +114 -0
- data/ext/libsass/src/to_value.hpp +46 -0
- data/ext/libsass/src/units.cpp +507 -0
- data/ext/libsass/src/units.hpp +110 -0
- data/ext/libsass/src/utf8/checked.h +336 -0
- data/ext/libsass/src/utf8/core.h +332 -0
- data/ext/libsass/src/utf8/unchecked.h +235 -0
- data/ext/libsass/src/utf8.h +34 -0
- data/ext/libsass/src/utf8_string.cpp +104 -0
- data/ext/libsass/src/utf8_string.hpp +38 -0
- data/ext/libsass/src/util.cpp +723 -0
- data/ext/libsass/src/util.hpp +105 -0
- data/ext/libsass/src/util_string.cpp +125 -0
- data/ext/libsass/src/util_string.hpp +73 -0
- data/ext/libsass/src/values.cpp +140 -0
- data/ext/libsass/src/values.hpp +12 -0
- data/lib/sassc/dependency.rb +17 -0
- data/lib/sassc/engine.rb +141 -0
- data/lib/sassc/error.rb +37 -0
- data/lib/sassc/functions_handler.rb +73 -0
- data/lib/sassc/import_handler.rb +50 -0
- data/lib/sassc/importer.rb +31 -0
- data/lib/sassc/native/native_context_api.rb +147 -0
- data/lib/sassc/native/native_functions_api.rb +159 -0
- data/lib/sassc/native/sass2scss_api.rb +10 -0
- data/lib/sassc/native/sass_input_style.rb +13 -0
- data/lib/sassc/native/sass_output_style.rb +12 -0
- data/lib/sassc/native/sass_value.rb +97 -0
- data/lib/sassc/native/string_list.rb +10 -0
- data/lib/sassc/native.rb +64 -0
- data/lib/sassc/sass_2_scss.rb +9 -0
- data/lib/sassc/script/functions.rb +8 -0
- data/lib/sassc/script/value/bool.rb +32 -0
- data/lib/sassc/script/value/color.rb +95 -0
- data/lib/sassc/script/value/list.rb +136 -0
- data/lib/sassc/script/value/map.rb +69 -0
- data/lib/sassc/script/value/number.rb +389 -0
- data/lib/sassc/script/value/string.rb +96 -0
- data/lib/sassc/script/value.rb +137 -0
- data/lib/sassc/script/value_conversion/base.rb +13 -0
- data/lib/sassc/script/value_conversion/bool.rb +13 -0
- data/lib/sassc/script/value_conversion/color.rb +18 -0
- data/lib/sassc/script/value_conversion/list.rb +25 -0
- data/lib/sassc/script/value_conversion/map.rb +21 -0
- data/lib/sassc/script/value_conversion/number.rb +13 -0
- data/lib/sassc/script/value_conversion/string.rb +17 -0
- data/lib/sassc/script/value_conversion.rb +69 -0
- data/lib/sassc/script.rb +17 -0
- data/lib/sassc/util/normalized_map.rb +117 -0
- data/lib/sassc/util.rb +231 -0
- data/lib/sassc/version.rb +5 -0
- data/lib/sassc.rb +57 -0
- data/sassc.gemspec +69 -0
- data/test/css_color_level4_test.rb +168 -0
- data/test/custom_importer_test.rb +127 -0
- data/test/engine_test.rb +314 -0
- data/test/error_test.rb +29 -0
- data/test/fixtures/paths.scss +10 -0
- data/test/functions_test.rb +340 -0
- data/test/native_test.rb +213 -0
- data/test/output_style_test.rb +107 -0
- data/test/sass_2_scss_test.rb +14 -0
- data/test/test_helper.rb +45 -0
- metadata +396 -0
|
@@ -0,0 +1,895 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sass2scss
|
|
3
|
+
* Licensed under the MIT License
|
|
4
|
+
* Copyright (c) Marcel Greter
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#ifdef _MSC_VER
|
|
8
|
+
#define _CRT_SECURE_NO_WARNINGS
|
|
9
|
+
#define _CRT_NONSTDC_NO_DEPRECATE
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
// include library
|
|
13
|
+
#include <stack>
|
|
14
|
+
#include <string>
|
|
15
|
+
#include <cstring>
|
|
16
|
+
#include <cstdlib>
|
|
17
|
+
#include <sstream>
|
|
18
|
+
#include <iostream>
|
|
19
|
+
#include <stdio.h>
|
|
20
|
+
|
|
21
|
+
///*
|
|
22
|
+
//
|
|
23
|
+
// src comments: comments in sass syntax (staring with //)
|
|
24
|
+
// css comments: multiline comments in css syntax (starting with /*)
|
|
25
|
+
//
|
|
26
|
+
// KEEP_COMMENT: keep src comments in the resulting css code
|
|
27
|
+
// STRIP_COMMENT: strip out all comments (either src or css)
|
|
28
|
+
// CONVERT_COMMENT: convert all src comments to css comments
|
|
29
|
+
//
|
|
30
|
+
//*/
|
|
31
|
+
|
|
32
|
+
// our own header
|
|
33
|
+
#include "sass2scss.h"
|
|
34
|
+
|
|
35
|
+
// add namespace for c++
|
|
36
|
+
namespace Sass
|
|
37
|
+
{
|
|
38
|
+
|
|
39
|
+
// return the actual prettify value from options
|
|
40
|
+
#define PRETTIFY(converter) (converter.options - (converter.options & 248))
|
|
41
|
+
// query the options integer to check if the option is enables
|
|
42
|
+
#define KEEP_COMMENT(converter) ((converter.options & SASS2SCSS_KEEP_COMMENT) == SASS2SCSS_KEEP_COMMENT)
|
|
43
|
+
#define STRIP_COMMENT(converter) ((converter.options & SASS2SCSS_STRIP_COMMENT) == SASS2SCSS_STRIP_COMMENT)
|
|
44
|
+
#define CONVERT_COMMENT(converter) ((converter.options & SASS2SCSS_CONVERT_COMMENT) == SASS2SCSS_CONVERT_COMMENT)
|
|
45
|
+
|
|
46
|
+
// some makros to access the indentation stack
|
|
47
|
+
#define INDENT(converter) (converter.indents.top())
|
|
48
|
+
|
|
49
|
+
// some makros to query comment parser status
|
|
50
|
+
#define IS_PARSING(converter) (converter.comment == "")
|
|
51
|
+
#define IS_COMMENT(converter) (converter.comment != "")
|
|
52
|
+
#define IS_SRC_COMMENT(converter) (converter.comment == "//" && ! CONVERT_COMMENT(converter))
|
|
53
|
+
#define IS_CSS_COMMENT(converter) (converter.comment == "/*" || (converter.comment == "//" && CONVERT_COMMENT(converter)))
|
|
54
|
+
|
|
55
|
+
// pretty printer helper function
|
|
56
|
+
static std::string closer (const converter& converter)
|
|
57
|
+
{
|
|
58
|
+
return PRETTIFY(converter) == 0 ? " }" :
|
|
59
|
+
PRETTIFY(converter) <= 1 ? " }" :
|
|
60
|
+
"\n" + INDENT(converter) + "}";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// pretty printer helper function
|
|
64
|
+
static std::string opener (const converter& converter)
|
|
65
|
+
{
|
|
66
|
+
return PRETTIFY(converter) == 0 ? " { " :
|
|
67
|
+
PRETTIFY(converter) <= 2 ? " {" :
|
|
68
|
+
"\n" + INDENT(converter) + "{";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// check if the given string is a pseudo selector
|
|
72
|
+
// needed to differentiate from sass property syntax
|
|
73
|
+
static bool isPseudoSelector (std::string& sel)
|
|
74
|
+
{
|
|
75
|
+
|
|
76
|
+
size_t len = sel.length();
|
|
77
|
+
if (len < 1) return false;
|
|
78
|
+
size_t pos = sel.find_first_not_of("abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1);
|
|
79
|
+
if (pos != std::string::npos) sel.erase(pos, std::string::npos);
|
|
80
|
+
size_t i = sel.length();
|
|
81
|
+
while (i -- > 0) { sel.at(i) = tolower(sel.at(i)); }
|
|
82
|
+
|
|
83
|
+
// CSS Level 1 - Recommendation
|
|
84
|
+
if (sel == ":link") return true;
|
|
85
|
+
if (sel == ":visited") return true;
|
|
86
|
+
if (sel == ":active") return true;
|
|
87
|
+
|
|
88
|
+
// CSS Level 2 (Revision 1) - Recommendation
|
|
89
|
+
if (sel == ":lang") return true;
|
|
90
|
+
if (sel == ":first-child") return true;
|
|
91
|
+
if (sel == ":hover") return true;
|
|
92
|
+
if (sel == ":focus") return true;
|
|
93
|
+
// disabled - also valid properties
|
|
94
|
+
// if (sel == ":left") return true;
|
|
95
|
+
// if (sel == ":right") return true;
|
|
96
|
+
if (sel == ":first") return true;
|
|
97
|
+
|
|
98
|
+
// Selectors Level 3 - Recommendation
|
|
99
|
+
if (sel == ":target") return true;
|
|
100
|
+
if (sel == ":root") return true;
|
|
101
|
+
if (sel == ":nth-child") return true;
|
|
102
|
+
if (sel == ":nth-last-of-child") return true;
|
|
103
|
+
if (sel == ":nth-of-type") return true;
|
|
104
|
+
if (sel == ":nth-last-of-type") return true;
|
|
105
|
+
if (sel == ":last-child") return true;
|
|
106
|
+
if (sel == ":first-of-type") return true;
|
|
107
|
+
if (sel == ":last-of-type") return true;
|
|
108
|
+
if (sel == ":only-child") return true;
|
|
109
|
+
if (sel == ":only-of-type") return true;
|
|
110
|
+
if (sel == ":empty") return true;
|
|
111
|
+
if (sel == ":not") return true;
|
|
112
|
+
|
|
113
|
+
// CSS Basic User Interface Module Level 3 - Working Draft
|
|
114
|
+
if (sel == ":default") return true;
|
|
115
|
+
if (sel == ":valid") return true;
|
|
116
|
+
if (sel == ":invalid") return true;
|
|
117
|
+
if (sel == ":in-range") return true;
|
|
118
|
+
if (sel == ":out-of-range") return true;
|
|
119
|
+
if (sel == ":required") return true;
|
|
120
|
+
if (sel == ":optional") return true;
|
|
121
|
+
if (sel == ":read-only") return true;
|
|
122
|
+
if (sel == ":read-write") return true;
|
|
123
|
+
if (sel == ":dir") return true;
|
|
124
|
+
if (sel == ":enabled") return true;
|
|
125
|
+
if (sel == ":disabled") return true;
|
|
126
|
+
if (sel == ":checked") return true;
|
|
127
|
+
if (sel == ":indeterminate") return true;
|
|
128
|
+
if (sel == ":nth-last-child") return true;
|
|
129
|
+
|
|
130
|
+
// Selectors Level 4 - Working Draft
|
|
131
|
+
if (sel == ":any-link") return true;
|
|
132
|
+
if (sel == ":local-link") return true;
|
|
133
|
+
if (sel == ":scope") return true;
|
|
134
|
+
if (sel == ":active-drop-target") return true;
|
|
135
|
+
if (sel == ":valid-drop-target") return true;
|
|
136
|
+
if (sel == ":invalid-drop-target") return true;
|
|
137
|
+
if (sel == ":current") return true;
|
|
138
|
+
if (sel == ":past") return true;
|
|
139
|
+
if (sel == ":future") return true;
|
|
140
|
+
if (sel == ":placeholder-shown") return true;
|
|
141
|
+
if (sel == ":user-error") return true;
|
|
142
|
+
if (sel == ":blank") return true;
|
|
143
|
+
if (sel == ":nth-match") return true;
|
|
144
|
+
if (sel == ":nth-last-match") return true;
|
|
145
|
+
if (sel == ":nth-column") return true;
|
|
146
|
+
if (sel == ":nth-last-column") return true;
|
|
147
|
+
if (sel == ":matches") return true;
|
|
148
|
+
|
|
149
|
+
// Fullscreen API - Living Standard
|
|
150
|
+
if (sel == ":fullscreen") return true;
|
|
151
|
+
|
|
152
|
+
// not a pseudo selector
|
|
153
|
+
return false;
|
|
154
|
+
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static size_t findFirstCharacter (std::string& sass, size_t pos)
|
|
158
|
+
{
|
|
159
|
+
return sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static size_t findLastCharacter (std::string& sass, size_t pos)
|
|
163
|
+
{
|
|
164
|
+
return sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE, pos);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static bool isUrl (std::string& sass, size_t pos)
|
|
168
|
+
{
|
|
169
|
+
return sass[pos] == 'u' && sass[pos+1] == 'r' && sass[pos+2] == 'l' && sass[pos+3] == '(';
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// check if there is some char data
|
|
173
|
+
// will ignore everything in comments
|
|
174
|
+
static bool hasCharData (std::string& sass)
|
|
175
|
+
{
|
|
176
|
+
|
|
177
|
+
size_t col_pos = 0;
|
|
178
|
+
|
|
179
|
+
while (true)
|
|
180
|
+
{
|
|
181
|
+
|
|
182
|
+
// try to find some meaningful char
|
|
183
|
+
col_pos = sass.find_first_not_of(" \t\n\v\f\r", col_pos);
|
|
184
|
+
|
|
185
|
+
// there was no meaningful char found
|
|
186
|
+
if (col_pos == std::string::npos) return false;
|
|
187
|
+
|
|
188
|
+
// found a multiline comment opener
|
|
189
|
+
if (sass.substr(col_pos, 2) == "/*")
|
|
190
|
+
{
|
|
191
|
+
// find the multiline comment closer
|
|
192
|
+
col_pos = sass.find("*/", col_pos);
|
|
193
|
+
// maybe we did not find the closer here
|
|
194
|
+
if (col_pos == std::string::npos) return false;
|
|
195
|
+
// skip closer
|
|
196
|
+
col_pos += 2;
|
|
197
|
+
}
|
|
198
|
+
else
|
|
199
|
+
{
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
// EO hasCharData
|
|
207
|
+
|
|
208
|
+
// find src comment opener
|
|
209
|
+
// correctly skips quoted strings
|
|
210
|
+
static size_t findCommentOpener (std::string& sass)
|
|
211
|
+
{
|
|
212
|
+
|
|
213
|
+
size_t col_pos = 0;
|
|
214
|
+
bool apoed = false;
|
|
215
|
+
bool quoted = false;
|
|
216
|
+
bool comment = false;
|
|
217
|
+
size_t brackets = 0;
|
|
218
|
+
|
|
219
|
+
while (col_pos != std::string::npos)
|
|
220
|
+
{
|
|
221
|
+
|
|
222
|
+
// process all interesting chars
|
|
223
|
+
col_pos = sass.find_first_of("\"\'/\\*()", col_pos);
|
|
224
|
+
|
|
225
|
+
// assertion for valid result
|
|
226
|
+
if (col_pos != std::string::npos)
|
|
227
|
+
{
|
|
228
|
+
char character = sass.at(col_pos);
|
|
229
|
+
|
|
230
|
+
if (character == '(')
|
|
231
|
+
{
|
|
232
|
+
if (!quoted && !apoed) brackets ++;
|
|
233
|
+
}
|
|
234
|
+
else if (character == ')')
|
|
235
|
+
{
|
|
236
|
+
if (!quoted && !apoed) brackets --;
|
|
237
|
+
}
|
|
238
|
+
else if (character == '\"')
|
|
239
|
+
{
|
|
240
|
+
// invert quote bool
|
|
241
|
+
if (!apoed && !comment) quoted = !quoted;
|
|
242
|
+
}
|
|
243
|
+
else if (character == '\'')
|
|
244
|
+
{
|
|
245
|
+
// invert quote bool
|
|
246
|
+
if (!quoted && !comment) apoed = !apoed;
|
|
247
|
+
}
|
|
248
|
+
else if (col_pos > 0 && character == '/')
|
|
249
|
+
{
|
|
250
|
+
if (sass.at(col_pos - 1) == '*')
|
|
251
|
+
{
|
|
252
|
+
comment = false;
|
|
253
|
+
}
|
|
254
|
+
// next needs to be a slash too
|
|
255
|
+
else if (sass.at(col_pos - 1) == '/')
|
|
256
|
+
{
|
|
257
|
+
// only found if not in single or double quote, bracket or comment
|
|
258
|
+
if (!quoted && !apoed && !comment && brackets == 0) return col_pos - 1;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else if (character == '\\')
|
|
262
|
+
{
|
|
263
|
+
// skip next char if in quote
|
|
264
|
+
if (quoted || apoed) col_pos ++;
|
|
265
|
+
}
|
|
266
|
+
// this might be a comment opener
|
|
267
|
+
else if (col_pos > 0 && character == '*')
|
|
268
|
+
{
|
|
269
|
+
// opening a multiline comment
|
|
270
|
+
if (sass.at(col_pos - 1) == '/')
|
|
271
|
+
{
|
|
272
|
+
// we are now in a comment
|
|
273
|
+
if (!quoted && !apoed) comment = true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// skip char
|
|
278
|
+
col_pos ++;
|
|
279
|
+
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
}
|
|
283
|
+
// EO while
|
|
284
|
+
|
|
285
|
+
return col_pos;
|
|
286
|
+
|
|
287
|
+
}
|
|
288
|
+
// EO findCommentOpener
|
|
289
|
+
|
|
290
|
+
// remove multiline comments from sass string
|
|
291
|
+
// correctly skips quoted strings
|
|
292
|
+
static std::string removeMultilineComment (std::string &sass)
|
|
293
|
+
{
|
|
294
|
+
|
|
295
|
+
std::string clean = "";
|
|
296
|
+
size_t col_pos = 0;
|
|
297
|
+
size_t open_pos = 0;
|
|
298
|
+
size_t close_pos = 0;
|
|
299
|
+
bool apoed = false;
|
|
300
|
+
bool quoted = false;
|
|
301
|
+
bool comment = false;
|
|
302
|
+
|
|
303
|
+
// process sass til string end
|
|
304
|
+
while (col_pos != std::string::npos)
|
|
305
|
+
{
|
|
306
|
+
|
|
307
|
+
// process all interesting chars
|
|
308
|
+
col_pos = sass.find_first_of("\"\'/\\*", col_pos);
|
|
309
|
+
|
|
310
|
+
// assertion for valid result
|
|
311
|
+
if (col_pos != std::string::npos)
|
|
312
|
+
{
|
|
313
|
+
char character = sass.at(col_pos);
|
|
314
|
+
|
|
315
|
+
// found quoted string delimiter
|
|
316
|
+
if (character == '\"')
|
|
317
|
+
{
|
|
318
|
+
if (!apoed && !comment) quoted = !quoted;
|
|
319
|
+
}
|
|
320
|
+
else if (character == '\'')
|
|
321
|
+
{
|
|
322
|
+
if (!quoted && !comment) apoed = !apoed;
|
|
323
|
+
}
|
|
324
|
+
// found possible comment closer
|
|
325
|
+
else if (character == '/')
|
|
326
|
+
{
|
|
327
|
+
// look back to see if it is actually a closer
|
|
328
|
+
if (comment && col_pos > 0 && sass.at(col_pos - 1) == '*')
|
|
329
|
+
{
|
|
330
|
+
close_pos = col_pos + 1; comment = false;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else if (character == '\\')
|
|
334
|
+
{
|
|
335
|
+
// skip escaped char
|
|
336
|
+
if (quoted || apoed) col_pos ++;
|
|
337
|
+
}
|
|
338
|
+
// this might be a comment opener
|
|
339
|
+
else if (character == '*')
|
|
340
|
+
{
|
|
341
|
+
// look back to see if it is actually an opener
|
|
342
|
+
if (!quoted && !apoed && col_pos > 0 && sass.at(col_pos - 1) == '/')
|
|
343
|
+
{
|
|
344
|
+
comment = true; open_pos = col_pos - 1;
|
|
345
|
+
clean += sass.substr(close_pos, open_pos - close_pos);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// skip char
|
|
350
|
+
col_pos ++;
|
|
351
|
+
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
}
|
|
355
|
+
// EO while
|
|
356
|
+
|
|
357
|
+
// add final parts (add half open comment text)
|
|
358
|
+
if (comment) clean += sass.substr(open_pos);
|
|
359
|
+
else clean += sass.substr(close_pos);
|
|
360
|
+
|
|
361
|
+
// return string
|
|
362
|
+
return clean;
|
|
363
|
+
|
|
364
|
+
}
|
|
365
|
+
// EO removeMultilineComment
|
|
366
|
+
|
|
367
|
+
// right trim a given string
|
|
368
|
+
std::string rtrim(const std::string &sass)
|
|
369
|
+
{
|
|
370
|
+
std::string trimmed = sass;
|
|
371
|
+
size_t pos_ws = trimmed.find_last_not_of(" \t\n\v\f\r");
|
|
372
|
+
if (pos_ws != std::string::npos)
|
|
373
|
+
{ trimmed.erase(pos_ws + 1); }
|
|
374
|
+
else { trimmed.clear(); }
|
|
375
|
+
return trimmed;
|
|
376
|
+
}
|
|
377
|
+
// EO rtrim
|
|
378
|
+
|
|
379
|
+
// flush whitespace and print additional text, but
|
|
380
|
+
// only print additional chars and buffer whitespace
|
|
381
|
+
std::string flush (std::string& sass, converter& converter)
|
|
382
|
+
{
|
|
383
|
+
|
|
384
|
+
// return flushed
|
|
385
|
+
std::string scss = "";
|
|
386
|
+
|
|
387
|
+
// print whitespace buffer
|
|
388
|
+
scss += PRETTIFY(converter) > 0 ?
|
|
389
|
+
converter.whitespace : "";
|
|
390
|
+
// reset whitespace buffer
|
|
391
|
+
converter.whitespace = "";
|
|
392
|
+
|
|
393
|
+
// remove possible newlines from string
|
|
394
|
+
size_t pos_right = sass.find_last_not_of("\n\r");
|
|
395
|
+
if (pos_right == std::string::npos) return scss;
|
|
396
|
+
|
|
397
|
+
// get the linefeeds from the string
|
|
398
|
+
std::string lfs = sass.substr(pos_right + 1);
|
|
399
|
+
sass = sass.substr(0, pos_right + 1);
|
|
400
|
+
|
|
401
|
+
// find some source comment opener
|
|
402
|
+
size_t comment_pos = findCommentOpener(sass);
|
|
403
|
+
// check if there was a source comment
|
|
404
|
+
if (comment_pos != std::string::npos)
|
|
405
|
+
{
|
|
406
|
+
// convert comment (but only outside other coments)
|
|
407
|
+
if (CONVERT_COMMENT(converter) && !IS_COMMENT(converter))
|
|
408
|
+
{
|
|
409
|
+
// convert to multiline comment
|
|
410
|
+
sass.at(comment_pos + 1) = '*';
|
|
411
|
+
// add comment node to the whitespace
|
|
412
|
+
sass += " */";
|
|
413
|
+
}
|
|
414
|
+
// not at line start
|
|
415
|
+
if (comment_pos > 0)
|
|
416
|
+
{
|
|
417
|
+
// also include whitespace before the actual comment opener
|
|
418
|
+
size_t ws_pos = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE, comment_pos - 1);
|
|
419
|
+
comment_pos = ws_pos == std::string::npos ? 0 : ws_pos + 1;
|
|
420
|
+
}
|
|
421
|
+
if (!STRIP_COMMENT(converter))
|
|
422
|
+
{
|
|
423
|
+
// add comment node to the whitespace
|
|
424
|
+
converter.whitespace += sass.substr(comment_pos);
|
|
425
|
+
}
|
|
426
|
+
else
|
|
427
|
+
{
|
|
428
|
+
// sass = removeMultilineComments(sass);
|
|
429
|
+
}
|
|
430
|
+
// update the actual sass code
|
|
431
|
+
sass = sass.substr(0, comment_pos);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// add newline as getline discharged it
|
|
435
|
+
converter.whitespace += lfs + "\n";
|
|
436
|
+
|
|
437
|
+
// maybe remove any leading whitespace
|
|
438
|
+
if (PRETTIFY(converter) == 0)
|
|
439
|
+
{
|
|
440
|
+
// remove leading whitespace and update string
|
|
441
|
+
size_t pos_left = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE);
|
|
442
|
+
if (pos_left != std::string::npos) sass = sass.substr(pos_left);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// add flushed data
|
|
446
|
+
scss += sass;
|
|
447
|
+
|
|
448
|
+
// return string
|
|
449
|
+
return scss;
|
|
450
|
+
|
|
451
|
+
}
|
|
452
|
+
// EO flush
|
|
453
|
+
|
|
454
|
+
// process a line of the sass text
|
|
455
|
+
std::string process (std::string& sass, converter& converter)
|
|
456
|
+
{
|
|
457
|
+
|
|
458
|
+
// resulting string
|
|
459
|
+
std::string scss = "";
|
|
460
|
+
|
|
461
|
+
// strip multi line comments
|
|
462
|
+
if (STRIP_COMMENT(converter))
|
|
463
|
+
{
|
|
464
|
+
sass = removeMultilineComment(sass);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// right trim input
|
|
468
|
+
sass = rtrim(sass);
|
|
469
|
+
|
|
470
|
+
// get position of first meaningful character in string
|
|
471
|
+
size_t pos_left = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE);
|
|
472
|
+
|
|
473
|
+
// special case for final run
|
|
474
|
+
if (converter.end_of_file) pos_left = 0;
|
|
475
|
+
|
|
476
|
+
// maybe has only whitespace
|
|
477
|
+
if (pos_left == std::string::npos)
|
|
478
|
+
{
|
|
479
|
+
// just add complete whitespace
|
|
480
|
+
converter.whitespace += sass + "\n";
|
|
481
|
+
}
|
|
482
|
+
// have meaningful first char
|
|
483
|
+
else
|
|
484
|
+
{
|
|
485
|
+
|
|
486
|
+
// extract and store indentation string
|
|
487
|
+
std::string indent = sass.substr(0, pos_left);
|
|
488
|
+
|
|
489
|
+
// check if current line starts a comment
|
|
490
|
+
std::string open = sass.substr(pos_left, 2);
|
|
491
|
+
|
|
492
|
+
// line has less or same indentation
|
|
493
|
+
// finalize previous open parser context
|
|
494
|
+
if (indent.length() <= INDENT(converter).length())
|
|
495
|
+
{
|
|
496
|
+
|
|
497
|
+
// close multilinie comment
|
|
498
|
+
if (IS_CSS_COMMENT(converter))
|
|
499
|
+
{
|
|
500
|
+
// check if comments will be stripped anyway
|
|
501
|
+
if (!STRIP_COMMENT(converter)) scss += " */";
|
|
502
|
+
}
|
|
503
|
+
// close src comment comment
|
|
504
|
+
else if (IS_SRC_COMMENT(converter))
|
|
505
|
+
{
|
|
506
|
+
// add a newline to avoid closer on same line
|
|
507
|
+
// this would put the bracket in the comment node
|
|
508
|
+
// no longer needed since we parse them correctly
|
|
509
|
+
// if (KEEP_COMMENT(converter)) scss += "\n";
|
|
510
|
+
}
|
|
511
|
+
// close css properties
|
|
512
|
+
else if (converter.property)
|
|
513
|
+
{
|
|
514
|
+
// add closer unless in concat mode
|
|
515
|
+
if (!converter.comma)
|
|
516
|
+
{
|
|
517
|
+
// if there was no colon we have a selector
|
|
518
|
+
// looks like there were no inner properties
|
|
519
|
+
if (converter.selector) scss += " {}";
|
|
520
|
+
// add final semicolon
|
|
521
|
+
else if (!converter.semicolon) scss += ";";
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// reset comment state
|
|
526
|
+
converter.comment = "";
|
|
527
|
+
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// make sure we close every "higher" block
|
|
531
|
+
while (indent.length() < INDENT(converter).length())
|
|
532
|
+
{
|
|
533
|
+
// pop stacked context
|
|
534
|
+
converter.indents.pop();
|
|
535
|
+
// print close bracket
|
|
536
|
+
if (IS_PARSING(converter))
|
|
537
|
+
{ scss += closer(converter); }
|
|
538
|
+
else { scss += " */"; }
|
|
539
|
+
// reset comment state
|
|
540
|
+
converter.comment = "";
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// reset converter state
|
|
544
|
+
converter.selector = false;
|
|
545
|
+
|
|
546
|
+
// looks like some undocumented behavior ...
|
|
547
|
+
// https://github.com/mgreter/sass2scss/issues/29
|
|
548
|
+
if (sass.substr(pos_left, 1) == "\\") {
|
|
549
|
+
converter.selector = true;
|
|
550
|
+
sass[pos_left] = ' ';
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// check if we have sass property syntax
|
|
554
|
+
if (sass.substr(pos_left, 1) == ":" && sass.substr(pos_left, 2) != "::")
|
|
555
|
+
{
|
|
556
|
+
|
|
557
|
+
// default to a selector
|
|
558
|
+
// change back if property found
|
|
559
|
+
converter.selector = true;
|
|
560
|
+
// get position of first whitespace char
|
|
561
|
+
size_t pos_wspace = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left);
|
|
562
|
+
// assertion check for valid result
|
|
563
|
+
if (pos_wspace != std::string::npos)
|
|
564
|
+
{
|
|
565
|
+
// get the possible pseudo selector
|
|
566
|
+
std::string pseudo = sass.substr(pos_left, pos_wspace - pos_left);
|
|
567
|
+
// get position of the first real property value char
|
|
568
|
+
// pseudo selectors get this far, but have no actual value
|
|
569
|
+
size_t pos_value = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_wspace);
|
|
570
|
+
// assertion check for valid result
|
|
571
|
+
if (pos_value != std::string::npos)
|
|
572
|
+
{
|
|
573
|
+
// only process if not (fallowed by a semicolon or is a pseudo selector)
|
|
574
|
+
if (!(sass.at(pos_value) == ':' || isPseudoSelector(pseudo)))
|
|
575
|
+
{
|
|
576
|
+
// create new string by interchanging the colon sign for property and value
|
|
577
|
+
sass = indent + sass.substr(pos_left + 1, pos_wspace - pos_left - 1) + ":" + sass.substr(pos_wspace);
|
|
578
|
+
// try to find a colon in the current line, but only ...
|
|
579
|
+
size_t pos_colon = sass.find_first_not_of(":", pos_left);
|
|
580
|
+
// assertion for valid result
|
|
581
|
+
if (pos_colon != std::string::npos)
|
|
582
|
+
{
|
|
583
|
+
// ... after the first word (skip beginning colons)
|
|
584
|
+
pos_colon = sass.find_first_of(":", pos_colon);
|
|
585
|
+
// it is a selector if there was no colon found
|
|
586
|
+
converter.selector = pos_colon == std::string::npos;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// check if we have a BEM property (one colon and no selector)
|
|
593
|
+
if (sass.substr(pos_left, 1) == ":" && converter.selector == true) {
|
|
594
|
+
size_t pos_wspace = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left);
|
|
595
|
+
sass = indent + sass.substr(pos_left + 1, pos_wspace) + ":";
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// terminate some statements immediately
|
|
601
|
+
else if (
|
|
602
|
+
sass.substr(pos_left, 5) == "@warn" ||
|
|
603
|
+
sass.substr(pos_left, 6) == "@debug" ||
|
|
604
|
+
sass.substr(pos_left, 6) == "@error" ||
|
|
605
|
+
sass.substr(pos_left, 6) == "@value" ||
|
|
606
|
+
sass.substr(pos_left, 8) == "@charset" ||
|
|
607
|
+
sass.substr(pos_left, 10) == "@namespace"
|
|
608
|
+
) { sass = indent + sass.substr(pos_left); }
|
|
609
|
+
// replace some specific sass shorthand directives (if not fallowed by a white space character)
|
|
610
|
+
else if (sass.substr(pos_left, 1) == "=")
|
|
611
|
+
{ sass = indent + "@mixin " + sass.substr(pos_left + 1); }
|
|
612
|
+
else if (sass.substr(pos_left, 1) == "+")
|
|
613
|
+
{
|
|
614
|
+
// must be followed by a mixin call (no whitespace afterwards or at ending directly)
|
|
615
|
+
if (sass[pos_left+1] != 0 && sass[pos_left+1] != ' ' && sass[pos_left+1] != '\t') {
|
|
616
|
+
sass = indent + "@include " + sass.substr(pos_left + 1);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// add quotes for import if needed
|
|
621
|
+
else if (sass.substr(pos_left, 7) == "@import")
|
|
622
|
+
{
|
|
623
|
+
// get positions for the actual import url
|
|
624
|
+
size_t pos_import = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left + 7);
|
|
625
|
+
size_t pos = sass.find_first_not_of(SASS2SCSS_FIND_WHITESPACE, pos_import);
|
|
626
|
+
size_t start = pos;
|
|
627
|
+
bool in_dqstr = false;
|
|
628
|
+
bool in_sqstr = false;
|
|
629
|
+
bool is_escaped = false;
|
|
630
|
+
do {
|
|
631
|
+
if (is_escaped) {
|
|
632
|
+
is_escaped = false;
|
|
633
|
+
}
|
|
634
|
+
else if (sass[pos] == '\\') {
|
|
635
|
+
is_escaped = true;
|
|
636
|
+
}
|
|
637
|
+
else if (sass[pos] == '"') {
|
|
638
|
+
if (!in_sqstr) in_dqstr = ! in_dqstr;
|
|
639
|
+
}
|
|
640
|
+
else if (sass[pos] == '\'') {
|
|
641
|
+
if (!in_dqstr) in_sqstr = ! in_sqstr;
|
|
642
|
+
}
|
|
643
|
+
else if (in_dqstr || in_sqstr) {
|
|
644
|
+
// skip over quoted stuff
|
|
645
|
+
}
|
|
646
|
+
else if (sass[pos] == ',' || sass[pos] == 0) {
|
|
647
|
+
if (sass[start] != '"' && sass[start] != '\'' && !isUrl(sass, start)) {
|
|
648
|
+
size_t end = findLastCharacter(sass, pos - 1) + 1;
|
|
649
|
+
sass = sass.replace(end, 0, "\"");
|
|
650
|
+
sass = sass.replace(start, 0, "\"");
|
|
651
|
+
pos += 2;
|
|
652
|
+
}
|
|
653
|
+
start = findFirstCharacter(sass, pos + 1);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
while (sass[pos++] != 0);
|
|
657
|
+
|
|
658
|
+
}
|
|
659
|
+
else if (
|
|
660
|
+
sass.substr(pos_left, 7) != "@return" &&
|
|
661
|
+
sass.substr(pos_left, 7) != "@extend" &&
|
|
662
|
+
sass.substr(pos_left, 8) != "@include" &&
|
|
663
|
+
sass.substr(pos_left, 8) != "@content"
|
|
664
|
+
) {
|
|
665
|
+
|
|
666
|
+
// probably a selector anyway
|
|
667
|
+
converter.selector = true;
|
|
668
|
+
// try to find first colon in the current line
|
|
669
|
+
size_t pos_colon = sass.find_first_of(":", pos_left);
|
|
670
|
+
// assertion that we have a colon
|
|
671
|
+
if (pos_colon != std::string::npos)
|
|
672
|
+
{
|
|
673
|
+
// it is not a selector if we have a space after a colon
|
|
674
|
+
if (sass[pos_colon+1] == ' ') converter.selector = false;
|
|
675
|
+
if (sass[pos_colon+1] == ' ') converter.selector = false;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// current line has more indentation
|
|
681
|
+
if (indent.length() >= INDENT(converter).length())
|
|
682
|
+
{
|
|
683
|
+
// not in comment mode
|
|
684
|
+
if (IS_PARSING(converter))
|
|
685
|
+
{
|
|
686
|
+
// has meaningful chars
|
|
687
|
+
if (hasCharData(sass))
|
|
688
|
+
{
|
|
689
|
+
// is probably a property
|
|
690
|
+
// also true for selectors
|
|
691
|
+
converter.property = true;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
// current line has more indentation
|
|
696
|
+
if (indent.length() > INDENT(converter).length())
|
|
697
|
+
{
|
|
698
|
+
// not in comment mode
|
|
699
|
+
if (IS_PARSING(converter))
|
|
700
|
+
{
|
|
701
|
+
// had meaningful chars
|
|
702
|
+
if (converter.property)
|
|
703
|
+
{
|
|
704
|
+
// print block opener
|
|
705
|
+
scss += opener(converter);
|
|
706
|
+
// push new stack context
|
|
707
|
+
converter.indents.push("");
|
|
708
|
+
// store block indentation
|
|
709
|
+
INDENT(converter) = indent;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
// is and will be a src comment
|
|
713
|
+
else if (!IS_CSS_COMMENT(converter))
|
|
714
|
+
{
|
|
715
|
+
// scss does not allow multiline src comments
|
|
716
|
+
// therefore add forward slashes to all lines
|
|
717
|
+
sass.at(INDENT(converter).length()+0) = '/';
|
|
718
|
+
// there is an edge case here if indentation
|
|
719
|
+
// is minimal (will overwrite the fist char)
|
|
720
|
+
sass.at(INDENT(converter).length()+1) = '/';
|
|
721
|
+
// could code around that, but I dont' think
|
|
722
|
+
// this will ever be the cause for any trouble
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// line is opening a new comment
|
|
727
|
+
if (open == "/*" || open == "//")
|
|
728
|
+
{
|
|
729
|
+
// reset the property state
|
|
730
|
+
converter.property = false;
|
|
731
|
+
// close previous comment
|
|
732
|
+
if (IS_CSS_COMMENT(converter) && open != "")
|
|
733
|
+
{
|
|
734
|
+
if (!STRIP_COMMENT(converter) && !CONVERT_COMMENT(converter)) scss += " */";
|
|
735
|
+
}
|
|
736
|
+
// force single line comments
|
|
737
|
+
// into a correct css comment
|
|
738
|
+
if (CONVERT_COMMENT(converter))
|
|
739
|
+
{
|
|
740
|
+
if (IS_PARSING(converter))
|
|
741
|
+
{ sass.at(pos_left + 1) = '*'; }
|
|
742
|
+
}
|
|
743
|
+
// set comment flag
|
|
744
|
+
converter.comment = open;
|
|
745
|
+
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// flush data only under certain conditions
|
|
749
|
+
if (!(
|
|
750
|
+
// strip css and src comments if option is set
|
|
751
|
+
(IS_COMMENT(converter) && STRIP_COMMENT(converter)) ||
|
|
752
|
+
// strip src comment even if strip option is not set
|
|
753
|
+
// but only if the keep src comment option is not set
|
|
754
|
+
(IS_SRC_COMMENT(converter) && ! KEEP_COMMENT(converter))
|
|
755
|
+
))
|
|
756
|
+
{
|
|
757
|
+
// flush data and buffer whitespace
|
|
758
|
+
scss += flush(sass, converter);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// get position of last meaningful char
|
|
762
|
+
size_t pos_right = sass.find_last_not_of(SASS2SCSS_FIND_WHITESPACE);
|
|
763
|
+
|
|
764
|
+
// check for invalid result
|
|
765
|
+
if (pos_right != std::string::npos)
|
|
766
|
+
{
|
|
767
|
+
|
|
768
|
+
// get the last meaningful char
|
|
769
|
+
std::string close = sass.substr(pos_right, 1);
|
|
770
|
+
|
|
771
|
+
// check if next line should be concatenated (list mode)
|
|
772
|
+
converter.comma = IS_PARSING(converter) && close == ",";
|
|
773
|
+
converter.semicolon = IS_PARSING(converter) && close == ";";
|
|
774
|
+
|
|
775
|
+
// check if we have more than
|
|
776
|
+
// one meaningful char
|
|
777
|
+
if (pos_right > 0)
|
|
778
|
+
{
|
|
779
|
+
|
|
780
|
+
// get the last two chars from string
|
|
781
|
+
std::string close = sass.substr(pos_right - 1, 2);
|
|
782
|
+
// update parser status for expicitly closed comment
|
|
783
|
+
if (close == "*/") converter.comment = "";
|
|
784
|
+
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
}
|
|
788
|
+
// EO have meaningful chars from end
|
|
789
|
+
|
|
790
|
+
}
|
|
791
|
+
// EO have meaningful chars from start
|
|
792
|
+
|
|
793
|
+
// return scss
|
|
794
|
+
return scss;
|
|
795
|
+
|
|
796
|
+
}
|
|
797
|
+
// EO process
|
|
798
|
+
|
|
799
|
+
// read line with either CR, LF or CR LF format
|
|
800
|
+
// http://stackoverflow.com/a/6089413/1550314
|
|
801
|
+
static std::istream& safeGetline(std::istream& is, std::string& t)
|
|
802
|
+
{
|
|
803
|
+
t.clear();
|
|
804
|
+
|
|
805
|
+
// The characters in the stream are read one-by-one using a std::streambuf.
|
|
806
|
+
// That is faster than reading them one-by-one using the std::istream.
|
|
807
|
+
// Code that uses streambuf this way must be guarded by a sentry object.
|
|
808
|
+
// The sentry object performs various tasks,
|
|
809
|
+
// such as thread synchronization and updating the stream state.
|
|
810
|
+
|
|
811
|
+
std::istream::sentry se(is, true);
|
|
812
|
+
std::streambuf* sb = is.rdbuf();
|
|
813
|
+
|
|
814
|
+
for(;;) {
|
|
815
|
+
int c = sb->sbumpc();
|
|
816
|
+
switch (c) {
|
|
817
|
+
case '\n':
|
|
818
|
+
return is;
|
|
819
|
+
case '\r':
|
|
820
|
+
if(sb->sgetc() == '\n')
|
|
821
|
+
sb->sbumpc();
|
|
822
|
+
return is;
|
|
823
|
+
case EOF:
|
|
824
|
+
// Also handle the case when the last line has no line ending
|
|
825
|
+
if(t.empty())
|
|
826
|
+
is.setstate(std::ios::eofbit);
|
|
827
|
+
return is;
|
|
828
|
+
default:
|
|
829
|
+
t += (char)c;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// the main converter function for c++
|
|
835
|
+
char* sass2scss (const std::string& sass, const int options)
|
|
836
|
+
{
|
|
837
|
+
|
|
838
|
+
// local variables
|
|
839
|
+
std::string line;
|
|
840
|
+
std::string scss = "";
|
|
841
|
+
std::stringstream stream(sass);
|
|
842
|
+
|
|
843
|
+
// create converter variable
|
|
844
|
+
converter converter;
|
|
845
|
+
// initialise all options
|
|
846
|
+
converter.comma = false;
|
|
847
|
+
converter.property = false;
|
|
848
|
+
converter.selector = false;
|
|
849
|
+
converter.semicolon = false;
|
|
850
|
+
converter.end_of_file = false;
|
|
851
|
+
converter.comment = "";
|
|
852
|
+
converter.whitespace = "";
|
|
853
|
+
converter.indents.push("");
|
|
854
|
+
converter.options = options;
|
|
855
|
+
|
|
856
|
+
// read line by line and process them
|
|
857
|
+
while(safeGetline(stream, line) && !stream.eof())
|
|
858
|
+
{ scss += process(line, converter); }
|
|
859
|
+
|
|
860
|
+
// create mutable string
|
|
861
|
+
std::string closer = "";
|
|
862
|
+
// set the end of file flag
|
|
863
|
+
converter.end_of_file = true;
|
|
864
|
+
// process to close all open blocks
|
|
865
|
+
scss += process(closer, converter);
|
|
866
|
+
|
|
867
|
+
// allocate new memory on the heap
|
|
868
|
+
// caller has to free it after use
|
|
869
|
+
char * cstr = (char*) malloc (scss.length() + 1);
|
|
870
|
+
// create a copy of the string
|
|
871
|
+
strcpy (cstr, scss.c_str());
|
|
872
|
+
// return pointer
|
|
873
|
+
return &cstr[0];
|
|
874
|
+
|
|
875
|
+
}
|
|
876
|
+
// EO sass2scss
|
|
877
|
+
|
|
878
|
+
}
|
|
879
|
+
// EO namespace
|
|
880
|
+
|
|
881
|
+
// implement for c
|
|
882
|
+
extern "C"
|
|
883
|
+
{
|
|
884
|
+
|
|
885
|
+
char* ADDCALL sass2scss (const char* sass, const int options)
|
|
886
|
+
{
|
|
887
|
+
return Sass::sass2scss(sass, options);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// Get compiled sass2scss version
|
|
891
|
+
const char* ADDCALL sass2scss_version(void) {
|
|
892
|
+
return SASS2SCSS_VERSION;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
}
|