sassc 1.8.1 → 1.8.2
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 +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);
|