UNPKG

3.2 kBJavaScriptView Raw
1'use strict';
2
3var q = require('q');
4var request = require('request');
5var cheerio = require('cheerio');
6var normalizeUrl = require('normalize-url');
7var resolveCssImportUrls = require('resolve-css-import-urls');
8var getLinkContents = require('./utils/get-link-contents');
9var createLink = require('./utils/create-link');
10var userAgentString = require('./utils/user-agent-string');
11
12module.exports = function(url, options){
13 var deferred = q.defer();
14 var options = options || {};
15 options.headers = options.headers || {};
16 options.headers['User-Agent'] = options.headers['User-Agent'] || userAgentString();
17 options.url = normalizeUrl(url);
18 options.timeout = options.timeout || 5000;
19 options.gzip = true;
20
21 if (options.ignoreCerts) {
22 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
23 }
24
25 var status = {
26 parsed: 0,
27 total: 0
28 };
29
30 var result = {
31 links: [],
32 styles: [],
33 css: ''
34 };
35
36 function handleResolve() {
37 if (status.parsed >= status.total) {
38 deferred.resolve(result);
39 }
40 }
41
42 function parseHtml(html) {
43 var $ = cheerio.load(html);
44 result.pageTitle = $('head > title').text();
45
46 $('[rel=stylesheet]').each(function() {
47 var link = $(this).attr('href');
48 result.links.push(createLink(link, url));
49 });
50
51 $('style').each(function() {
52 result.styles.push($(this).text());
53 });
54
55 status.total = result.links.length + result.styles.length;
56 if (!status.total) {
57 deferred.resolve(false);
58 }
59
60 result.links.forEach(function(link) {
61 getLinkContents(link.url, options)
62 .then(function(css) {
63 handleCssFromLink(link, css);
64 })
65 .catch(function(error) {
66 link.error = error;
67 status.parsed++;
68 handleResolve();
69 });
70 });
71
72 result.styles.forEach(function(css) {
73 result.css += css;
74 status.parsed++;
75 handleResolve();
76 });
77 }
78
79 function handleCssFromLink(link, css) {
80 link.css += css;
81
82 parseCssForImports(link, css);
83
84 status.parsed++;
85 handleResolve();
86 }
87
88 // Handle potential @import url(foo.css) statements in the CSS.
89 function parseCssForImports(link, css) {
90 link.imports = resolveCssImportUrls(link.url, css);
91 status.total += link.imports.length;
92 result.css += css;
93
94 link.imports.forEach(function(importUrl) {
95 var importLink = createLink(importUrl, importUrl);
96 result.links.push(importLink);
97
98 getLinkContents(importLink.url, options)
99 .then(function(css) {
100 handleCssFromLink(importLink, css);
101 })
102 .catch(function(error) {
103 link.error = error;
104 status.parsed++;
105 handleResolve();
106 });
107 });
108 }
109
110 request(options, function(error, response, body) {
111 if (error) {
112 if (options.verbose) console.log('Error from ' + url + ' ' + error);
113 deferred.reject(error);
114 return;
115 }
116
117 if (response && response.statusCode != 200) {
118 if (options.verbose) console.log('Received a ' + response.statusCode + ' from: ' + url);
119 deferred.reject({ url: url, statusCode: response.code });
120 return;
121 }
122
123 parseHtml(body);
124 });
125
126 return deferred.promise;
127};