1 |
|
---|
2 | /*!
|
---|
3 | * Stylus - plugin - url
|
---|
4 | * Copyright (c) Automattic <developer.wordpress.com>
|
---|
5 | * MIT Licensed
|
---|
6 | */
|
---|
7 |
|
---|
8 | /**
|
---|
9 | * Module dependencies.
|
---|
10 | */
|
---|
11 |
|
---|
12 | var Compiler = require('../visitor/compiler')
|
---|
13 | , events = require('../renderer').events
|
---|
14 | , nodes = require('../nodes')
|
---|
15 | , parse = require('url').parse
|
---|
16 | , extname = require('path').extname
|
---|
17 | , utils = require('../utils')
|
---|
18 | , fs = require('fs');
|
---|
19 |
|
---|
20 | /**
|
---|
21 | * Mime table.
|
---|
22 | */
|
---|
23 |
|
---|
24 | var defaultMimes = {
|
---|
25 | '.gif': 'image/gif'
|
---|
26 | , '.png': 'image/png'
|
---|
27 | , '.jpg': 'image/jpeg'
|
---|
28 | , '.jpeg': 'image/jpeg'
|
---|
29 | , '.svg': 'image/svg+xml'
|
---|
30 | , '.webp': 'image/webp'
|
---|
31 | , '.ttf': 'application/x-font-ttf'
|
---|
32 | , '.eot': 'application/vnd.ms-fontobject'
|
---|
33 | , '.woff': 'application/font-woff'
|
---|
34 | , '.woff2': 'application/font-woff2'
|
---|
35 | };
|
---|
36 |
|
---|
37 | /**
|
---|
38 | * Supported encoding types
|
---|
39 | */
|
---|
40 | var encodingTypes = {
|
---|
41 | BASE_64: 'base64',
|
---|
42 | UTF8: 'charset=utf-8'
|
---|
43 | }
|
---|
44 |
|
---|
45 | /**
|
---|
46 | * Return a url() function with the given `options`.
|
---|
47 | *
|
---|
48 | * Options:
|
---|
49 | *
|
---|
50 | * - `limit` bytesize limit defaulting to 30Kb
|
---|
51 | * - `paths` image resolution path(s), merged with general lookup paths
|
---|
52 | *
|
---|
53 | * Examples:
|
---|
54 | *
|
---|
55 | * stylus(str)
|
---|
56 | * .set('filename', __dirname + '/css/test.styl')
|
---|
57 | * .define('url', stylus.url({ paths: [__dirname + '/public'] }))
|
---|
58 | * .render(function(err, css) { ... })
|
---|
59 | *
|
---|
60 | * @param {Object} options
|
---|
61 | * @return {Function}
|
---|
62 | * @api public
|
---|
63 | */
|
---|
64 |
|
---|
65 | module.exports = function(options) {
|
---|
66 | options = options || {};
|
---|
67 |
|
---|
68 | var _paths = options.paths || [];
|
---|
69 | var sizeLimit = null != options.limit ? options.limit : 30000;
|
---|
70 | var mimes = options.mimes || defaultMimes;
|
---|
71 |
|
---|
72 | /**
|
---|
73 | * @param {object} url - The path to the image you want to encode.
|
---|
74 | * @param {object} enc - The encoding for the image. Defaults to base64, the
|
---|
75 | * other valid option is `utf8`.
|
---|
76 | */
|
---|
77 | function fn(url, enc) {
|
---|
78 | // Compile the url
|
---|
79 | var compiler = new Compiler(url)
|
---|
80 | , encoding = encodingTypes.BASE_64;
|
---|
81 |
|
---|
82 | compiler.isURL = true;
|
---|
83 | url = url.nodes.map(function(node) {
|
---|
84 | return compiler.visit(node);
|
---|
85 | }).join('');
|
---|
86 |
|
---|
87 | // Parse literal
|
---|
88 | url = parse(url);
|
---|
89 | var ext = extname(url.pathname)
|
---|
90 | , mime = mimes[ext]
|
---|
91 | , hash = url.hash || ''
|
---|
92 | , literal = new nodes.Literal('url("' + url.href + '")')
|
---|
93 | , paths = _paths.concat(this.paths)
|
---|
94 | , buf
|
---|
95 | , result;
|
---|
96 |
|
---|
97 | // Not supported
|
---|
98 | if(!mime) return literal;
|
---|
99 |
|
---|
100 | // Absolute
|
---|
101 | if(url.protocol) return literal;
|
---|
102 |
|
---|
103 | // Lookup
|
---|
104 | var found = utils.lookup(url.pathname, paths);
|
---|
105 |
|
---|
106 | // Failed to lookup
|
---|
107 | if(!found) {
|
---|
108 | events.emit(
|
---|
109 | 'file not found'
|
---|
110 | , 'File ' + literal + ' could not be found, literal url retained!'
|
---|
111 | );
|
---|
112 |
|
---|
113 | return literal;
|
---|
114 | }
|
---|
115 |
|
---|
116 | // Read data
|
---|
117 | var str = fs.readFileSync(found, 'utf8');
|
---|
118 |
|
---|
119 | // Too large
|
---|
120 | if(false !== sizeLimit && str.length > sizeLimit) return literal;
|
---|
121 |
|
---|
122 | if(enc && 'utf8' == enc.first.val.toLowerCase()) {
|
---|
123 | encoding = encodingTypes.UTF8;
|
---|
124 | result = str.replace(/\s+/g, ' ')
|
---|
125 | .replace(/[{}\|\\\^~\[\]`"<>#%]/g, function(match) {
|
---|
126 | return '%' + match[0].charCodeAt(0).toString(16).toUpperCase();
|
---|
127 | }).trim();
|
---|
128 | } else {
|
---|
129 | result = Buffer.from(str.replace(/\r\n?/g, '\n')).toString(encoding) + hash;
|
---|
130 | }
|
---|
131 |
|
---|
132 | // Encode
|
---|
133 | return new nodes.Literal('url("data:' + mime + ';' + encoding + ',' + result + '")');
|
---|
134 | };
|
---|
135 |
|
---|
136 | fn.raw = true;
|
---|
137 | return fn;
|
---|
138 | };
|
---|
139 |
|
---|
140 | // Exporting default mimes so we could easily access them
|
---|
141 | module.exports.mimes = defaultMimes;
|
---|
142 |
|
---|