UNPKG

4.1 kBJavaScriptView Raw
1/**
2 * Fetches remote asset / local CSS file and returns analyzer results
3 *
4 * Used internally by analyze-css "binary" to communicate with CommonJS module
5 */
6'use strict';
7
8var cli = require('cli'),
9 debug = require('debug')('analyze-css:runner'),
10 fs = require('fs'),
11 resolve = require('path').resolve,
12 analyzer = require('./index'),
13 preprocessors = new(require('./preprocessors'))();
14
15/**
16 * Return user agent to be used by analyze-css when making HTTP requests (issue #75)
17 */
18function getUserAgent() {
19 var format = require('util').format,
20 version = require('../package').version;
21
22 return format(
23 'analyze-css/%s (%s %s, %s %s)',
24 version,
25 process.release.name,
26 process.version,
27 process.platform,
28 process.arch
29 );
30}
31
32/**
33 * Simplified implementation of "request" npm module
34 *
35 * @see https://www.npmjs.com/package/node-fetch
36 */
37function request(requestOptions, callback) {
38 var debug = require('debug')('analyze-css:http'),
39 fetch = require('node-fetch');
40
41 debug('GET %s', requestOptions.url);
42 debug('Options: %j', requestOptions);
43
44 fetch(requestOptions.url, requestOptions).
45 then(function(resp) {
46 debug('HTTP %d %s', resp.status, resp.statusText);
47 debug('Headers: %j', resp.headers._headers);
48
49 if (!resp.ok) {
50 var err = new Error('HTTP request failed: ' + (err ? err.toString() : 'received HTTP ' + resp.status + ' ' + resp.statusText));
51 callback(err);
52 } else {
53 return resp.text(); // a promise
54 }
55 }).
56 then(function(body) {
57 debug('Received %d bytes of CSS', body.length);
58 callback(null, body);
59 }).
60 catch(function(err) {
61 debug(err);
62 callback(err);
63 });
64}
65
66/**
67 * Module's main function
68 */
69function runner(options, callback) {
70 // call CommonJS module
71 var analyzerOpts = {
72 'noOffenders': options.noOffenders,
73 'preprocessor': false,
74 };
75
76 function analyze(css) {
77 new analyzer(css, analyzerOpts, callback);
78 }
79
80 if (options.url) {
81 debug('Fetching remote CSS file: %s', options.url);
82
83 // @see https://www.npmjs.com/package/node-fetch#options
84 var agentOptions = {},
85 requestOptions = {
86 url: options.url,
87 headers: {
88 'User-Agent': getUserAgent()
89 }
90 };
91
92 // handle options
93
94 // @see https://github.com/bitinn/node-fetch/issues/15
95 // @see https://nodejs.org/api/https.html#https_https_request_options_callback
96 if (options.ignoreSslErrors) {
97 agentOptions.rejectUnauthorized = false;
98 }
99
100 // @see https://gist.github.com/cojohn/1772154
101 if (options.authUser && options.authPass) {
102 requestOptions.headers.Authorization = "Basic " + new Buffer(options.authUser + ":" + options.authPass, "utf8").toString("base64");
103 }
104
105 // @see https://nodejs.org/api/http.html#http_class_http_agent
106 var client = require(/^https:/.test(options.url) ? 'https' : 'http');
107 requestOptions.agent = new client.Agent(agentOptions);
108
109 // @see http://stackoverflow.com/a/5810547
110 options.proxy = options.proxy || process.env.HTTP_PROXY;
111
112 if (options.proxy) {
113 debug('Using HTTP proxy: %s', options.proxy);
114
115 requestOptions.agent = new(require('http-proxy-agent'))(options.proxy);
116 }
117
118 request(requestOptions, function(err, css) {
119 if (err) {
120 err.code = analyzer.EXIT_URL_LOADING_FAILED;
121
122 debug(err);
123 callback(err);
124 } else {
125 analyze(css);
126 }
127 });
128 } else if (options.file) {
129 // resolve to the full path
130 options.file = resolve(process.cwd(), options.file);
131 debug('Loading local CSS file: %s', options.file);
132
133 fs.readFile(options.file, {
134 encoding: 'utf-8'
135 }, function(err, css) {
136 if (err) {
137 err = new Error('Loading CSS file failed: ' + err.toString());
138 err.code = analyzer.EXIT_FILE_LOADING_FAILED;
139
140 debug(err);
141 callback(err);
142 } else {
143 // find the matching preprocessor and use it
144 if (analyzerOpts.preprocessor === false) {
145 analyzerOpts.preprocessor = preprocessors.findMatchingByFileName(options.file);
146 }
147
148 // pass the name of the file being analyzed
149 analyzerOpts.file = options.file;
150
151 analyze(css);
152 }
153 });
154 } else if (options.stdin) {
155 debug('Reading from stdin');
156 cli.withStdin(analyze);
157 }
158}
159
160module.exports = runner;