Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit 6aeec11

Browse files
committed
Add support for multiple importers
Call them in priority order so each one can decide if it wants to handle a certain url. Return `null` to skip an importer and to check the next one. Continue until one returns a valid import. Otherwise libsass will handle it.
1 parent 4b8c486 commit 6aeec11

File tree

13 files changed

+156
-93
lines changed

13 files changed

+156
-93
lines changed

context.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ namespace Sass {
5050
this->source = source;
5151
}
5252

53+
inline bool sort_importers (const Sass_C_Importer_Call& i, const Sass_C_Importer_Call& j)
54+
{ return sass_importer_get_priority(i) < sass_importer_get_priority(j); }
5355

5456
Context::Context(Context::Data initializers)
5557
: // Output(this),
@@ -61,7 +63,8 @@ namespace Sass {
6163
queue (vector<Sass_Queued>()),
6264
style_sheets (map<string, Block*>()),
6365
emitter (this),
64-
c_functions (vector<Sass_C_Function_Callback>()),
66+
c_functions (vector<Sass_C_Function_Call>()),
67+
c_importers (vector<Sass_C_Importer_Call>()),
6568
indent (initializers.indent()),
6669
linefeed (initializers.linefeed()),
6770
input_path (make_canonical_path(initializers.input_path())),
@@ -74,7 +77,6 @@ namespace Sass {
7477
source_map_contents (initializers.source_map_contents()),
7578
omit_source_map_url (initializers.omit_source_map_url()),
7679
is_indented_syntax_src (initializers.is_indented_syntax_src()),
77-
importer (initializers.importer()),
7880
names_to_colors (map<string, Color*>()),
7981
colors_to_names (map<int, string>()),
8082
precision (initializers.precision()),
@@ -104,7 +106,11 @@ namespace Sass {
104106
for(auto fn : plugins.get_functions()) {
105107
c_functions.push_back(fn);
106108
}
109+
for(auto fn : plugins.get_importers()) {
110+
c_importers.push_back(fn);
111+
}
107112

113+
sort (c_importers.begin(), c_importers.end(), sort_importers);
108114
string entry_point = initializers.entry_point();
109115
if (!entry_point.empty()) {
110116
string result(add_file(entry_point));
@@ -117,6 +123,17 @@ namespace Sass {
117123

118124
}
119125

126+
void Context::add_c_function(Sass_C_Function_Call function)
127+
{
128+
c_functions.push_back(function);
129+
}
130+
void Context::add_c_importer(Sass_C_Importer_Call importer)
131+
{
132+
c_importers.push_back(importer);
133+
// need to sort the array afterwards (no big deal)
134+
sort (c_importers.begin(), c_importers.end(), sort_importers);
135+
}
136+
120137
Context::~Context()
121138
{
122139
// everything that gets put into sources will be freed by us
@@ -263,7 +280,7 @@ namespace Sass {
263280
void register_overload_stub(Context&, string name, Env* env);
264281
void register_built_in_functions(Context&, Env* env);
265282
void register_c_functions(Context&, Env* env, Sass_C_Function_List);
266-
void register_c_function(Context&, Env* env, Sass_C_Function_Callback);
283+
void register_c_function(Context&, Env* env, Sass_C_Function_Call);
267284

268285
char* Context::compile_block(Block* root)
269286
{
@@ -515,7 +532,7 @@ namespace Sass {
515532
++descrs;
516533
}
517534
}
518-
void register_c_function(Context& ctx, Env* env, Sass_C_Function_Callback descr)
535+
void register_c_function(Context& ctx, Env* env, Sass_C_Function_Call descr)
519536
{
520537
Definition* def = make_c_function(
521538
sass_function_get_signature(descr),

context.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ namespace Sass {
5151
map<string, Block*> style_sheets; // map of paths to ASTs
5252
// SourceMap source_map;
5353
Output emitter;
54-
vector<Sass_C_Function_Callback> c_functions;
54+
55+
vector<Sass_C_Function_Call> c_functions;
56+
vector<Sass_C_Importer_Call> c_importers;
57+
58+
void add_c_function(Sass_C_Function_Call function);
59+
void add_c_importer(Sass_C_Importer_Call importer);
5560

5661
string indent; // String to be used for indentation
5762
string linefeed; // String to be used for line feeds
@@ -67,7 +72,6 @@ namespace Sass {
6772
bool is_indented_syntax_src; // treat source string as sass
6873

6974
// overload import calls
70-
Sass_C_Import_Callback importer;
7175
vector<struct Sass_Import*> import_stack;
7276

7377
map<string, Color*> names_to_colors;
@@ -97,7 +101,6 @@ namespace Sass {
97101
KWD_ARG(Data, size_t, precision);
98102
KWD_ARG(Data, bool, source_map_embed);
99103
KWD_ARG(Data, bool, source_map_contents);
100-
KWD_ARG(Data, Sass_C_Import_Callback, importer);
101104
};
102105

103106
Context(Data);

contrib/plugin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ extern "C" const char* ADDCALL libsass_get_version() {
1919
extern "C" Sass_C_Function_List ADDCALL libsass_load_functions()
2020
{
2121
// allocate a custom function caller
22-
Sass_C_Function_Callback fn_foo =
22+
Sass_C_Function_Call fn_foo =
2323
sass_make_function("foo()", call_fn_foo, (void*)42);
2424
// create list of all custom functions
2525
Sass_C_Function_List fn_list = sass_make_function_list(1);

file.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ namespace Sass {
5757
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
5858
(!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)));
5959
#else
60-
struct stat buffer;
61-
return (stat (path.c_str(), &buffer) == 0);
60+
struct stat st_buf;
61+
return (stat (path.c_str(), &st_buf) == 0) &&
62+
(!S_ISDIR (st_buf.st_mode));
6263
#endif
6364
}
6465

@@ -284,7 +285,7 @@ namespace Sass {
284285
{
285286
if (paths == 0) return string("");
286287
vector<string> includes(0);
287-
includes.push_back(".");
288+
// includes.push_back(".");
288289
const char** it = paths;
289290
while (it && *it) {
290291
includes.push_back(*it);

parser.cpp

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,20 @@ namespace Sass {
179179

180180
}
181181

182+
void Parser::import_single_file (Import* imp, string import_path) {
183+
184+
if (!unquote(import_path).substr(0, 7).compare("http://") ||
185+
!unquote(import_path).substr(0, 8).compare("https://") ||
186+
!unquote(import_path).substr(0, 2).compare("//"))
187+
{
188+
imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
189+
}
190+
else {
191+
add_single_file(imp, import_path);
192+
}
193+
194+
}
195+
182196
Import* Parser::parse_import()
183197
{
184198
lex< kwd_import >();
@@ -188,21 +202,18 @@ namespace Sass {
188202
while (lex< block_comment >());
189203
if (lex< quoted_string >()) {
190204
string import_path(lexed);
191-
192-
// struct Sass_Options opt = sass_context_get_options(ctx)
193-
Sass_C_Import_Callback importer = ctx.importer;
194-
// custom importer
195-
if (importer) {
196-
Sass_Import* current = ctx.import_stack.back();
197-
Sass_C_Import_Fn fn = sass_import_get_function(importer);
198-
void* cookie = sass_import_get_cookie(importer);
199-
// create a new import entry
200-
string inc_path = unquote(import_path);
201-
struct Sass_Import** includes = fn(
202-
inc_path.c_str(),
203-
sass_import_get_path(current),
204-
cookie);
205-
if (includes) {
205+
bool has_custom_import = false;
206+
Sass_Import* current = ctx.import_stack.back();
207+
const char* cur_path = sass_import_get_path(current);
208+
string load_path = unquote(import_path);
209+
for (auto importer : ctx.c_importers) {
210+
if (has_custom_import) break;
211+
Sass_C_Importer fn = sass_importer_get_function(importer);
212+
// int priority = sass_importer_get_priority(importer);
213+
void* cookie = sass_importer_get_cookie(importer);
214+
if (struct Sass_Import** includes =
215+
fn(load_path.c_str(), cur_path, cookie)
216+
) {
206217
struct Sass_Import** list = includes;
207218
while (*includes) {
208219
struct Sass_Import* include = *includes;
@@ -211,38 +222,32 @@ namespace Sass {
211222
size_t line = sass_import_get_error_line(include);
212223
size_t column = sass_import_get_error_column(include);
213224
const char* message = sass_import_get_error_message(include);
214-
// char *srcmap = sass_import_take_srcmap(include);
215225
if (message) {
216226
if (line == string::npos && column == string::npos) error(message, pstate);
217227
else error(message, ParserState(message, source, Position(line, column)));
218228
} else if (source) {
219229
if (file) {
220-
ctx.add_source(file, inc_path, source);
230+
ctx.add_source(file, load_path, source);
221231
imp->files().push_back(file);
222232
} else {
223-
ctx.add_source(inc_path, inc_path, source);
224-
imp->files().push_back(inc_path);
233+
ctx.add_source(load_path, load_path, source);
234+
imp->files().push_back(load_path);
225235
}
226236
} else if(file) {
227-
add_single_file(imp, file);
237+
import_single_file(imp, file);
228238
}
229239
++includes;
230240
}
231241
// deallocate returned memory
232242
sass_delete_import_list(list);
233-
// parse next import
234-
continue;
243+
// break import chain
244+
has_custom_import = true;
235245
}
236246
}
237247

238-
if (!unquote(import_path).substr(0, 7).compare("http://") ||
239-
!unquote(import_path).substr(0, 8).compare("https://") ||
240-
!unquote(import_path).substr(0, 2).compare("//"))
241-
{
242-
imp->urls().push_back(new (ctx.mem) String_Quoted(pstate, import_path));
243-
}
244-
else {
245-
add_single_file(imp, import_path);
248+
if (!has_custom_import) {
249+
// push single file import
250+
import_single_file(imp, import_path);
246251
}
247252

248253
}

parser.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace Sass {
2525
class Parser : public ParserState {
2626
private:
2727
void add_single_file (Import* imp, string import_path);
28+
void import_single_file (Import* imp, string import_path);
2829
public:
2930
class AST_Node;
3031

plugins.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace Sass {
4646

4747
typedef const char* (*__plugin_version__)(void);
4848
typedef Sass_C_Function_List (*__plugin_load_fns__)(void);
49+
typedef Sass_C_Importer_List (*__plugin_load_imps__)(void);
4950

5051
if (LOAD_LIB(plugin, path))
5152
{
@@ -60,6 +61,12 @@ namespace Sass {
6061
Sass_C_Function_List fns = plugin_load_functions();
6162
while (fns && *fns) { functions.push_back(*fns); ++ fns; }
6263
}
64+
// try to get import address for "libsass_load_importers"
65+
if (LOAD_LIB_FN(__plugin_load_imps__, plugin_load_importers, "libsass_load_importers"))
66+
{
67+
Sass_C_Importer_List imps = plugin_load_importers();
68+
while (imps && *imps) { importers.push_back(*imps); ++ imps; }
69+
}
6370
// success
6471
return true;
6572
}

plugins.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ namespace Sass {
4242
size_t load_plugins(const string& path);
4343

4444
public: // public accessors
45-
// const vector<Sass_C_Import_Callback> get_importers(void) { return importers; };
46-
const vector<Sass_C_Function_Callback> get_functions(void) { return functions; };
45+
const vector<Sass_C_Importer_Call> get_importers(void) { return importers; };
46+
const vector<Sass_C_Function_Call> get_functions(void) { return functions; };
4747

4848
private: // private vars
49-
// vector<Sass_C_Import_Callback> importers;
50-
vector<Sass_C_Function_Callback> functions;
49+
vector<Sass_C_Importer_Call> importers;
50+
vector<Sass_C_Function_Call> functions;
5151

5252
};
5353

sass_context.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ extern "C" {
102102
Sass_C_Function_List c_functions;
103103

104104
// Callback to overload imports
105-
Sass_C_Import_Callback importer;
105+
Sass_C_Importer_List c_importers;
106106

107107
};
108108

@@ -405,7 +405,6 @@ extern "C" {
405405
// .plugin_paths_array(plugin_paths)
406406
.include_paths(vector<string>())
407407
.plugin_paths(vector<string>())
408-
.importer(c_ctx->importer)
409408
.precision(c_ctx->precision ? c_ctx->precision : 5)
410409
.linefeed(c_ctx->linefeed ? c_ctx->linefeed : LFEED)
411410
.indent(c_ctx->indent ? c_ctx->indent : " ");
@@ -418,13 +417,22 @@ extern "C" {
418417

419418
// register our custom functions
420419
if (c_ctx->c_functions) {
421-
Sass_C_Function_List this_func_data = c_ctx->c_functions;
422-
while ((this_func_data) && (*this_func_data)) {
423-
cpp_ctx->c_functions.push_back((*this_func_data));
420+
auto this_func_data = c_ctx->c_functions;
421+
while (this_func_data && *this_func_data) {
422+
cpp_ctx->add_c_function(*this_func_data);
424423
++this_func_data;
425424
}
426425
}
427426

427+
// register our custom importers
428+
if (c_ctx->c_importers) {
429+
auto this_imp_data = c_ctx->c_importers;
430+
while (this_imp_data && *this_imp_data) {
431+
cpp_ctx->add_c_importer(*this_imp_data);
432+
++this_imp_data;
433+
}
434+
}
435+
428436
// reset error status
429437
c_ctx->error_json = 0;
430438
c_ctx->error_text = 0;
@@ -657,11 +665,19 @@ extern "C" {
657665
// Deallocate custom functions
658666
if (options->c_functions) {
659667
struct Sass_C_Function_Descriptor** this_func_data = options->c_functions;
660-
while ((this_func_data) && (*this_func_data)) {
661-
free((*this_func_data));
668+
while (this_func_data && *this_func_data) {
669+
free(*this_func_data);
662670
++this_func_data;
663671
}
664672
}
673+
// Deallocate custom importers
674+
if (options->c_importers) {
675+
struct Sass_C_Importer_Descriptor** this_imp_data = options->c_importers;
676+
while (this_imp_data && *this_imp_data) {
677+
free(*this_imp_data);
678+
++this_imp_data;
679+
}
680+
}
665681
// Deallocate inc paths
666682
if (options->plugin_paths) {
667683
struct string_list* cur;
@@ -686,13 +702,13 @@ extern "C" {
686702
cur = next;
687703
}
688704
}
689-
// Free custom importer
690-
free(options->importer);
691-
// Free the list container
705+
// Free custom functions
692706
free(options->c_functions);
693-
// Make it null terminated
694-
options->importer = 0;
707+
// Free custom importers
708+
free(options->c_importers);
709+
// Reset our pointers
695710
options->c_functions = 0;
711+
options->c_importers = 0;
696712
options->plugin_paths = 0;
697713
options->include_paths = 0;
698714
}
@@ -765,7 +781,7 @@ extern "C" {
765781
IMPLEMENT_SASS_OPTION_ACCESSOR(bool, omit_source_map_url);
766782
IMPLEMENT_SASS_OPTION_ACCESSOR(bool, is_indented_syntax_src);
767783
IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_C_Function_List, c_functions);
768-
IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_C_Import_Callback, importer);
784+
IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_C_Importer_List, c_importers);
769785
IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, indent);
770786
IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, linefeed);
771787
IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, input_path);

sass_context.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ ADDAPI const char* ADDCALL sass_option_get_include_path (struct Sass_Options* op
7575
ADDAPI const char* ADDCALL sass_option_get_source_map_file (struct Sass_Options* options);
7676
ADDAPI const char* ADDCALL sass_option_get_source_map_root (struct Sass_Options* options);
7777
ADDAPI Sass_C_Function_List ADDCALL sass_option_get_c_functions (struct Sass_Options* options);
78-
ADDAPI Sass_C_Import_Callback ADDCALL sass_option_get_importer (struct Sass_Options* options);
78+
ADDAPI Sass_C_Importer_List ADDCALL sass_option_get_c_importers (struct Sass_Options* options);
7979

8080
// Setters for Context_Option values
8181
ADDAPI void ADDCALL sass_option_set_precision (struct Sass_Options* options, int precision);
@@ -94,7 +94,7 @@ ADDAPI void ADDCALL sass_option_set_include_path (struct Sass_Options* options,
9494
ADDAPI void ADDCALL sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file);
9595
ADDAPI void ADDCALL sass_option_set_source_map_root (struct Sass_Options* options, const char* source_map_root);
9696
ADDAPI void ADDCALL sass_option_set_c_functions (struct Sass_Options* options, Sass_C_Function_List c_functions);
97-
ADDAPI void ADDCALL sass_option_set_importer (struct Sass_Options* options, Sass_C_Import_Callback importer);
97+
ADDAPI void ADDCALL sass_option_set_c_importers (struct Sass_Options* options, Sass_C_Importer_List c_importers);
9898

9999

100100
// Getters for Sass_Context values

0 commit comments

Comments
 (0)