source: imaps-frontend/node_modules/clean-css/lib/reader/apply-source-maps.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 7.8 KB
Line 
1var fs = require('fs');
2var path = require('path');
3
4var isAllowedResource = require('./is-allowed-resource');
5var matchDataUri = require('./match-data-uri');
6var rebaseLocalMap = require('./rebase-local-map');
7var rebaseRemoteMap = require('./rebase-remote-map');
8
9var Token = require('../tokenizer/token');
10var hasProtocol = require('../utils/has-protocol');
11var isDataUriResource = require('../utils/is-data-uri-resource');
12var isRemoteResource = require('../utils/is-remote-resource');
13
14var MAP_MARKER_PATTERN = /^\/\*# sourceMappingURL=(\S+) \*\/$/;
15
16function applySourceMaps(tokens, context, callback) {
17 var applyContext = {
18 callback: callback,
19 fetch: context.options.fetch,
20 index: 0,
21 inline: context.options.inline,
22 inlineRequest: context.options.inlineRequest,
23 inlineTimeout: context.options.inlineTimeout,
24 inputSourceMapTracker: context.inputSourceMapTracker,
25 localOnly: context.localOnly,
26 processedTokens: [],
27 rebaseTo: context.options.rebaseTo,
28 sourceTokens: tokens,
29 warnings: context.warnings
30 };
31
32 return context.options.sourceMap && tokens.length > 0
33 ? doApplySourceMaps(applyContext)
34 : callback(tokens);
35}
36
37function doApplySourceMaps(applyContext) {
38 var singleSourceTokens = [];
39 var lastSource = findTokenSource(applyContext.sourceTokens[0]);
40 var source;
41 var token;
42 var l;
43
44 for (l = applyContext.sourceTokens.length; applyContext.index < l; applyContext.index++) {
45 token = applyContext.sourceTokens[applyContext.index];
46 source = findTokenSource(token);
47
48 if (source != lastSource) {
49 singleSourceTokens = [];
50 lastSource = source;
51 }
52
53 singleSourceTokens.push(token);
54 applyContext.processedTokens.push(token);
55
56 if (token[0] == Token.COMMENT && MAP_MARKER_PATTERN.test(token[1])) {
57 return fetchAndApplySourceMap(token[1], source, singleSourceTokens, applyContext);
58 }
59 }
60
61 return applyContext.callback(applyContext.processedTokens);
62}
63
64function findTokenSource(token) {
65 var scope;
66 var metadata;
67
68 if (token[0] == Token.AT_RULE || token[0] == Token.COMMENT || token[0] == Token.RAW) {
69 metadata = token[2][0];
70 } else {
71 scope = token[1][0];
72 metadata = scope[2][0];
73 }
74
75 return metadata[2];
76}
77
78function fetchAndApplySourceMap(sourceMapComment, source, singleSourceTokens, applyContext) {
79 return extractInputSourceMapFrom(sourceMapComment, applyContext, function(inputSourceMap) {
80 if (inputSourceMap) {
81 applyContext.inputSourceMapTracker.track(source, inputSourceMap);
82 applySourceMapRecursively(singleSourceTokens, applyContext.inputSourceMapTracker);
83 }
84
85 applyContext.index++;
86 return doApplySourceMaps(applyContext);
87 });
88}
89
90function extractInputSourceMapFrom(sourceMapComment, applyContext, whenSourceMapReady) {
91 var uri = MAP_MARKER_PATTERN.exec(sourceMapComment)[1];
92 var absoluteUri;
93 var sourceMap;
94 var rebasedMap;
95
96 if (isDataUriResource(uri)) {
97 sourceMap = extractInputSourceMapFromDataUri(uri);
98 return whenSourceMapReady(sourceMap);
99 } if (isRemoteResource(uri)) {
100 return loadInputSourceMapFromRemoteUri(uri, applyContext, function(sourceMap) {
101 var parsedMap;
102
103 if (sourceMap) {
104 parsedMap = JSON.parse(sourceMap);
105 rebasedMap = rebaseRemoteMap(parsedMap, uri);
106 whenSourceMapReady(rebasedMap);
107 } else {
108 whenSourceMapReady(null);
109 }
110 });
111 }
112 // at this point `uri` is already rebased, see lib/reader/rebase.js#rebaseSourceMapComment
113 // it is rebased to be consistent with rebasing other URIs
114 // however here we need to resolve it back to read it from disk
115 absoluteUri = path.resolve(applyContext.rebaseTo, uri);
116 sourceMap = loadInputSourceMapFromLocalUri(absoluteUri, applyContext);
117
118 if (sourceMap) {
119 rebasedMap = rebaseLocalMap(sourceMap, absoluteUri, applyContext.rebaseTo);
120 return whenSourceMapReady(rebasedMap);
121 }
122 return whenSourceMapReady(null);
123}
124
125function extractInputSourceMapFromDataUri(uri) {
126 var dataUriMatch = matchDataUri(uri);
127 var charset = dataUriMatch[2] ? dataUriMatch[2].split(/[=;]/)[2] : 'us-ascii';
128 var encoding = dataUriMatch[3] ? dataUriMatch[3].split(';')[1] : 'utf8';
129 var data = encoding == 'utf8' ? global.unescape(dataUriMatch[4]) : dataUriMatch[4];
130
131 var buffer = Buffer.from(data, encoding);
132 buffer.charset = charset;
133
134 return JSON.parse(buffer.toString());
135}
136
137function loadInputSourceMapFromRemoteUri(uri, applyContext, whenLoaded) {
138 var isAllowed = isAllowedResource(uri, true, applyContext.inline);
139 var isRuntimeResource = !hasProtocol(uri);
140
141 if (applyContext.localOnly) {
142 applyContext.warnings.push('Cannot fetch remote resource from "' + uri + '" as no callback given.');
143 return whenLoaded(null);
144 } if (isRuntimeResource) {
145 applyContext.warnings.push('Cannot fetch "' + uri + '" as no protocol given.');
146 return whenLoaded(null);
147 } if (!isAllowed) {
148 applyContext.warnings.push('Cannot fetch "' + uri + '" as resource is not allowed.');
149 return whenLoaded(null);
150 }
151
152 applyContext.fetch(uri, applyContext.inlineRequest, applyContext.inlineTimeout, function(error, body) {
153 if (error) {
154 applyContext.warnings.push('Missing source map at "' + uri + '" - ' + error);
155 return whenLoaded(null);
156 }
157
158 whenLoaded(body);
159 });
160}
161
162function loadInputSourceMapFromLocalUri(uri, applyContext) {
163 var isAllowed = isAllowedResource(uri, false, applyContext.inline);
164 var sourceMap;
165
166 if (!fs.existsSync(uri) || !fs.statSync(uri).isFile()) {
167 applyContext.warnings.push('Ignoring local source map at "' + uri + '" as resource is missing.');
168 return null;
169 } if (!isAllowed) {
170 applyContext.warnings.push('Cannot fetch "' + uri + '" as resource is not allowed.');
171 return null;
172 } if (!fs.statSync(uri).size) {
173 applyContext.warnings.push('Cannot fetch "' + uri + '" as resource is empty.');
174 return null;
175 }
176
177 sourceMap = fs.readFileSync(uri, 'utf-8');
178 return JSON.parse(sourceMap);
179}
180
181function applySourceMapRecursively(tokens, inputSourceMapTracker) {
182 var token;
183 var i, l;
184
185 for (i = 0, l = tokens.length; i < l; i++) {
186 token = tokens[i];
187
188 switch (token[0]) {
189 case Token.AT_RULE:
190 applySourceMapTo(token, inputSourceMapTracker);
191 break;
192 case Token.AT_RULE_BLOCK:
193 applySourceMapRecursively(token[1], inputSourceMapTracker);
194 applySourceMapRecursively(token[2], inputSourceMapTracker);
195 break;
196 case Token.AT_RULE_BLOCK_SCOPE:
197 applySourceMapTo(token, inputSourceMapTracker);
198 break;
199 case Token.NESTED_BLOCK:
200 applySourceMapRecursively(token[1], inputSourceMapTracker);
201 applySourceMapRecursively(token[2], inputSourceMapTracker);
202 break;
203 case Token.NESTED_BLOCK_SCOPE:
204 applySourceMapTo(token, inputSourceMapTracker);
205 break;
206 case Token.COMMENT:
207 applySourceMapTo(token, inputSourceMapTracker);
208 break;
209 case Token.PROPERTY:
210 applySourceMapRecursively(token, inputSourceMapTracker);
211 break;
212 case Token.PROPERTY_BLOCK:
213 applySourceMapRecursively(token[1], inputSourceMapTracker);
214 break;
215 case Token.PROPERTY_NAME:
216 applySourceMapTo(token, inputSourceMapTracker);
217 break;
218 case Token.PROPERTY_VALUE:
219 applySourceMapTo(token, inputSourceMapTracker);
220 break;
221 case Token.RULE:
222 applySourceMapRecursively(token[1], inputSourceMapTracker);
223 applySourceMapRecursively(token[2], inputSourceMapTracker);
224 break;
225 case Token.RULE_SCOPE:
226 applySourceMapTo(token, inputSourceMapTracker);
227 }
228 }
229
230 return tokens;
231}
232
233function applySourceMapTo(token, inputSourceMapTracker) {
234 var value = token[1];
235 var metadata = token[2];
236 var newMetadata = [];
237 var i, l;
238
239 for (i = 0, l = metadata.length; i < l; i++) {
240 newMetadata.push(inputSourceMapTracker.originalPositionFor(metadata[i], value.length));
241 }
242
243 token[2] = newMetadata;
244}
245
246module.exports = applySourceMaps;
Note: See TracBrowser for help on using the repository browser.