Skip to content

Commit 6c7fcd2

Browse files
committed
Implements source map embedding
- embed sources content inside source map - embed source map inside sourceMappingURL
1 parent 9f16e7f commit 6c7fcd2

File tree

8 files changed

+89
-43
lines changed

8 files changed

+89
-43
lines changed

context.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ namespace Sass {
5858
source_comments (initializers.source_comments()),
5959
output_style (initializers.output_style()),
6060
source_map_file (make_canonical_path(initializers.source_map_file())),
61+
source_map_embed (initializers.source_map_embed()),
62+
source_map_contents (initializers.source_map_contents()),
6163
omit_source_map_url (initializers.omit_source_map_url()),
6264
is_indented_syntax_src (initializers.is_indented_syntax_src()),
6365
names_to_colors (map<string, Color*>()),
@@ -153,7 +155,8 @@ namespace Sass {
153155
sources.push_back(contents);
154156
included_files.push_back(abs_path);
155157
queue.push_back(make_pair(load_path, contents));
156-
source_map.files.push_back(resolve_relative_path(abs_path, source_map_file, cwd));
158+
source_map.source_index.push_back(sources.size() - 1);
159+
include_links.push_back(resolve_relative_path(abs_path, source_map_file, cwd));
157160
}
158161

159162
string Context::add_file(string path)
@@ -268,14 +271,23 @@ namespace Sass {
268271

269272
string Context::format_source_mapping_url(const string& file) const
270273
{
271-
return "/*# sourceMappingURL=" + resolve_relative_path(file, output_path, cwd) + " */";
274+
string url = resolve_relative_path(file, output_path, cwd);
275+
if (source_map_embed) {
276+
base64::encoder E;
277+
istringstream is( sources[0] );
278+
ostringstream buffer;
279+
E.encode(is, buffer);
280+
url = "data:text/css;base64," + buffer.str();
281+
url.erase(url.size() - 1);
282+
}
283+
return "/*# sourceMappingURL=" + url + " */";
272284
}
273285

274286
char* Context::generate_source_map()
275287
{
276288
if (source_map_file == "") return 0;
277289
char* result = 0;
278-
string map = source_map.generate_source_map();
290+
string map = source_map.generate_source_map(*this);
279291
result = copy_c_str(map.c_str());
280292
return result;
281293
}

context.hpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#include "subset_map.hpp"
2222
#endif
2323

24+
#define BUFFERSIZE 255
25+
#include "b64/encode.h"
26+
2427
struct Sass_C_Function_Descriptor;
2528

2629
namespace Sass {
@@ -41,8 +44,17 @@ namespace Sass {
4144
Memory_Manager<AST_Node> mem;
4245

4346
const char* source_c_str;
44-
vector<const char*> sources; // c-strs containing Sass file contents
45-
vector<string> include_paths;
47+
48+
// c-strs containing Sass file contents
49+
// we will overtake ownership of memory
50+
vector<const char*> sources;
51+
// absolute paths to includes
52+
vector<string> included_files;
53+
// relative links to includes
54+
vector<string> include_links;
55+
// vectors above have same size
56+
57+
vector<string> include_paths; // lookup paths for includes
4658
vector<pair<string, const char*> > queue; // queue of files to be parsed
4759
map<string, Block*> style_sheets; // map of paths to ASTs
4860
SourceMap source_map;
@@ -53,6 +65,8 @@ namespace Sass {
5365
bool source_comments; // for inline debug comments in css output
5466
Output_Style output_style; // output style for the generated css code
5567
string source_map_file; // path to source map file (enables feature)
68+
bool source_map_embed; // embed in sourceMappingUrl (as data-url)
69+
bool source_map_contents; // insert included contents into source map
5670
bool omit_source_map_url; // disable source map comment in css output
5771
bool is_indented_syntax_src; // treat source string as sass
5872

@@ -77,6 +91,8 @@ namespace Sass {
7791
KWD_ARG(Data, bool, is_indented_syntax_src);
7892
KWD_ARG(Data, size_t, precision);
7993
KWD_ARG(Data, bool, _skip_source_map_update);
94+
KWD_ARG(Data, bool, source_map_embed);
95+
KWD_ARG(Data, bool, source_map_contents);
8096
};
8197

8298
Context(Data);
@@ -93,14 +109,13 @@ namespace Sass {
93109
char* compile_file();
94110
char* generate_source_map();
95111

96-
std::vector<string> get_included_files();
112+
vector<string> get_included_files();
97113

98114
private:
99115
void add_source(const string &load_path, const string &abs_path, const char* contents);
100116
string format_source_mapping_url(const string& file) const;
101117
string get_cwd();
102118

103-
vector<string> included_files;
104119
string cwd;
105120

106121
// void register_built_in_functions(Env* env);

sass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ extern "C" {
4646

4747
.source_comments (c_ctx->source_comments)
4848
.source_map_file (c_ctx->source_map_file)
49+
.source_map_embed (c_ctx->source_map_embed)
50+
.source_map_contents (c_ctx->source_map_contents)
4951
.omit_source_map_url (c_ctx->omit_source_map_url)
5052

5153
.image_path (c_ctx->image_path ?

sass.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ struct Sass_Context {
2323

2424
int output_style;
2525
bool source_comments;
26-
const char* source_map_file;
26+
bool source_map_embed;
27+
bool source_map_contents;
2728
bool omit_source_map_url;
29+
const char* source_map_file;
2830
const char* image_path;
2931
const char* output_path;
3032
const char* include_paths_string;

sass_interface.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ extern "C" {
199199
.output_style((Output_Style) c_ctx->options.output_style)
200200
.source_comments(c_ctx->options.source_comments)
201201
.source_map_file(safe_str(c_ctx->options.source_map_file))
202+
.source_map_embed(c_ctx->options.source_map_embed)
203+
.source_map_contents(c_ctx->options.source_map_contents)
202204
.omit_source_map_url(c_ctx->options.omit_source_map_url)
203205
.image_path(safe_str(c_ctx->options.image_path))
204206
.include_paths_c_str(c_ctx->options.include_paths)

sass_interface.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ struct sass_options {
2727
const char* source_map_file;
2828
// Disable sourceMappingUrl in css output
2929
bool omit_source_map_url;
30+
// embed sourceMappingUrl as data uri
31+
bool source_map_embed;
32+
// embed include contents in maps
33+
bool source_map_contents;
3034
// Treat source_string as sass (as opposed to scss)
3135
bool is_indented_syntax_src;
3236
// Colon-separated list of paths

source_map.cpp

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "source_map.hpp"
2+
#include "json.hpp"
23

34
#ifndef SASS_CONTEXT
45
#include "context.hpp"
@@ -13,45 +14,54 @@ namespace Sass {
1314
using std::ptrdiff_t;
1415
SourceMap::SourceMap(const string& file) : current_position(Position(1, 1)), file(file) { }
1516

16-
// taken from http://stackoverflow.com/a/7725289/1550314
17-
std::string encodeJsonString(const std::string& input) {
18-
std::ostringstream ss;
19-
for (std::string::const_iterator iter = input.begin(); iter != input.end(); iter++) {
20-
switch (*iter) {
21-
case '\\': ss << "\\\\"; break;
22-
case '"': ss << "\\\""; break;
23-
case '\b': ss << "\\b"; break;
24-
case '\f': ss << "\\f"; break;
25-
case '\n': ss << "\\n"; break;
26-
case '\r': ss << "\\r"; break;
27-
case '\t': ss << "\\t"; break;
28-
// is a legal escape in JSON
29-
case '/': ss << "\\/"; break;
30-
default: ss << *iter; break;
31-
}
32-
}
17+
string SourceMap::generate_source_map(Context &ctx) {
3318

34-
return ss.str();
35-
}
19+
const bool include_sources = ctx.source_map_contents;
20+
const vector<string> includes = ctx.include_links;
21+
const vector<const char*> sources = ctx.sources;
22+
23+
JsonNode *json_srcmap = json_mkobject();
24+
25+
json_append_member(json_srcmap, "version", json_mknumber(3));
26+
27+
const char *include = file.c_str();
28+
JsonNode *json_include = json_mkstring(include);
29+
json_append_member(json_srcmap, "file", json_include);
3630

37-
string SourceMap::generate_source_map() {
38-
string result = "{\n";
39-
result += " \"version\": 3,\n";
40-
result += " \"file\": \"" + encodeJsonString(file) + "\",\n";
41-
result += " \"sources\": [";
42-
for (size_t i = 0; i < files.size(); ++i) {
43-
result+="\"" + encodeJsonString(files[i]) + "\",";
31+
JsonNode *json_includes = json_mkarray();
32+
for (size_t i = 0; i < source_index.size(); ++i) {
33+
const char *include = includes[source_index[i]].c_str();
34+
JsonNode *json_include = json_mkstring(include);
35+
json_append_element(json_includes, json_include);
4436
}
45-
if (!files.empty()) result.erase(result.length() - 1);
46-
result += "],\n";
47-
result += " \"names\": [],\n";
48-
result += " \"mappings\": \"" + serialize_mappings() + "\"\n";
49-
result += "}";
37+
json_append_member(json_srcmap, "sources", json_includes);
38+
39+
JsonNode *json_contents = json_mkarray();
40+
if (include_sources) {
41+
for (size_t i = 1; i < source_index.size(); ++i) {
42+
const char *content = sources[source_index[i]];
43+
JsonNode *json_content = json_mkstring(content);
44+
json_append_element(json_contents, json_content);
45+
}
46+
}
47+
json_append_member(json_srcmap, "sourcesContent", json_contents);
48+
49+
string mappings = serialize_mappings();
50+
JsonNode *json_mappings = json_mkstring(mappings.c_str());
51+
json_append_member(json_srcmap, "mappings", json_mappings);
5052

53+
JsonNode *json_names = json_mkarray();
54+
// so far we have no implementation for names
55+
// no problem as we do not alter any identifiers
56+
json_append_member(json_srcmap, "names", json_names);
57+
58+
char *str = json_stringify(json_srcmap, "\t");
59+
string result = string(str);
60+
free(str);
61+
json_delete(json_srcmap);
5162
return result;
5263
}
5364

54-
5565
string SourceMap::serialize_mappings() {
5666
string result = "";
5767

source_map.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,14 @@ namespace Sass {
2424
class SourceMap {
2525

2626
public:
27-
vector<string> files;
28-
27+
vector<size_t> source_index;
2928
SourceMap(const string& file);
3029

3130
void remove_line();
3231
void update_column(const string& str);
3332
void add_mapping(AST_Node* node);
3433

35-
string generate_source_map();
34+
string generate_source_map(Context &ctx);
3635

3736
private:
3837

0 commit comments

Comments
 (0)