-
Notifications
You must be signed in to change notification settings - Fork 6
/
index.js
146 lines (120 loc) · 4.34 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
'use strict';
/**
* Dependencies
*/
var through = require('through2');
var signale = require('signale');
var fs = require('fs');
var path = require('path');
var cheerio = require('cheerio');
const PLUGIN_NAME = 'gulp-sass-inline-svg';
const URI_PREFIX = 'data:image/svg+xml, ';
module.exports = gulpSassInlineSvg;
/**
* Convert svg file into a sass function and write to a scss file
* @param {object} options plugin options
*/
function gulpSassInlineSvg(options) {
options = options || {};
options.destDir = options.destDir || "./scss";
// Create the output directory if it does not exist
if (!fs.existsSync(options.destDir)) {
fs.mkdirSync(options.destDir);
}
options.rootScss = path.join(options.destDir, "_sass-inline-svg.scss");
options.dataScss = path.join(options.destDir, "_sass-inline-svg-data.scss");
var writeStreamRoot = fs.createWriteStream(options.rootScss);
writeStreamRoot.write(fs.readFileSync(__dirname + "/_sass-inline-svg.scss", "utf8"));
writeStreamRoot.end();
var writeStream = fs.createWriteStream(options.dataScss);
var svgMap = "\n\n$svg-map: (";
function listStream(file, enc, cb) {
var dir = path.parse(file.path).dir.split(path.sep);
var folderName = dir.pop();
var fileName = path.parse(file.path).name;
svgMap += "'" + fileName + "': ('name': '" + fileName + "', 'folder': '" + folderName + "'),";
svgToInlineSvg(writeStream, cb, file.path, String(file.contents));
}
function endStream(cb) {
svgMap += ");";
writeStream.write(svgMap);
writeStream.end();
cb();
}
return through.obj(listStream, endStream);
}
/**
* Convert svg string to inline svg with sass variables
* @param {*} writeStream
* @param {*} cb
* @param {*} filePath
* @param {*} svgString
*/
function svgToInlineSvg(writeStream, cb, filePath, svgString) {
var inlineSvg = encodeSVG(addVariables(filePath, svgString));
var fileName = path.parse(filePath).name;
var uriString =
writeStream.write(
assembleDataString(fileName, inlineSvg)
);
cb();
}
/**
* Enocde the svg string as a URI based on recommended optimization of data uri
* strings for full cross browser support
* @see https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
* @param {string} svgString the html string of the inline svg
* @returns {string} the svg as a encoded uri string
*/
function encodeSVG(svgString) {
var uriPayload = svgString.replace(/\n+/g, ''); // remove newlines
uriPayload = encodeURIComponent(uriPayload); // encode URL-unsafe characters
uriPayload = uriPayload
.replace(/%20/g, ' ') // put spaces back in
.replace(/%3D/g, '=') // ditto equals signs
.replace(/%3A/g, ':') // ditto colons
.replace(/%2F/g, '/') // ditto slashes
.replace(/%22/g, "'"); // replace quotes with apostrophes (may break certain SVGs)
// Decode sass variables
var regex = /(%23%7B).*?(%7D)/gm; // (#{if).*?(})/gm; in URI
uriPayload = uriPayload.replace(regex, function(str) {
return decodeURIComponent(str);
});
return uriPayload;
}
/**
* Swaps fill and stroke attributes with a value of black of an svg file to sass
* variables so that we can change the color with sass.
* @param {String} filePath The file path
* @param {String} fileContent HTML/XML string
*/
function addVariables(filePath, fileContent) {
var $ = cheerio.load(fileContent, {
normalizeWhitespace: true,
xmlMode: true
});
if ($('svg').length !== 1) {
signale.fatal(new Error("File at '" + filePath + "' is not a valid svg file"));
}
// Allow fill values that are black to be set with sass variable.
var $fills = $('[fill]').not('[fill=none]');
if ($fills.length > 0) {
var $fillsToChange = $('[fill="#000"], [fill="#000000"], [fill="rgb(0,0,0)"]');
$fillsToChange.attr('fill', '#{$fillcolor}');
} else {
$('svg').attr('fill', '#{$fillcolor}');
}
// Allow stroke values that are black to be set with a sass variable
var $strokes = $('[stroke="#000"], [stroke="#000000"], [stroke="rgb(0,0,0)"]');
$strokes.attr('stroke', '#{$strokecolor}');
return $.html('svg'); //return only the svg
}
/**
* Create a sass function that will return the URI for the inline svg
* @param {string} fileName The name of the svg file
* @param {string} inlineSvg The encoded svg string
* @returns (string) The sass function as a string
*/
function assembleDataString(fileName, inlineSvg) {
return '@function ' + fileName + '($fillcolor, $strokecolor){ @return "' + URI_PREFIX + inlineSvg + '";}\n';
}