sassc 1.8.1 → 1.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/ext/libsass/Makefile +10 -6
- data/ext/libsass/Readme.md +4 -4
- data/ext/libsass/appveyor.yml +16 -1
- data/ext/libsass/docs/README.md +1 -1
- data/ext/libsass/docs/api-context-example.md +1 -1
- data/ext/libsass/docs/api-context.md +1 -1
- data/ext/libsass/docs/api-doc.md +1 -1
- data/ext/libsass/docs/api-function-example.md +12 -3
- data/ext/libsass/docs/api-function-internal.md +4 -4
- data/ext/libsass/docs/api-function.md +15 -13
- data/ext/libsass/docs/api-importer-internal.md +9 -4
- data/ext/libsass/docs/api-value.md +1 -1
- data/ext/libsass/docs/build-shared-library.md +3 -3
- data/ext/libsass/docs/custom-functions-internal.md +1 -1
- data/ext/libsass/docs/{plugins.go → plugins.md} +0 -0
- data/ext/libsass/script/ci-build-libsass +25 -36
- data/ext/libsass/script/ci-install-deps +3 -8
- data/ext/libsass/script/ci-report-coverage +17 -13
- data/ext/libsass/src/ast.cpp +102 -7
- data/ext/libsass/src/ast.hpp +53 -27
- data/ext/libsass/src/ast_def_macros.hpp +8 -0
- data/ext/libsass/src/ast_fwd_decl.hpp +3 -2
- data/ext/libsass/src/backtrace.hpp +1 -1
- data/ext/libsass/src/bind.cpp +28 -17
- data/ext/libsass/src/bind.hpp +1 -1
- data/ext/libsass/src/context.cpp +441 -184
- data/ext/libsass/src/context.hpp +79 -82
- data/ext/libsass/src/debugger.hpp +3 -1
- data/ext/libsass/src/emitter.cpp +18 -17
- data/ext/libsass/src/emitter.hpp +5 -2
- data/ext/libsass/src/error_handling.cpp +78 -7
- data/ext/libsass/src/error_handling.hpp +50 -9
- data/ext/libsass/src/eval.cpp +100 -36
- data/ext/libsass/src/eval.hpp +5 -5
- data/ext/libsass/src/expand.cpp +32 -3
- data/ext/libsass/src/extend.cpp +1 -1
- data/ext/libsass/src/file.cpp +39 -27
- data/ext/libsass/src/file.hpp +67 -13
- data/ext/libsass/src/functions.cpp +39 -32
- data/ext/libsass/src/inspect.cpp +21 -21
- data/ext/libsass/src/json.cpp +1 -1
- data/ext/libsass/src/lexer.hpp +33 -4
- data/ext/libsass/src/output.cpp +11 -11
- data/ext/libsass/src/parser.cpp +28 -130
- data/ext/libsass/src/parser.hpp +0 -4
- data/ext/libsass/src/prelexer.cpp +8 -5
- data/ext/libsass/src/prelexer.hpp +1 -3
- data/ext/libsass/src/sass_context.cpp +52 -241
- data/ext/libsass/src/sass_context.hpp +156 -0
- data/ext/libsass/src/sass_functions.cpp +1 -26
- data/ext/libsass/src/sass_functions.hpp +32 -0
- data/ext/libsass/src/sass_interface.cpp +14 -48
- data/ext/libsass/src/sass_values.cpp +3 -77
- data/ext/libsass/src/sass_values.hpp +81 -0
- data/ext/libsass/src/source_map.cpp +7 -7
- data/ext/libsass/src/source_map.hpp +1 -4
- data/ext/libsass/src/to_string.cpp +4 -3
- data/ext/libsass/src/to_string.hpp +2 -1
- data/ext/libsass/src/util.cpp +34 -16
- data/ext/libsass/src/util.hpp +10 -8
- data/lib/sassc/version.rb +1 -1
- data/lib/tasks/libsass.rb +1 -1
- data/test/custom_importer_test.rb +6 -4
- data/test/engine_test.rb +5 -3
- data/test/functions_test.rb +1 -0
- data/test/native_test.rb +1 -1
- metadata +6 -4
- data/ext/libsass/script/coveralls-debug +0 -32
data/ext/libsass/src/bind.hpp
CHANGED
@@ -12,7 +12,7 @@ namespace Sass {
|
|
12
12
|
class Eval;
|
13
13
|
typedef Environment<AST_Node*> Env;
|
14
14
|
|
15
|
-
void bind(std::string
|
15
|
+
void bind(std::string type, std::string name, Parameters*, Arguments*, Context*, Env*, Eval*);
|
16
16
|
}
|
17
17
|
|
18
18
|
#endif
|
data/ext/libsass/src/context.cpp
CHANGED
@@ -38,88 +38,80 @@ namespace Sass {
|
|
38
38
|
using namespace File;
|
39
39
|
using namespace Sass;
|
40
40
|
|
41
|
-
|
41
|
+
inline bool sort_importers (const Sass_Importer_Entry& i, const Sass_Importer_Entry& j)
|
42
|
+
{ return sass_importer_get_priority(i) > sass_importer_get_priority(j); }
|
43
|
+
|
44
|
+
static std::string safe_input(const char* in_path)
|
42
45
|
{
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
// enforce some safe defaults
|
47
|
+
// used to create relative file links
|
48
|
+
std::string safe_path(in_path ? in_path : "");
|
49
|
+
return safe_path == "" ? "stdin" : safe_path;
|
46
50
|
}
|
47
51
|
|
48
|
-
|
49
|
-
{
|
52
|
+
static std::string safe_output(const char* out_path, const std::string& input_path = "")
|
53
|
+
{
|
54
|
+
std::string safe_path(out_path ? out_path : "");
|
55
|
+
// maybe we can extract an output path from input path
|
56
|
+
if (safe_path == "" && input_path != "") {
|
57
|
+
int lastindex = static_cast<int>(input_path.find_last_of("."));
|
58
|
+
return (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
|
59
|
+
}
|
60
|
+
// enforce some safe defaults
|
61
|
+
// used to create relative file links
|
62
|
+
return safe_path == "" ? "stdout" : safe_path;
|
63
|
+
}
|
50
64
|
|
51
|
-
Context::Context(
|
52
|
-
:
|
65
|
+
Context::Context(struct Sass_Context* c_ctx)
|
66
|
+
: CWD(File::get_cwd()),
|
67
|
+
entry_path(""),
|
53
68
|
head_imports(0),
|
54
69
|
mem(Memory_Manager()),
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
70
|
+
plugins(),
|
71
|
+
emitter(this),
|
72
|
+
|
73
|
+
strings(),
|
74
|
+
resources(),
|
75
|
+
sheets(),
|
76
|
+
subset_map(),
|
77
|
+
import_stack(),
|
78
|
+
|
79
|
+
c_options (c_ctx),
|
80
|
+
|
65
81
|
c_headers (std::vector<Sass_Importer_Entry>()),
|
66
82
|
c_importers (std::vector<Sass_Importer_Entry>()),
|
67
83
|
c_functions (std::vector<Sass_Function_Entry>()),
|
68
|
-
indent (initializers.indent()),
|
69
|
-
linefeed (initializers.linefeed()),
|
70
|
-
input_path (make_canonical_path(initializers.input_path())),
|
71
|
-
output_path (make_canonical_path(initializers.output_path())),
|
72
|
-
source_comments (initializers.source_comments()),
|
73
|
-
output_style (initializers.output_style()),
|
74
|
-
source_map_file (make_canonical_path(initializers.source_map_file())),
|
75
|
-
source_map_root (initializers.source_map_root()), // pass-through
|
76
|
-
source_map_embed (initializers.source_map_embed()),
|
77
|
-
source_map_contents (initializers.source_map_contents()),
|
78
|
-
omit_source_map_url (initializers.omit_source_map_url()),
|
79
|
-
is_indented_syntax_src (initializers.is_indented_syntax_src()),
|
80
|
-
precision (initializers.precision()),
|
81
|
-
plugins(),
|
82
|
-
subset_map (Subset_Map<std::string, std::pair<Complex_Selector*, Compound_Selector*> >())
|
83
|
-
{
|
84
84
|
|
85
|
-
|
85
|
+
indent (safe_str(c_options->indent, " ")),
|
86
|
+
linefeed (safe_str(c_options->linefeed, "\n")),
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
input_path (make_canonical_path(safe_input(c_options->input_path))),
|
89
|
+
output_path (make_canonical_path(safe_output(c_options->output_path, input_path))),
|
90
|
+
source_map_file (make_canonical_path(safe_str(c_options->source_map_file, ""))),
|
91
|
+
source_map_root (make_canonical_path(safe_str(c_options->source_map_root, "")))
|
92
|
+
|
93
|
+
{
|
91
94
|
|
92
|
-
|
93
|
-
|
95
|
+
// add cwd to include paths
|
96
|
+
include_paths.push_back(CWD);
|
97
|
+
|
98
|
+
// collect more paths from different options
|
99
|
+
collect_include_paths(sass_option_get_include_path(c_options));
|
94
100
|
// collect_include_paths(initializers.include_paths_array());
|
95
|
-
collect_plugin_paths(
|
101
|
+
collect_plugin_paths(sass_option_get_plugin_path(c_options));
|
96
102
|
// collect_plugin_paths(initializers.plugin_paths_array());
|
97
103
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
for(auto fn : plugins.get_functions())
|
103
|
-
c_functions.push_back(fn);
|
104
|
-
}
|
105
|
-
for(auto fn : plugins.get_headers()) {
|
106
|
-
c_headers.push_back(fn);
|
107
|
-
}
|
108
|
-
for(auto fn : plugins.get_importers()) {
|
109
|
-
c_importers.push_back(fn);
|
110
|
-
}
|
104
|
+
// load plugins and register custom behaviors
|
105
|
+
for(auto plug : plugin_paths) plugins.load_plugins(plug);
|
106
|
+
for(auto fn : plugins.get_headers()) c_headers.push_back(fn);
|
107
|
+
for(auto fn : plugins.get_importers()) c_importers.push_back(fn);
|
108
|
+
for(auto fn : plugins.get_functions()) c_functions.push_back(fn);
|
111
109
|
|
110
|
+
// sort the items by priority (lowest first)
|
112
111
|
sort (c_headers.begin(), c_headers.end(), sort_importers);
|
113
112
|
sort (c_importers.begin(), c_importers.end(), sort_importers);
|
114
|
-
std::string entry_point = initializers.entry_point();
|
115
|
-
if (!entry_point.empty()) {
|
116
|
-
std::string result(add_file(entry_point, true));
|
117
|
-
if (result.empty()) {
|
118
|
-
throw "File to read not found or unreadable: " + entry_point;
|
119
|
-
}
|
120
|
-
}
|
121
113
|
|
122
|
-
emitter.set_filename(
|
114
|
+
emitter.set_filename(abs2rel(output_path, source_map_file, CWD));
|
123
115
|
|
124
116
|
}
|
125
117
|
|
@@ -142,16 +134,35 @@ namespace Sass {
|
|
142
134
|
|
143
135
|
Context::~Context()
|
144
136
|
{
|
145
|
-
//
|
146
|
-
|
147
|
-
|
148
|
-
|
137
|
+
// resources were allocated by strdup or malloc
|
138
|
+
for (size_t i = 0; i < resources.size(); ++i) {
|
139
|
+
free(resources[i].contents);
|
140
|
+
free(resources[i].srcmap);
|
141
|
+
}
|
149
142
|
// free all strings we kept alive during compiler execution
|
150
143
|
for (size_t n = 0; n < strings.size(); ++n) free(strings[n]);
|
151
144
|
// everything that gets put into sources will be freed by us
|
152
|
-
|
145
|
+
// this shouldn't have anything in it anyway!?
|
146
|
+
for (size_t m = 0; m < import_stack.size(); ++m) {
|
147
|
+
sass_import_take_source(import_stack[m]);
|
148
|
+
sass_import_take_srcmap(import_stack[m]);
|
149
|
+
sass_delete_import(import_stack[m]);
|
150
|
+
}
|
153
151
|
// clear inner structures (vectors) and input source
|
154
|
-
|
152
|
+
resources.clear(); import_stack.clear();
|
153
|
+
}
|
154
|
+
|
155
|
+
Data_Context::~Data_Context()
|
156
|
+
{
|
157
|
+
// --> this will be freed by resources
|
158
|
+
// make sure we free the source even if not processed!
|
159
|
+
// if (resources.size() == 0 && source_c_str) free(source_c_str);
|
160
|
+
// if (resources.size() == 0 && srcmap_c_str) free(srcmap_c_str);
|
161
|
+
// source_c_str = 0; srcmap_c_str = 0;
|
162
|
+
}
|
163
|
+
|
164
|
+
File_Context::~File_Context()
|
165
|
+
{
|
155
166
|
}
|
156
167
|
|
157
168
|
void Context::collect_include_paths(const char* paths_str)
|
@@ -181,10 +192,9 @@ namespace Sass {
|
|
181
192
|
|
182
193
|
void Context::collect_include_paths(const char** paths_array)
|
183
194
|
{
|
184
|
-
if (paths_array)
|
185
|
-
|
186
|
-
|
187
|
-
}
|
195
|
+
if (!paths_array) return;
|
196
|
+
for (size_t i = 0; paths_array[i]; i++) {
|
197
|
+
collect_include_paths(paths_array[i]);
|
188
198
|
}
|
189
199
|
}
|
190
200
|
|
@@ -215,70 +225,255 @@ namespace Sass {
|
|
215
225
|
|
216
226
|
void Context::collect_plugin_paths(const char** paths_array)
|
217
227
|
{
|
218
|
-
if (paths_array)
|
219
|
-
|
220
|
-
|
221
|
-
}
|
228
|
+
if (!paths_array) return;
|
229
|
+
for (size_t i = 0; paths_array[i]; i++) {
|
230
|
+
collect_plugin_paths(paths_array[i]);
|
222
231
|
}
|
223
232
|
}
|
224
|
-
|
233
|
+
|
234
|
+
|
235
|
+
// resolve the imp_path in base_path or include_paths
|
236
|
+
// looks for alternatives and returns a list from one directory
|
237
|
+
std::vector<Include> Context::find_includes(const Importer& import)
|
225
238
|
{
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
239
|
+
// make sure we resolve against an absolute path
|
240
|
+
std::string base_path(rel2abs(import.base_path));
|
241
|
+
// first try to resolve the load path relative to the base path
|
242
|
+
std::vector<Include> vec(resolve_includes(base_path, import.imp_path));
|
243
|
+
// then search in every include path (but only if nothing found yet)
|
244
|
+
for (size_t i = 0, S = include_paths.size(); vec.size() == 0 && i < S; ++i)
|
245
|
+
{
|
246
|
+
// call resolve_includes and individual base path and append all results
|
247
|
+
std::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path));
|
248
|
+
if (resolved.size()) vec.insert(vec.end(), resolved.begin(), resolved.end());
|
249
|
+
}
|
250
|
+
// return vector
|
251
|
+
return vec;
|
231
252
|
}
|
232
253
|
|
233
|
-
|
234
|
-
|
254
|
+
|
255
|
+
// register include with resolved path and its content
|
256
|
+
// memory of the resources will be freed by us on exit
|
257
|
+
void Context::register_resource(const Include& inc, const Resource& res)
|
235
258
|
{
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
if (
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
259
|
+
|
260
|
+
// do not parse same resource twice
|
261
|
+
// maybe raise an error in this case
|
262
|
+
// if (sheets.count(inc.abs_path)) {
|
263
|
+
// free(res.contents); free(res.srcmap);
|
264
|
+
// throw std::runtime_error("duplicate resource registered");
|
265
|
+
// return;
|
266
|
+
// }
|
267
|
+
|
268
|
+
// get index for this resource
|
269
|
+
size_t idx = resources.size();
|
270
|
+
|
271
|
+
// tell emitter about new resource
|
272
|
+
emitter.add_source_index(idx);
|
273
|
+
|
274
|
+
// put resources under our control
|
275
|
+
// the memory will be freed later
|
276
|
+
resources.push_back(res);
|
277
|
+
|
278
|
+
// add a relative link to the working directory
|
279
|
+
included_files.push_back(inc.abs_path);
|
280
|
+
// add a relative link to the source map output file
|
281
|
+
srcmap_links.push_back(abs2rel(inc.abs_path, source_map_file, CWD));
|
282
|
+
|
283
|
+
// get pointer to the loaded content
|
284
|
+
Sass_Import_Entry import = sass_make_import(
|
285
|
+
inc.imp_path.c_str(),
|
286
|
+
inc.abs_path.c_str(),
|
287
|
+
res.contents,
|
288
|
+
res.srcmap
|
289
|
+
);
|
290
|
+
// add the entry to the stack
|
291
|
+
import_stack.push_back(import);
|
292
|
+
|
293
|
+
// get pointer to the loaded content
|
294
|
+
const char* contents = resources[idx].contents;
|
295
|
+
// keep a copy of the path around (for parserstates)
|
296
|
+
// ToDo: we clean it, but still not very elegant!?
|
297
|
+
strings.push_back(sass_strdup(inc.abs_path.c_str()));
|
298
|
+
// create the initial parser state from resource
|
299
|
+
ParserState pstate(strings.back(), contents, idx);
|
300
|
+
// create a parser instance from the given c_str buffer
|
301
|
+
Parser p(Parser::from_c_str(contents, *this, pstate));
|
302
|
+
// do not yet dispose these buffers
|
303
|
+
sass_import_take_source(import);
|
304
|
+
sass_import_take_srcmap(import);
|
305
|
+
// then parse the root block
|
306
|
+
Block* root = p.parse();
|
307
|
+
// delete memory of current stack frame
|
308
|
+
sass_delete_import(import_stack.back());
|
309
|
+
// remove current stack frame
|
310
|
+
import_stack.pop_back();
|
311
|
+
// create key/value pair for ast node
|
312
|
+
std::pair<const std::string, const StyleSheet>
|
313
|
+
ast_pair(inc.abs_path, { res, root });
|
314
|
+
// register resulting resource
|
315
|
+
sheets.insert(ast_pair);
|
316
|
+
|
250
317
|
}
|
251
318
|
|
252
|
-
// Add a new import
|
253
|
-
|
254
|
-
std::string Context::add_file(const std::string& base, const std::string& file, ParserState pstate)
|
319
|
+
// Add a new import to the context (called from `import_url`)
|
320
|
+
Include Context::load_import(const Importer& imp, ParserState pstate)
|
255
321
|
{
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
322
|
+
|
323
|
+
// search for valid imports (ie. partials) on the filesystem
|
324
|
+
// this may return more than one valid result (ambiguous imp_path)
|
325
|
+
const std::vector<Include> resolved(find_includes(imp));
|
326
|
+
|
327
|
+
// error nicely on ambiguous imp_path
|
261
328
|
if (resolved.size() > 1) {
|
262
329
|
std::stringstream msg_stream;
|
263
330
|
msg_stream << "It's not clear which file to import for ";
|
264
|
-
msg_stream << "'@import \"" <<
|
331
|
+
msg_stream << "'@import \"" << imp.imp_path << "\"'." << "\n";
|
265
332
|
msg_stream << "Candidates:" << "\n";
|
266
333
|
for (size_t i = 0, L = resolved.size(); i < L; ++i)
|
267
|
-
{ msg_stream << " " << resolved[i].
|
334
|
+
{ msg_stream << " " << resolved[i].imp_path << "\n"; }
|
268
335
|
msg_stream << "Please delete or rename all but one of these files." << "\n";
|
269
336
|
error(msg_stream.str(), pstate);
|
270
337
|
}
|
271
|
-
|
338
|
+
|
339
|
+
// process the resolved entry
|
340
|
+
else if (resolved.size() == 1) {
|
341
|
+
// use cache for the resource loading
|
342
|
+
if (sheets.count(resolved[0].abs_path)) return resolved[0];
|
343
|
+
// try to read the content of the resolved file entry
|
344
|
+
// the memory buffer returned must be freed by us!
|
272
345
|
if (char* contents = read_file(resolved[0].abs_path)) {
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
346
|
+
// register the newly resolved file resource
|
347
|
+
register_resource(resolved[0], { contents, 0 });
|
348
|
+
// return resolved entry
|
349
|
+
return resolved[0];
|
350
|
+
}
|
351
|
+
}
|
352
|
+
|
353
|
+
// nothing found
|
354
|
+
return { imp, "" };
|
355
|
+
|
356
|
+
}
|
357
|
+
|
358
|
+
void Context::import_url (Import* imp, std::string load_path, const std::string& ctx_path) {
|
359
|
+
|
360
|
+
ParserState pstate(imp->pstate());
|
361
|
+
std::string imp_path(unquote(load_path));
|
362
|
+
std::string protocol("file");
|
363
|
+
|
364
|
+
using namespace Prelexer;
|
365
|
+
if (const char* proto = sequence< identifier, exactly<':'>, exactly<'/'>, exactly<'/'> >(imp_path.c_str())) {
|
366
|
+
|
367
|
+
protocol = std::string(imp_path.c_str(), proto - 3);
|
368
|
+
// std::cerr << "==================== " << protocol << "\n";
|
369
|
+
if (protocol.compare("file") && true) {
|
370
|
+
|
371
|
+
}
|
372
|
+
}
|
373
|
+
|
374
|
+
// add urls (protocol other than file) and urls without procotol to `urls` member
|
375
|
+
// ToDo: if ctx_path is already a file resource, we should not add it here?
|
376
|
+
if (imp->media_queries() || protocol != "file" || imp_path.substr(0, 2) == "//") {
|
377
|
+
imp->urls().push_back(SASS_MEMORY_NEW(mem, String_Quoted, imp->pstate(), load_path));
|
378
|
+
}
|
379
|
+
else if (imp_path.length() > 4 && imp_path.substr(imp_path.length() - 4, 4) == ".css") {
|
380
|
+
String_Constant* loc = SASS_MEMORY_NEW(mem, String_Constant, pstate, unquote(load_path));
|
381
|
+
Argument* loc_arg = SASS_MEMORY_NEW(mem, Argument, pstate, loc);
|
382
|
+
Arguments* loc_args = SASS_MEMORY_NEW(mem, Arguments, pstate);
|
383
|
+
(*loc_args) << loc_arg;
|
384
|
+
Function_Call* new_url = SASS_MEMORY_NEW(mem, Function_Call, pstate, "url", loc_args);
|
385
|
+
imp->urls().push_back(new_url);
|
386
|
+
}
|
387
|
+
else {
|
388
|
+
const Importer importer(imp_path, ctx_path);
|
389
|
+
Include include(load_import(importer, pstate));
|
390
|
+
if (include.abs_path.empty()) {
|
391
|
+
error("File to import not found or unreadable: " + imp_path + "\nParent style sheet: " + ctx_path, pstate);
|
392
|
+
}
|
393
|
+
imp->incs().push_back(include);
|
394
|
+
}
|
395
|
+
|
396
|
+
}
|
397
|
+
|
398
|
+
|
399
|
+
// call custom importers on the given (unquoted) load_path and eventually parse the resulting style_sheet
|
400
|
+
bool Context::call_loader(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp, std::vector<Sass_Importer_Entry> importers, bool only_one)
|
401
|
+
{
|
402
|
+
// unique counter
|
403
|
+
size_t count = 0;
|
404
|
+
// need one correct import
|
405
|
+
bool has_import = false;
|
406
|
+
// process all custom importers (or custom headers)
|
407
|
+
for (Sass_Importer_Entry& importer : importers) {
|
408
|
+
// int priority = sass_importer_get_priority(importer);
|
409
|
+
Sass_Importer_Fn fn = sass_importer_get_function(importer);
|
410
|
+
// skip importer if it returns NULL
|
411
|
+
if (Sass_Import_List includes =
|
412
|
+
fn(load_path.c_str(), importer, c_compiler)
|
413
|
+
) {
|
414
|
+
// get c pointer copy to iterate over
|
415
|
+
Sass_Import_List it_includes = includes;
|
416
|
+
while (*it_includes) { ++count;
|
417
|
+
// create unique path to use as key
|
418
|
+
std::string uniq_path = load_path;
|
419
|
+
if (!only_one && count) {
|
420
|
+
std::stringstream path_strm;
|
421
|
+
path_strm << uniq_path << ":" << count;
|
422
|
+
uniq_path = path_strm.str();
|
423
|
+
}
|
424
|
+
// create the importer struct
|
425
|
+
Importer importer(uniq_path, ctx_path);
|
426
|
+
// query data from the current include
|
427
|
+
Sass_Import_Entry include = *it_includes;
|
428
|
+
char* source = sass_import_take_source(include);
|
429
|
+
char* srcmap = sass_import_take_source(include);
|
430
|
+
size_t line = sass_import_get_error_line(include);
|
431
|
+
size_t column = sass_import_get_error_column(include);
|
432
|
+
const char *abs_path = sass_import_get_abs_path(include);
|
433
|
+
// handle error message passed back from custom importer
|
434
|
+
// it may (or may not) override the line and column info
|
435
|
+
if (const char* err_message = sass_import_get_error_message(include)) {
|
436
|
+
if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap });
|
437
|
+
if (line == std::string::npos && column == std::string::npos) error(err_message, pstate);
|
438
|
+
else error(err_message, ParserState(ctx_path, source, Position(line, column)));
|
439
|
+
}
|
440
|
+
// content for import was set
|
441
|
+
else if (source) {
|
442
|
+
// resolved abs_path should be set by custom importer
|
443
|
+
// use the created uniq_path as fallback (maybe enforce)
|
444
|
+
std::string path_key(abs_path ? abs_path : uniq_path);
|
445
|
+
// create the importer struct
|
446
|
+
Include include(importer, path_key);
|
447
|
+
// attach information to AST node
|
448
|
+
imp->incs().push_back(include);
|
449
|
+
// register the resource buffers
|
450
|
+
register_resource(include, { source, srcmap });
|
451
|
+
}
|
452
|
+
// only a path was retuned
|
453
|
+
// try to load it like normal
|
454
|
+
else if(abs_path) {
|
455
|
+
// checks some urls to preserve
|
456
|
+
// `http://`, `https://` and `//`
|
457
|
+
// or dispatchs to `import_file`
|
458
|
+
// which will check for a `.css` extension
|
459
|
+
// or resolves the file on the filesystem
|
460
|
+
// added and resolved via `add_file`
|
461
|
+
// finally stores everything on `imp`
|
462
|
+
import_url(imp, abs_path, ctx_path);
|
463
|
+
}
|
464
|
+
// move to next
|
465
|
+
++it_includes;
|
466
|
+
}
|
467
|
+
// deallocate the returned memory
|
468
|
+
sass_delete_import_list(includes);
|
469
|
+
// set success flag
|
470
|
+
has_import = true;
|
471
|
+
// break out of loop
|
472
|
+
if (only_one) break;
|
278
473
|
}
|
279
474
|
}
|
280
|
-
//
|
281
|
-
return
|
475
|
+
// return result
|
476
|
+
return has_import;
|
282
477
|
}
|
283
478
|
|
284
479
|
void register_function(Context&, Signature sig, Native_Function f, Env* env);
|
@@ -288,53 +483,148 @@ namespace Sass {
|
|
288
483
|
void register_c_functions(Context&, Env* env, Sass_Function_List);
|
289
484
|
void register_c_function(Context&, Env* env, Sass_Function_Entry);
|
290
485
|
|
291
|
-
char* Context::
|
486
|
+
char* Context::render(Block* root)
|
292
487
|
{
|
488
|
+
// check for valid block
|
293
489
|
if (!root) return 0;
|
490
|
+
// start the render process
|
294
491
|
root->perform(&emitter);
|
492
|
+
// finish emitter stream
|
295
493
|
emitter.finalize();
|
494
|
+
// get the resulting buffer from stream
|
296
495
|
OutputBuffer emitted = emitter.get_buffer();
|
297
|
-
|
298
|
-
if (!omit_source_map_url) {
|
299
|
-
|
300
|
-
|
496
|
+
// should we append a source map url?
|
497
|
+
if (!c_options->omit_source_map_url) {
|
498
|
+
// generate an embeded source map
|
499
|
+
if (c_options->source_map_embed) {
|
500
|
+
emitted.buffer += linefeed;
|
501
|
+
emitted.buffer += format_embedded_source_map();
|
301
502
|
}
|
503
|
+
// or just link the generated one
|
302
504
|
else if (source_map_file != "") {
|
303
|
-
|
505
|
+
emitted.buffer += linefeed;
|
506
|
+
emitted.buffer += format_source_mapping_url(source_map_file);
|
304
507
|
}
|
305
508
|
}
|
306
|
-
|
509
|
+
// create a copy of the resulting buffer string
|
510
|
+
// this must be freed or taken over by implementor
|
511
|
+
return sass_strdup(emitted.buffer.c_str());
|
307
512
|
}
|
308
513
|
|
309
|
-
void Context::
|
514
|
+
void Context::apply_custom_headers(Block* root, const char* ctx_path, ParserState pstate)
|
310
515
|
{
|
311
|
-
|
516
|
+
// create a custom import to resolve headers
|
517
|
+
Import* imp = SASS_MEMORY_NEW(mem, Import, pstate);
|
518
|
+
// dispatch headers which will add custom functions
|
519
|
+
// custom headers are added to the import instance
|
520
|
+
call_headers(entry_path, ctx_path, pstate, imp);
|
521
|
+
// increase head count to skip later
|
522
|
+
head_imports += resources.size() - 1;
|
523
|
+
// add the statement if we have urls
|
524
|
+
if (!imp->urls().empty()) (*root) << imp;
|
525
|
+
// process all other resources (add Import_Stub nodes)
|
526
|
+
for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
|
527
|
+
(*root) << SASS_MEMORY_NEW(mem, Import_Stub, pstate, imp->incs()[i]);
|
528
|
+
}
|
529
|
+
}
|
530
|
+
|
531
|
+
Block* File_Context::parse()
|
532
|
+
{
|
533
|
+
|
534
|
+
// check if entry file is given
|
535
|
+
if (input_path.empty()) return 0;
|
536
|
+
|
537
|
+
// create absolute path from input filename
|
538
|
+
// ToDo: this should be resolved via custom importers
|
539
|
+
std::string abs_path(rel2abs(input_path, CWD));
|
540
|
+
|
541
|
+
// try to load the entry file
|
542
|
+
char* contents = read_file(abs_path);
|
543
|
+
|
544
|
+
// alternatively also look inside each include path folder
|
545
|
+
// I think this differs from ruby sass (IMO too late to remove)
|
546
|
+
for (size_t i = 0, S = include_paths.size(); contents == 0 && i < S; ++i) {
|
547
|
+
// build absolute path for this include path entry
|
548
|
+
abs_path = rel2abs(input_path, include_paths[i]);
|
549
|
+
// try to load the resulting path
|
550
|
+
contents = read_file(abs_path);
|
551
|
+
}
|
552
|
+
|
553
|
+
// abort early if no content could be loaded (various reasons)
|
554
|
+
if (!contents) throw "File to read not found or unreadable: " + input_path;
|
555
|
+
|
556
|
+
// store entry path
|
557
|
+
entry_path = abs_path;
|
558
|
+
|
559
|
+
// create entry only for import stack
|
312
560
|
Sass_Import_Entry import = sass_make_import(
|
313
|
-
|
314
|
-
|
315
|
-
|
561
|
+
input_path.c_str(),
|
562
|
+
entry_path.c_str(),
|
563
|
+
contents,
|
564
|
+
0
|
316
565
|
);
|
566
|
+
// add the entry to the stack
|
317
567
|
import_stack.push_back(import);
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
// ToDo: we store by load_path, which can lead
|
326
|
-
// to duplicates if importer reports the same path
|
327
|
-
// Maybe we should add an error for duplicates!?
|
328
|
-
style_sheets[queue[i].load_path] = ast;
|
568
|
+
|
569
|
+
// create the source entry for file entry
|
570
|
+
register_resource({{ input_path, "." }, abs_path }, { contents, 0 });
|
571
|
+
|
572
|
+
// create root ast tree node
|
573
|
+
return compile();
|
574
|
+
|
329
575
|
}
|
330
576
|
|
331
|
-
Block*
|
577
|
+
Block* Data_Context::parse()
|
332
578
|
{
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
579
|
+
|
580
|
+
// check if source string is given
|
581
|
+
if (!source_c_str) return 0;
|
582
|
+
|
583
|
+
// convert indented sass syntax
|
584
|
+
if(c_options->is_indented_syntax_src) {
|
585
|
+
// call sass2scss to convert the string
|
586
|
+
char * converted = sass2scss(source_c_str,
|
587
|
+
// preserve the structure as much as possible
|
588
|
+
SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
|
589
|
+
// replace old source_c_str with converted
|
590
|
+
free(source_c_str); source_c_str = converted;
|
337
591
|
}
|
592
|
+
|
593
|
+
// remember entry path (defaults to stdin for string)
|
594
|
+
entry_path = input_path.empty() ? "stdin" : input_path;
|
595
|
+
|
596
|
+
// ToDo: this may be resolved via custom importers
|
597
|
+
std::string abs_path(rel2abs(entry_path));
|
598
|
+
char* abs_path_c_str = sass_strdup(abs_path.c_str());
|
599
|
+
strings.push_back(abs_path_c_str);
|
600
|
+
|
601
|
+
// create entry only for the import stack
|
602
|
+
Sass_Import_Entry import = sass_make_import(
|
603
|
+
entry_path.c_str(),
|
604
|
+
abs_path_c_str,
|
605
|
+
source_c_str,
|
606
|
+
srcmap_c_str
|
607
|
+
);
|
608
|
+
// add the entry to the stack
|
609
|
+
import_stack.push_back(import);
|
610
|
+
|
611
|
+
// register a synthetic resource (path does not really exist, skip in includes)
|
612
|
+
register_resource({{ input_path, "." }, input_path }, { source_c_str, srcmap_c_str });
|
613
|
+
|
614
|
+
// create root ast tree node
|
615
|
+
return compile();
|
616
|
+
}
|
617
|
+
|
618
|
+
|
619
|
+
|
620
|
+
// parse root block from includes
|
621
|
+
Block* Context::compile()
|
622
|
+
{
|
623
|
+
// abort if there is no data
|
624
|
+
if (resources.size() == 0) return 0;
|
625
|
+
// get root block from the first style sheet
|
626
|
+
Block* root = sheets.at(entry_path).root;
|
627
|
+
// abort on invalid root
|
338
628
|
if (root == 0) return 0;
|
339
629
|
|
340
630
|
Env global; // create root environment
|
@@ -367,39 +657,11 @@ namespace Sass {
|
|
367
657
|
// return processed tree
|
368
658
|
return root;
|
369
659
|
}
|
370
|
-
// EO
|
371
|
-
|
372
|
-
Block* Context::parse_string()
|
373
|
-
{
|
374
|
-
if (!source_c_str) return 0;
|
375
|
-
queue.clear();
|
376
|
-
if(is_indented_syntax_src) {
|
377
|
-
char * contents = sass2scss(source_c_str, SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
|
378
|
-
add_source(input_path, input_path, contents);
|
379
|
-
free(source_c_str);
|
380
|
-
return parse_file();
|
381
|
-
}
|
382
|
-
add_source(input_path, input_path, source_c_str);
|
383
|
-
size_t idx = queue.size() - 1;
|
384
|
-
process_queue_entry(queue[idx], idx);
|
385
|
-
return parse_file();
|
386
|
-
}
|
387
|
-
|
388
|
-
char* Context::compile_file()
|
389
|
-
{
|
390
|
-
// returns NULL if something fails
|
391
|
-
return compile_block(parse_file());
|
392
|
-
}
|
393
|
-
|
394
|
-
char* Context::compile_string()
|
395
|
-
{
|
396
|
-
// returns NULL if something fails
|
397
|
-
return compile_block(parse_string());
|
398
|
-
}
|
660
|
+
// EO compile
|
399
661
|
|
400
662
|
std::string Context::format_embedded_source_map()
|
401
663
|
{
|
402
|
-
std::string map = emitter.
|
664
|
+
std::string map = emitter.render_srcmap(*this);
|
403
665
|
std::istringstream is( map );
|
404
666
|
std::ostringstream buffer;
|
405
667
|
base64::encoder E;
|
@@ -411,15 +673,15 @@ namespace Sass {
|
|
411
673
|
|
412
674
|
std::string Context::format_source_mapping_url(const std::string& file)
|
413
675
|
{
|
414
|
-
std::string url =
|
676
|
+
std::string url = abs2rel(file, output_path, CWD);
|
415
677
|
return "/*# sourceMappingURL=" + url + " */";
|
416
678
|
}
|
417
679
|
|
418
|
-
char* Context::
|
680
|
+
char* Context::render_srcmap()
|
419
681
|
{
|
420
682
|
if (source_map_file == "") return 0;
|
421
683
|
char* result = 0;
|
422
|
-
std::string map = emitter.
|
684
|
+
std::string map = emitter.render_srcmap(*this);
|
423
685
|
result = sass_strdup(map.c_str());
|
424
686
|
return result;
|
425
687
|
}
|
@@ -429,7 +691,7 @@ namespace Sass {
|
|
429
691
|
// we probably always want to skip the header includes?
|
430
692
|
std::vector<std::string> Context::get_included_files(bool skip, size_t headers)
|
431
693
|
{
|
432
|
-
// create a copy of the vector for
|
694
|
+
// create a copy of the vector for manipulations
|
433
695
|
std::vector<std::string> includes = included_files;
|
434
696
|
if (includes.size() == 0) return includes;
|
435
697
|
if (skip) { includes.erase( includes.begin(), includes.begin() + 1 + headers); }
|
@@ -439,11 +701,6 @@ namespace Sass {
|
|
439
701
|
return includes;
|
440
702
|
}
|
441
703
|
|
442
|
-
std::string Context::get_cwd()
|
443
|
-
{
|
444
|
-
return Sass::File::get_cwd();
|
445
|
-
}
|
446
|
-
|
447
704
|
void register_function(Context& ctx, Signature sig, Native_Function f, Env* env)
|
448
705
|
{
|
449
706
|
Definition* def = make_native_function(sig, f, ctx);
|