sassc 1.10.1 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -2
  3. data/ext/libsass/.github/CONTRIBUTING.md +65 -0
  4. data/ext/libsass/.github/ISSUE_TEMPLATE.md +29 -0
  5. data/ext/libsass/Makefile +8 -3
  6. data/ext/libsass/Makefile.conf +28 -22
  7. data/ext/libsass/Readme.md +14 -7
  8. data/ext/libsass/configure.ac +5 -8
  9. data/ext/libsass/docs/api-context-internal.md +3 -0
  10. data/ext/libsass/docs/api-context.md +7 -0
  11. data/ext/libsass/docs/api-doc.md +4 -0
  12. data/ext/libsass/docs/api-importer.md +2 -0
  13. data/ext/libsass/docs/api-value-example.md +55 -0
  14. data/ext/libsass/docs/api-value.md +49 -22
  15. data/ext/libsass/docs/implementations.md +4 -0
  16. data/ext/libsass/include/sass/base.h +5 -4
  17. data/ext/libsass/include/sass/context.h +3 -0
  18. data/ext/libsass/include/sass/values.h +28 -27
  19. data/ext/libsass/include/sass/version.h +1 -1
  20. data/ext/libsass/include/sass2scss.h +1 -1
  21. data/ext/libsass/script/ci-build-libsass +3 -3
  22. data/ext/libsass/script/ci-install-deps +12 -3
  23. data/ext/libsass/src/ast.cpp +321 -212
  24. data/ext/libsass/src/ast.hpp +273 -165
  25. data/ext/libsass/src/ast_factory.hpp +4 -5
  26. data/ext/libsass/src/ast_fwd_decl.hpp +8 -7
  27. data/ext/libsass/src/bind.cpp +2 -7
  28. data/ext/libsass/src/bind.hpp +0 -1
  29. data/ext/libsass/src/check_nesting.cpp +379 -0
  30. data/ext/libsass/src/check_nesting.hpp +60 -0
  31. data/ext/libsass/src/constants.cpp +7 -6
  32. data/ext/libsass/src/constants.hpp +2 -1
  33. data/ext/libsass/src/context.cpp +7 -1
  34. data/ext/libsass/src/context.hpp +1 -1
  35. data/ext/libsass/src/cssize.cpp +76 -32
  36. data/ext/libsass/src/cssize.hpp +7 -8
  37. data/ext/libsass/src/debugger.hpp +70 -40
  38. data/ext/libsass/src/error_handling.cpp +15 -2
  39. data/ext/libsass/src/error_handling.hpp +19 -0
  40. data/ext/libsass/src/eval.cpp +107 -161
  41. data/ext/libsass/src/eval.hpp +12 -8
  42. data/ext/libsass/src/expand.cpp +81 -74
  43. data/ext/libsass/src/expand.hpp +13 -12
  44. data/ext/libsass/src/extend.cpp +149 -142
  45. data/ext/libsass/src/extend.hpp +10 -3
  46. data/ext/libsass/src/file.cpp +2 -1
  47. data/ext/libsass/src/functions.cpp +96 -59
  48. data/ext/libsass/src/functions.hpp +2 -2
  49. data/ext/libsass/src/inspect.cpp +33 -45
  50. data/ext/libsass/src/inspect.hpp +7 -7
  51. data/ext/libsass/src/json.cpp +17 -5
  52. data/ext/libsass/src/lexer.cpp +3 -3
  53. data/ext/libsass/src/listize.cpp +10 -10
  54. data/ext/libsass/src/listize.hpp +3 -3
  55. data/ext/libsass/src/node.cpp +30 -30
  56. data/ext/libsass/src/node.hpp +13 -13
  57. data/ext/libsass/src/operation.hpp +21 -19
  58. data/ext/libsass/src/output.cpp +48 -103
  59. data/ext/libsass/src/output.hpp +0 -1
  60. data/ext/libsass/src/parser.cpp +161 -133
  61. data/ext/libsass/src/parser.hpp +10 -7
  62. data/ext/libsass/src/remove_placeholders.cpp +6 -6
  63. data/ext/libsass/src/remove_placeholders.hpp +1 -1
  64. data/ext/libsass/src/sass.cpp +21 -0
  65. data/ext/libsass/src/sass.hpp +8 -1
  66. data/ext/libsass/src/sass2scss.cpp +14 -3
  67. data/ext/libsass/src/sass_context.cpp +69 -24
  68. data/ext/libsass/src/sass_context.hpp +3 -0
  69. data/ext/libsass/src/source_map.cpp +22 -10
  70. data/ext/libsass/src/to_value.cpp +2 -2
  71. data/ext/libsass/src/to_value.hpp +1 -1
  72. data/ext/libsass/src/units.hpp +3 -1
  73. data/ext/libsass/src/util.cpp +20 -16
  74. data/ext/libsass/src/util.hpp +2 -1
  75. data/ext/libsass/win/libsass.targets +2 -0
  76. data/ext/libsass/win/libsass.vcxproj.filters +6 -0
  77. data/lib/sassc/engine.rb +5 -0
  78. data/lib/sassc/native/native_functions_api.rb +13 -1
  79. data/lib/sassc/script/value_conversion.rb +11 -1
  80. data/lib/sassc/script/value_conversion/list.rb +23 -0
  81. data/lib/sassc/version.rb +1 -1
  82. data/test/engine_test.rb +18 -2
  83. data/test/functions_test.rb +30 -0
  84. data/test/native_test.rb +1 -1
  85. metadata +8 -3
@@ -51,7 +51,7 @@ namespace Sass {
51
51
  static Parser from_c_str(const char* beg, const char* end, Context& ctx, ParserState pstate = ParserState("[CSTRING]"), const char* source = 0);
52
52
  static Parser from_token(Token t, Context& ctx, ParserState pstate = ParserState("[TOKEN]"), const char* source = 0);
53
53
  // special static parsers to convert strings into certain selectors
54
- static Selector_List* parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"), const char* source = 0);
54
+ static CommaSequence_Selector* parse_selector(const char* src, Context& ctx, ParserState pstate = ParserState("[SELECTOR]"), const char* source = 0);
55
55
 
56
56
  #ifdef __clang__
57
57
 
@@ -66,6 +66,10 @@ namespace Sass {
66
66
  #endif
67
67
 
68
68
 
69
+ // skip current token and next whitespace
70
+ // moves ParserState right before next token
71
+ void advanceToNextToken();
72
+
69
73
  bool peek_newline(const char* start = 0);
70
74
 
71
75
  // skip over spaces, tabs and line comments
@@ -236,12 +240,11 @@ namespace Sass {
236
240
  Arguments* parse_arguments();
237
241
  Argument* parse_argument();
238
242
  Assignment* parse_assignment();
239
- // Propset* parse_propset();
240
243
  Ruleset* parse_ruleset(Lookahead lookahead, bool is_root = false);
241
244
  Selector_Schema* parse_selector_schema(const char* end_of_selector);
242
- Selector_List* parse_selector_list(bool at_root = false);
243
- Complex_Selector* parse_complex_selector(bool in_root = true);
244
- Compound_Selector* parse_compound_selector();
245
+ CommaSequence_Selector* parse_selector_list(bool at_root = false);
246
+ Sequence_Selector* parse_complex_selector(bool in_root = true);
247
+ SimpleSequence_Selector* parse_compound_selector();
245
248
  Simple_Selector* parse_simple_selector();
246
249
  Wrapped_Selector* parse_negated_selector();
247
250
  Simple_Selector* parse_pseudo_selector();
@@ -255,8 +258,8 @@ namespace Sass {
255
258
  Declaration* parse_declaration();
256
259
  Expression* parse_map_value();
257
260
  Expression* parse_map();
258
- Expression* parse_list();
259
- Expression* parse_comma_list();
261
+ Expression* parse_list(bool delayed = false);
262
+ Expression* parse_comma_list(bool delayed = false);
260
263
  Expression* parse_space_list();
261
264
  Expression* parse_disjunction();
262
265
  Expression* parse_conjunction();
@@ -16,9 +16,9 @@ namespace Sass {
16
16
  }
17
17
  }
18
18
 
19
- Selector_List* Remove_Placeholders::remove_placeholders(Selector_List* sl)
19
+ CommaSequence_Selector* Remove_Placeholders::remove_placeholders(CommaSequence_Selector* sl)
20
20
  {
21
- Selector_List* new_sl = SASS_MEMORY_NEW(ctx.mem, Selector_List, sl->pstate());
21
+ CommaSequence_Selector* new_sl = SASS_MEMORY_NEW(ctx.mem, CommaSequence_Selector, sl->pstate());
22
22
 
23
23
  for (size_t i = 0, L = sl->length(); i < L; ++i) {
24
24
  if (!(*sl)[i]->contains_placeholder()) {
@@ -33,19 +33,19 @@ namespace Sass {
33
33
 
34
34
  void Remove_Placeholders::operator()(Ruleset* r) {
35
35
  // Create a new selector group without placeholders
36
- Selector_List* sl = static_cast<Selector_List*>(r->selector());
36
+ CommaSequence_Selector* sl = static_cast<CommaSequence_Selector*>(r->selector());
37
37
 
38
38
  if (sl) {
39
39
  // Set the new placeholder selector list
40
40
  r->selector(remove_placeholders(sl));
41
41
  // Remove placeholders in wrapped selectors
42
- for (Complex_Selector* cs : *sl) {
42
+ for (Sequence_Selector* cs : *sl) {
43
43
  while (cs) {
44
44
  if (cs->head()) {
45
45
  for (Simple_Selector* ss : *cs->head()) {
46
46
  if (Wrapped_Selector* ws = dynamic_cast<Wrapped_Selector*>(ss)) {
47
- if (Selector_List* sl = dynamic_cast<Selector_List*>(ws->selector())) {
48
- Selector_List* clean = remove_placeholders(sl);
47
+ if (CommaSequence_Selector* sl = dynamic_cast<CommaSequence_Selector*>(ws->selector())) {
48
+ CommaSequence_Selector* clean = remove_placeholders(sl);
49
49
  // also clean superflous parent selectors
50
50
  // probably not really the correct place
51
51
  clean->remove_parent_selectors();
@@ -18,7 +18,7 @@ namespace Sass {
18
18
  void fallback_impl(AST_Node* n) {}
19
19
 
20
20
  public:
21
- Selector_List* remove_placeholders(Selector_List*);
21
+ CommaSequence_Selector* remove_placeholders(CommaSequence_Selector*);
22
22
 
23
23
  public:
24
24
  Remove_Placeholders(Context&);
@@ -70,3 +70,24 @@ extern "C" {
70
70
  }
71
71
 
72
72
  }
73
+
74
+ namespace Sass {
75
+
76
+ // helper to aid dreaded MSVC debug mode
77
+ char* sass_copy_string(std::string str)
78
+ {
79
+ // In MSVC the following can lead to segfault:
80
+ // sass_copy_c_string(stream.str().c_str());
81
+ // Reason is that the string returned by str() is disposed before
82
+ // sass_copy_c_string is invoked. The string is actually a stack
83
+ // object, so indeed nobody is holding on to it. So it seems
84
+ // perfectly fair to release it right away. So the const char*
85
+ // by c_str will point to invalid memory. I'm not sure if this is
86
+ // the behavior for all compiler, but I'm pretty sure we would
87
+ // have gotten more issues reported if that would be the case.
88
+ // Wrapping it in a functions seems the cleanest approach as the
89
+ // function must hold on to the stack variable until it's done.
90
+ return sass_copy_c_string(str.c_str());
91
+ }
92
+
93
+ }
@@ -45,6 +45,9 @@
45
45
  // include C-API header
46
46
  #include "sass/base.h"
47
47
 
48
+ // For C++ helper
49
+ #include <string>
50
+
48
51
  // output behaviours
49
52
  namespace Sass {
50
53
 
@@ -57,7 +60,11 @@ namespace Sass {
57
60
  const static Sass_Output_Style INSPECT = SASS_STYLE_INSPECT;
58
61
  const static Sass_Output_Style TO_SASS = SASS_STYLE_TO_SASS;
59
62
 
60
- };
63
+ // helper to aid dreaded MSVC debug mode
64
+ // see implementation for more details
65
+ char* sass_copy_string(std::string str);
66
+
67
+ }
61
68
 
62
69
  // input behaviours
63
70
  enum Sass_Input_Style {
@@ -574,6 +574,12 @@ namespace Sass
574
574
  }
575
575
  }
576
576
 
577
+ // check if we have a BEM property (one colon and no selector)
578
+ if (sass.substr(pos_left, 1) == ":" && converter.selector == true) {
579
+ size_t pos_wspace = sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left);
580
+ sass = indent + sass.substr(pos_left + 1, pos_wspace) + ":";
581
+ }
582
+
577
583
  }
578
584
 
579
585
  // terminate some statements immediately
@@ -584,10 +590,15 @@ namespace Sass
584
590
  sass.substr(pos_left, 8) == "@charset"
585
591
  ) { sass = indent + sass.substr(pos_left); }
586
592
  // replace some specific sass shorthand directives (if not fallowed by a white space character)
587
- else if (sass.substr(pos_left, 1) == "=" && sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left) != pos_left + 1)
593
+ else if (sass.substr(pos_left, 1) == "=")
588
594
  { sass = indent + "@mixin " + sass.substr(pos_left + 1); }
589
- else if (sass.substr(pos_left, 1) == "+" && sass.find_first_of(SASS2SCSS_FIND_WHITESPACE, pos_left) != pos_left + 1)
590
- { sass = indent + "@include " + sass.substr(pos_left + 1); }
595
+ else if (sass.substr(pos_left, 1) == "+")
596
+ {
597
+ // must be followed by a mixin call (no whitespace afterwards or at ending directly)
598
+ if (sass[pos_left+1] != 0 && sass[pos_left+1] != ' ' && sass[pos_left+1] != '\t') {
599
+ sass = indent + "@include " + sass.substr(pos_left + 1);
600
+ }
601
+ }
591
602
 
592
603
  // add quotes for import if needed
593
604
  else if (sass.substr(pos_left, 7) == "@import")
@@ -17,10 +17,30 @@
17
17
 
18
18
  #define LFEED "\n"
19
19
 
20
+ // C++ helper
21
+ namespace Sass {
22
+ // see sass_copy_c_string(std::string str)
23
+ static inline JsonNode* json_mkstream(const std::stringstream& stream)
24
+ {
25
+ // hold on to string on stack!
26
+ std::string str(stream.str());
27
+ return json_mkstring(str.c_str());
28
+ }
29
+ }
30
+
20
31
  extern "C" {
21
32
  using namespace Sass;
22
33
 
23
- static void copy_options(struct Sass_Options* to, struct Sass_Options* from) { *to = *from; }
34
+ static void sass_clear_options (struct Sass_Options* options);
35
+ static void sass_reset_options (struct Sass_Options* options);
36
+ static void copy_options(struct Sass_Options* to, struct Sass_Options* from) {
37
+ // free assigned memory
38
+ sass_clear_options(to);
39
+ // move memory
40
+ *to = *from;
41
+ // Reset pointers on source
42
+ sass_reset_options(from);
43
+ }
24
44
 
25
45
  #define IMPLEMENT_SASS_OPTION_ACCESSOR(type, option) \
26
46
  type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return options->option; } \
@@ -103,10 +123,9 @@ extern "C" {
103
123
  json_append_member(json_err, "line", json_mknumber((double)(e.pstate.line+1)));
104
124
  json_append_member(json_err, "column", json_mknumber((double)(e.pstate.column+1)));
105
125
  json_append_member(json_err, "message", json_mkstring(e.what()));
106
- json_append_member(json_err, "formatted", json_mkstring(msg_stream.str().c_str()));
107
-
126
+ json_append_member(json_err, "formatted", json_mkstream(msg_stream));
108
127
  try { c_ctx->error_json = json_stringify(json_err, " "); } catch(...) {}
109
- c_ctx->error_message = sass_copy_c_string(msg_stream.str().c_str());
128
+ c_ctx->error_message = sass_copy_string(msg_stream.str());
110
129
  c_ctx->error_text = sass_copy_c_string(e.what());
111
130
  c_ctx->error_status = 1;
112
131
  c_ctx->error_file = sass_copy_c_string(e.pstate.path);
@@ -123,9 +142,9 @@ extern "C" {
123
142
  msg_stream << "Unable to allocate memory: " << ba.what() << std::endl;
124
143
  json_append_member(json_err, "status", json_mknumber(2));
125
144
  json_append_member(json_err, "message", json_mkstring(ba.what()));
126
- json_append_member(json_err, "formatted", json_mkstring(msg_stream.str().c_str()));
145
+ json_append_member(json_err, "formatted", json_mkstream(msg_stream));
127
146
  try { c_ctx->error_json = json_stringify(json_err, " "); } catch(...) {}
128
- c_ctx->error_message = sass_copy_c_string(msg_stream.str().c_str());
147
+ c_ctx->error_message = sass_copy_string(msg_stream.str());
129
148
  c_ctx->error_text = sass_copy_c_string(ba.what());
130
149
  c_ctx->error_status = 2;
131
150
  c_ctx->output_string = 0;
@@ -138,9 +157,9 @@ extern "C" {
138
157
  msg_stream << "Internal Error: " << e.what() << std::endl;
139
158
  json_append_member(json_err, "status", json_mknumber(3));
140
159
  json_append_member(json_err, "message", json_mkstring(e.what()));
141
- json_append_member(json_err, "formatted", json_mkstring(msg_stream.str().c_str()));
160
+ json_append_member(json_err, "formatted", json_mkstream(msg_stream));
142
161
  try { c_ctx->error_json = json_stringify(json_err, " "); } catch(...) {}
143
- c_ctx->error_message = sass_copy_c_string(msg_stream.str().c_str());
162
+ c_ctx->error_message = sass_copy_string(msg_stream.str());
144
163
  c_ctx->error_text = sass_copy_c_string(e.what());
145
164
  c_ctx->error_status = 3;
146
165
  c_ctx->output_string = 0;
@@ -153,9 +172,9 @@ extern "C" {
153
172
  msg_stream << "Internal Error: " << e << std::endl;
154
173
  json_append_member(json_err, "status", json_mknumber(4));
155
174
  json_append_member(json_err, "message", json_mkstring(e.c_str()));
156
- json_append_member(json_err, "formatted", json_mkstring(msg_stream.str().c_str()));
175
+ json_append_member(json_err, "formatted", json_mkstream(msg_stream));
157
176
  try { c_ctx->error_json = json_stringify(json_err, " "); } catch(...) {}
158
- c_ctx->error_message = sass_copy_c_string(msg_stream.str().c_str());
177
+ c_ctx->error_message = sass_copy_string(msg_stream.str());
159
178
  c_ctx->error_text = sass_copy_c_string(e.c_str());
160
179
  c_ctx->error_status = 4;
161
180
  c_ctx->output_string = 0;
@@ -168,9 +187,9 @@ extern "C" {
168
187
  msg_stream << "Internal Error: " << e << std::endl;
169
188
  json_append_member(json_err, "status", json_mknumber(4));
170
189
  json_append_member(json_err, "message", json_mkstring(e));
171
- json_append_member(json_err, "formatted", json_mkstring(msg_stream.str().c_str()));
190
+ json_append_member(json_err, "formatted", json_mkstream(msg_stream));
172
191
  try { c_ctx->error_json = json_stringify(json_err, " "); } catch(...) {}
173
- c_ctx->error_message = sass_copy_c_string(msg_stream.str().c_str());
192
+ c_ctx->error_message = sass_copy_string(msg_stream.str());
174
193
  c_ctx->error_text = sass_copy_c_string(e);
175
194
  c_ctx->error_status = 4;
176
195
  c_ctx->output_string = 0;
@@ -184,7 +203,7 @@ extern "C" {
184
203
  json_append_member(json_err, "status", json_mknumber(5));
185
204
  json_append_member(json_err, "message", json_mkstring("unknown"));
186
205
  try { c_ctx->error_json = json_stringify(json_err, " "); } catch(...) {}
187
- c_ctx->error_message = sass_copy_c_string(msg_stream.str().c_str());
206
+ c_ctx->error_message = sass_copy_string(msg_stream.str());
188
207
  c_ctx->error_text = sass_copy_c_string("unknown");
189
208
  c_ctx->error_status = 5;
190
209
  c_ctx->output_string = 0;
@@ -465,6 +484,24 @@ extern "C" {
465
484
  return 0;
466
485
  }
467
486
 
487
+ // helper function, not exported, only accessible locally
488
+ static void sass_reset_options (struct Sass_Options* options)
489
+ {
490
+ // free pointer before
491
+ // or copy/move them
492
+ options->input_path = 0;
493
+ options->output_path = 0;
494
+ options->plugin_path = 0;
495
+ options->include_path = 0;
496
+ options->source_map_file = 0;
497
+ options->source_map_root = 0;
498
+ options->c_functions = 0;
499
+ options->c_importers = 0;
500
+ options->c_headers = 0;
501
+ options->plugin_paths = 0;
502
+ options->include_paths = 0;
503
+ }
504
+
468
505
  // helper function, not exported, only accessible locally
469
506
  static void sass_clear_options (struct Sass_Options* options)
470
507
  {
@@ -517,12 +554,25 @@ extern "C" {
517
554
  cur = next;
518
555
  }
519
556
  }
557
+ // Free options strings
558
+ free(options->input_path);
559
+ free(options->output_path);
560
+ free(options->plugin_path);
561
+ free(options->include_path);
562
+ free(options->source_map_file);
563
+ free(options->source_map_root);
520
564
  // Free custom functions
521
565
  free(options->c_functions);
522
566
  // Free custom importers
523
567
  free(options->c_importers);
524
568
  free(options->c_headers);
525
569
  // Reset our pointers
570
+ options->input_path = 0;
571
+ options->output_path = 0;
572
+ options->plugin_path = 0;
573
+ options->include_path = 0;
574
+ options->source_map_file = 0;
575
+ options->source_map_root = 0;
526
576
  options->c_functions = 0;
527
577
  options->c_importers = 0;
528
578
  options->c_headers = 0;
@@ -542,12 +592,6 @@ extern "C" {
542
592
  if (ctx->error_text) free(ctx->error_text);
543
593
  if (ctx->error_json) free(ctx->error_json);
544
594
  if (ctx->error_file) free(ctx->error_file);
545
- if (ctx->input_path) free(ctx->input_path);
546
- if (ctx->output_path) free(ctx->output_path);
547
- if (ctx->plugin_path) free(ctx->plugin_path);
548
- if (ctx->include_path) free(ctx->include_path);
549
- if (ctx->source_map_file) free(ctx->source_map_file);
550
- if (ctx->source_map_root) free(ctx->source_map_root);
551
595
  free_string_array(ctx->included_files);
552
596
  // play safe and reset properties
553
597
  ctx->output_string = 0;
@@ -556,11 +600,6 @@ extern "C" {
556
600
  ctx->error_text = 0;
557
601
  ctx->error_json = 0;
558
602
  ctx->error_file = 0;
559
- ctx->input_path = 0;
560
- ctx->output_path = 0;
561
- ctx->include_path = 0;
562
- ctx->source_map_file = 0;
563
- ctx->source_map_root = 0;
564
603
  ctx->included_files = 0;
565
604
  // now clear the options
566
605
  sass_clear_options(ctx);
@@ -577,6 +616,11 @@ extern "C" {
577
616
  free(compiler);
578
617
  }
579
618
 
619
+ void ADDCALL sass_delete_options (struct Sass_Options* options)
620
+ {
621
+ sass_clear_options(options); free(options);
622
+ }
623
+
580
624
  // Deallocate all associated memory with file context
581
625
  void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx)
582
626
  {
@@ -623,6 +667,7 @@ extern "C" {
623
667
  IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_comments);
624
668
  IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_embed);
625
669
  IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_contents);
670
+ IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_file_urls);
626
671
  IMPLEMENT_SASS_OPTION_ACCESSOR(bool, omit_source_map_url);
627
672
  IMPLEMENT_SASS_OPTION_ACCESSOR(bool, is_indented_syntax_src);
628
673
  IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Function_List, c_functions);
@@ -15,6 +15,9 @@ struct Sass_Options : Sass_Output_Options {
15
15
  // embed include contents in maps
16
16
  bool source_map_contents;
17
17
 
18
+ // create file urls for sources
19
+ bool source_map_file_urls;
20
+
18
21
  // Disable sourceMappingUrl in css output
19
22
  bool omit_source_map_url;
20
23
 
@@ -25,20 +25,32 @@ namespace Sass {
25
25
 
26
26
  json_append_member(json_srcmap, "version", json_mknumber(3));
27
27
 
28
+ const char *include = file.c_str();
29
+ JsonNode *json_include = json_mkstring(include);
30
+ json_append_member(json_srcmap, "file", json_include);
31
+
28
32
  // pass-through sourceRoot option
29
33
  if (!ctx.source_map_root.empty()) {
30
34
  JsonNode* root = json_mkstring(ctx.source_map_root.c_str());
31
35
  json_append_member(json_srcmap, "sourceRoot", root);
32
36
  }
33
37
 
34
- const char *include = file.c_str();
35
- JsonNode *json_include = json_mkstring(include);
36
- json_append_member(json_srcmap, "file", json_include);
37
-
38
38
  JsonNode *json_includes = json_mkarray();
39
39
  for (size_t i = 0; i < source_index.size(); ++i) {
40
- const char *include = links[source_index[i]].c_str();
41
- JsonNode *json_include = json_mkstring(include);
40
+ std::string include(links[source_index[i]]);
41
+ if (ctx.c_options.source_map_file_urls) {
42
+ include = File::rel2abs(include);
43
+ // check for windows abs path
44
+ if (include[0] == '/') {
45
+ // ends up with three slashes
46
+ include = "file://" + include;
47
+ } else {
48
+ // needs an additional slash
49
+ include = "file:///" + include;
50
+ }
51
+ }
52
+ const char* inc = include.c_str();
53
+ JsonNode *json_include = json_mkstring(inc);
42
54
  json_append_element(json_includes, json_include);
43
55
  }
44
56
  json_append_member(json_srcmap, "sources", json_includes);
@@ -54,15 +66,15 @@ namespace Sass {
54
66
  json_append_member(json_srcmap, "sourcesContent", json_contents);
55
67
  }
56
68
 
57
- std::string mappings = serialize_mappings();
58
- JsonNode *json_mappings = json_mkstring(mappings.c_str());
59
- json_append_member(json_srcmap, "mappings", json_mappings);
60
-
61
69
  JsonNode *json_names = json_mkarray();
62
70
  // so far we have no implementation for names
63
71
  // no problem as we do not alter any identifiers
64
72
  json_append_member(json_srcmap, "names", json_names);
65
73
 
74
+ std::string mappings = serialize_mappings();
75
+ JsonNode *json_mappings = json_mkstring(mappings.c_str());
76
+ json_append_member(json_srcmap, "mappings", json_mappings);
77
+
66
78
  char *str = json_stringify(json_srcmap, "\t");
67
79
  std::string result = std::string(str);
68
80
  free(str);
@@ -88,8 +88,8 @@ namespace Sass {
88
88
  return arg->value()->perform(this);
89
89
  }
90
90
 
91
- // Selector_List is converted to a string
92
- Value* To_Value::operator()(Selector_List* s)
91
+ // CommaSequence_Selector is converted to a string
92
+ Value* To_Value::operator()(CommaSequence_Selector* s)
93
93
  {
94
94
  return SASS_MEMORY_NEW(mem, String_Quoted,
95
95
  s->pstate(),
@@ -37,7 +37,7 @@ namespace Sass {
37
37
  Value* operator()(Null*);
38
38
 
39
39
  // convert to string via `To_String`
40
- Value* operator()(Selector_List*);
40
+ Value* operator()(CommaSequence_Selector*);
41
41
  Value* operator()(Binary_Expression*);
42
42
 
43
43
  // fallback throws error