html-snapshots 0.18.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +4 -5
- package/.github/workflows/verify.yml +2 -2
- package/HISTORY.md +42 -0
- package/README.md +109 -256
- package/examples/README.md +149 -0
- package/examples/custom/myFilter.js +2 -2
- package/examples/custom/package-lock.json +2021 -5
- package/examples/custom/package.json +1 -1
- package/examples/custom/snapshot.js +8 -10
- package/examples/debug-phantomjs/package-lock.json +6 -6
- package/examples/debug-phantomjs/package.json +1 -1
- package/examples/debug-phantomjs/snapshot.js +13 -14
- package/examples/debug-puppeteer/README.md +18 -0
- package/examples/debug-puppeteer/package-lock.json +2804 -0
- package/examples/debug-puppeteer/package.json +12 -0
- package/examples/debug-puppeteer/snapshot.js +30 -0
- package/examples/html5rocks/package-lock.json +1306 -5
- package/examples/html5rocks/package.json +1 -1
- package/examples/html5rocks/snapshot.js +14 -23
- package/examples/process-limit/package-lock.json +1306 -5
- package/examples/process-limit/package.json +1 -1
- package/examples/process-limit/snapshot.js +8 -10
- package/examples/simple-promise/package-lock.json +1306 -5
- package/examples/simple-promise/package.json +1 -1
- package/examples/simple-promise/snapshot.js +6 -8
- package/examples/sitemap-index/package-lock.json +1306 -5
- package/examples/sitemap-index/package.json +1 -1
- package/examples/sitemap-index/snapshot.js +6 -6
- package/examples/utils/index.js +2 -4
- package/examples/verbose/package-lock.json +1306 -5
- package/examples/verbose/package.json +1 -1
- package/examples/verbose/snapshot.js +12 -14
- package/lib/async/index.js +0 -1
- package/lib/common/index.js +1 -1
- package/lib/common/sitemap/index.js +16 -0
- package/lib/common/sitemap/sitemap-collection.js +94 -0
- package/lib/common/sitemap/sitemap-index.js +68 -0
- package/lib/common/{sitemap.js → sitemap/sitemap.js} +68 -57
- package/lib/html-snapshots.js +87 -5
- package/lib/input-generators/_base.js +7 -1
- package/lib/input-generators/array.js +0 -1
- package/lib/input-generators/robots.js +98 -58
- package/lib/input-generators/sitemap-index.js +3 -124
- package/lib/input-generators/sitemap.js +3 -7
- package/lib/input-generators/textfile.js +2 -6
- package/lib/puppeteer/index.js +98 -0
- package/lib/puppeteer/removeScripts.js +8 -0
- package/package.json +9 -4
- package/test/helpers/options.js +4 -2
- package/test/mocha/browsers/puppeteer.js +106 -0
- package/test/mocha/browsers/server/index.html +9 -0
- package/test/mocha/browsers/test.js +11 -0
- package/test/mocha/html-snapshots/basics.js +60 -47
- package/test/mocha/html-snapshots/phantomjs-options.js +54 -60
- package/test/mocha/html-snapshots/process-limit.js +126 -120
- package/test/mocha/html-snapshots/puppeteer.js +47 -0
- package/test/mocha/html-snapshots/robots.js +156 -121
- package/test/mocha/html-snapshots/server/public/page-sitemap.xml +16 -0
- package/test/mocha/html-snapshots/server/test_robots.txt +13 -0
- package/test/mocha/html-snapshots/server/test_robots_sitemap.txt +15 -0
- package/test/mocha/html-snapshots/server/test_robots_sitemap.xml +22 -0
- package/test/mocha/html-snapshots/sitemap-index.js +100 -90
- package/test/mocha/html-snapshots/sitemap.js +75 -31
- package/test/mocha/html-snapshots/snapshot-scripts.js +150 -145
- package/test/mocha/html-snapshots/test.js +23 -14
- package/test/mocha/html-snapshots/test_robots.txt +0 -2
- package/test/mocha/html-snapshots/use-jquery.js +65 -64
- package/test/mocha/html-snapshots/utils.js +29 -30
- package/test/mocha/input-generators/server/test_robots.txt +0 -2
- package/test/mocha/input-generators/server/test_robots_bad.txt +0 -2
- package/test/mocha/input-generators/server/test_robots_sitemap.txt +17 -0
- package/test/mocha/input-generators/server/test_robots_sitemap_bad.txt +17 -0
- package/test/mocha/input-generators/server/test_robots_sitemap_multi.txt +18 -0
- package/test/mocha/input-generators/server/test_sitemap_index_empty.xml +3 -0
- package/test/mocha/input-generators/server/test_sitemap_index_malformed.xml +2 -0
- package/test/mocha/input-generators/sitemap-index.js +65 -9
- package/test/mocha/input-generators/test.js +276 -280
- package/test/mocha/input-generators/test_robots.txt +0 -2
- package/test/mocha/input-generators/test_robots_bad.txt +0 -2
- package/test/mocha/input-generators/test_robots_sitemap.txt +17 -0
- package/test/mocha/input-generators/test_robots_sitemap_bad.txt +17 -0
- package/test/mocha/input-generators/test_robots_sitemap_multi.txt +18 -0
- package/lib/common/node.js +0 -26
- package/test/mocha/common/node.js +0 -100
|
@@ -5,32 +5,30 @@
|
|
|
5
5
|
* Use sitemap.xml to snapshot an entire site.
|
|
6
6
|
* Use the verbose option to debug the loading of one of the pages.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
const htmlSnapshots = require("html-snapshots");
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
var pageToDebug = origin + "/sample-page";
|
|
10
|
+
const origin = "https://www.sitemaps.org";
|
|
11
|
+
const pageToDebug = `${origin}/en_GB/`;
|
|
13
12
|
|
|
14
13
|
// Make the verbose option as an object keyed with the page to debug.
|
|
15
|
-
|
|
16
|
-
__default: false
|
|
14
|
+
const verboseOption = {
|
|
15
|
+
__default: false,
|
|
16
|
+
[pageToDebug]: true
|
|
17
17
|
};
|
|
18
|
-
verboseOption[pageToDebug] = true;
|
|
19
18
|
|
|
20
19
|
htmlSnapshots.run({
|
|
21
20
|
input: "sitemap",
|
|
22
|
-
source: origin
|
|
21
|
+
source: `${origin}/sitemap.xml`,
|
|
23
22
|
outputDir: require("path").join(__dirname, "./tmp"),
|
|
24
23
|
outputDirClean: true,
|
|
25
|
-
selector: "
|
|
26
|
-
timeout:
|
|
24
|
+
selector: "#mainContent",
|
|
25
|
+
timeout: 10000,
|
|
26
|
+
browser: "phantomjs",
|
|
27
27
|
processLimit: 1, // to clarify output
|
|
28
28
|
verbose: verboseOption
|
|
29
29
|
})
|
|
30
|
-
.then(
|
|
30
|
+
.then(completed => {
|
|
31
31
|
console.log("completed snapshots:");
|
|
32
32
|
console.log(require("util").inspect(completed));
|
|
33
33
|
})
|
|
34
|
-
.catch(
|
|
35
|
-
console.error(err);
|
|
36
|
-
});
|
|
34
|
+
.catch(console.error);
|
package/lib/async/index.js
CHANGED
package/lib/common/index.js
CHANGED
|
@@ -48,7 +48,7 @@ function isUrl (obj) {
|
|
|
48
48
|
* If undefined, then pass through undefined.
|
|
49
49
|
* @param {String} [message] - The message to prepend.
|
|
50
50
|
* @param {Boolean} [quoteInput] - True if the message should be quoted.
|
|
51
|
-
* @returns {Error} The updated Error instance, undefined if no error
|
|
51
|
+
* @returns {Error|Undefined} The updated Error instance, *undefined if no error*.
|
|
52
52
|
*/
|
|
53
53
|
function prependMsgToErr (error, message, quoteInput) {
|
|
54
54
|
let result, prepend;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reused sitemap modules.
|
|
3
|
+
* Used by robots, sitemap, and sitemap-index input generators.
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2013 - 2022 Alex Grant, LocalNerve, contributors
|
|
6
|
+
* Licensed under the MIT license.
|
|
7
|
+
*/
|
|
8
|
+
const sitemap = require("./sitemap");
|
|
9
|
+
const smc = require("./sitemap-collection");
|
|
10
|
+
const smi = require("./sitemap-index");
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
sitemapCollection: { process: smc.processSitemaps.bind(null, sitemap) },
|
|
14
|
+
sitemapIndex: { process: smi.sitemapIndex.bind(null, sitemap) },
|
|
15
|
+
sitemap
|
|
16
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sitemap-index.js (common functions)
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2013 - 2022 Alex Grant, LocalNerve, contributors
|
|
5
|
+
* Licensed under the MIT license.
|
|
6
|
+
*/
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const pathLib = require("path");
|
|
9
|
+
const mkdirp = require("mkdirp");
|
|
10
|
+
const common = require("../index");
|
|
11
|
+
const base = require("../../input-generators/_base");
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Make sure path exists so a sitemap write can succeed.
|
|
15
|
+
*
|
|
16
|
+
* @param {String} outputPath - File path and name.
|
|
17
|
+
* @param {Function} callback - Completion callback.
|
|
18
|
+
*/
|
|
19
|
+
function prepareWrite (outputPath, callback) {
|
|
20
|
+
const path = pathLib.parse(outputPath);
|
|
21
|
+
const dir = pathLib.join(path.root, path.dir);
|
|
22
|
+
mkdirp(dir).then(() => callback()).catch(callback);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parse a sitemap, generate input, and optionally update the local file
|
|
27
|
+
* for sitemapPolicy purposes.
|
|
28
|
+
* This writes the sitemap files out EVEN IF sitemapPolicy is false.
|
|
29
|
+
* The thinking is that it's better/cheaper to do this b/c if sitemapPolicy is
|
|
30
|
+
* enabled later, then there is something to compare against, for more savings.
|
|
31
|
+
*
|
|
32
|
+
* @param {Object} options - Sitemap options.
|
|
33
|
+
* @param {Object} options.__sitemapIndex - Sitemap Index options.
|
|
34
|
+
* @param {String} document - xml document string.
|
|
35
|
+
* @param {Function} callback - A completion callback.
|
|
36
|
+
*/
|
|
37
|
+
function processSitemap (smLib, options, document, callback) {
|
|
38
|
+
smLib.parse(options, document, err => {
|
|
39
|
+
const sitemapIndexOpts = options.__sitemapIndex;
|
|
40
|
+
const outputPath = base.outputFile(sitemapIndexOpts, options.source);
|
|
41
|
+
|
|
42
|
+
if (!err && sitemapIndexOpts.sitemapOutputDir) {
|
|
43
|
+
prepareWrite(outputPath, err => {
|
|
44
|
+
if (!err) {
|
|
45
|
+
fs.writeFile(outputPath, document, callback);
|
|
46
|
+
} else {
|
|
47
|
+
callback(common.prependMsgToErr(err, outputPath, true));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
} else {
|
|
51
|
+
callback(err);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get and process a sitemaps collection.
|
|
58
|
+
*
|
|
59
|
+
* @param {Object} smLib - Sitemap common module.
|
|
60
|
+
* @param {Object} options - Sitemap options.
|
|
61
|
+
* @param {Array} sitemapUrls - collection of sitemap urls to process.
|
|
62
|
+
* @param {Object} [sitemapIndexOptions] - Sitemap index options.
|
|
63
|
+
* @returns {Promise} resolves when all sitemaps are processed, reject as soon as one fails
|
|
64
|
+
*/
|
|
65
|
+
function processSitemaps (smLib, options, sitemapUrls, sitemapIndexOptions) {
|
|
66
|
+
// Edge case message for clarity
|
|
67
|
+
if (sitemapUrls.length === 0) {
|
|
68
|
+
console.log("[*] No sitemaps qualified for processing");
|
|
69
|
+
return Promise.resolve([]);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const smiOptions = sitemapIndexOptions || {
|
|
73
|
+
...options,
|
|
74
|
+
...{ outputPath: undefined }
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Get all the sitemaps, parse them, and generate input for each
|
|
78
|
+
return Promise.all(sitemapUrls.map(sitemapUrl => {
|
|
79
|
+
const sitemapOptions = Object.assign({}, options, {
|
|
80
|
+
source: sitemapUrl,
|
|
81
|
+
input: "sitemap",
|
|
82
|
+
sitemapOutputDir: false,
|
|
83
|
+
__sitemapIndex: smiOptions
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
console.log(`[+] Loading the sitemap: '${sitemapUrl}'`);
|
|
87
|
+
|
|
88
|
+
return smLib.getUrl(sitemapOptions, processSitemap.bind(null, smLib));
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
processSitemaps
|
|
94
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sitemap-index.js
|
|
3
|
+
*
|
|
4
|
+
* Generates the urls for a sitemap-index.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2013 - 2022 Alex Grant, LocalNerve, contributors
|
|
7
|
+
* Licensed under the MIT license.
|
|
8
|
+
*/
|
|
9
|
+
const _ = require("lodash");
|
|
10
|
+
const smc = require("./sitemap-collection");
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create a collection of sitemap urls to process by policy, form sitemapIndexOptions.
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} smLib - Sitemap module
|
|
16
|
+
* @param {Object} options - sitemap index options
|
|
17
|
+
* @param {Boolean} options.sitemapPolicy - True if sitemap policy should be used.
|
|
18
|
+
* @param {Object} parseResult - xml2js sax parse result object
|
|
19
|
+
* @returns {Object} The sitemapUrls collection and sitemapIndexOptions
|
|
20
|
+
*/
|
|
21
|
+
function sitemapIndexUrls (smLib, options, parseResult) {
|
|
22
|
+
const sitemapUrls = [];
|
|
23
|
+
const sitemapIndexOptions = {
|
|
24
|
+
...options,
|
|
25
|
+
...{ outputPath: undefined }
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Check if we should process each sitemap in the index.
|
|
29
|
+
_.forEach(
|
|
30
|
+
// if the sitemap index is malformed, just blow up
|
|
31
|
+
parseResult.sitemapindex.sitemap,
|
|
32
|
+
sitemapNode => {
|
|
33
|
+
// optionally ignore current sitemaps by sitemap policy
|
|
34
|
+
const shouldProcess = !options.sitemapPolicy ||
|
|
35
|
+
!smLib.stillCurrent(sitemapNode, sitemapIndexOptions);
|
|
36
|
+
|
|
37
|
+
if (shouldProcess) {
|
|
38
|
+
// if sitemap index is malformed, just blow up
|
|
39
|
+
sitemapUrls.push(sitemapNode.loc[0]);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
sitemapUrls,
|
|
46
|
+
sitemapIndexOptions
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Collect sitemap urls from a sitemap index file for processing.
|
|
52
|
+
*
|
|
53
|
+
* @param {Object} smLib - sitemap module
|
|
54
|
+
* @param {Object} options - sitemapIndex options
|
|
55
|
+
* @param {Object} parseResult - xml2js sax parse result object
|
|
56
|
+
* @returns {Promise} resolves when all sitemaps are processed, reject as soon as one fails
|
|
57
|
+
*/
|
|
58
|
+
function sitemapIndex (smLib, options, parseResult) {
|
|
59
|
+
const {
|
|
60
|
+
sitemapUrls,
|
|
61
|
+
sitemapIndexOptions
|
|
62
|
+
} = sitemapIndexUrls(smLib, options, parseResult);
|
|
63
|
+
return smc.processSitemaps(smLib, options, sitemapUrls, sitemapIndexOptions);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
sitemapIndex
|
|
68
|
+
};
|
|
@@ -9,14 +9,15 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const fs = require("fs");
|
|
12
|
+
const util = require("util");
|
|
12
13
|
const path = require("path");
|
|
13
14
|
const urlm = require("url");
|
|
14
15
|
const zlib = require("zlib");
|
|
15
16
|
const _ = require("lodash");
|
|
16
17
|
const xml2js = require("xml2js");
|
|
17
|
-
const
|
|
18
|
-
const common = require("
|
|
19
|
-
const base = require("
|
|
18
|
+
const smi = require("./sitemap-index");
|
|
19
|
+
const common = require("../index");
|
|
20
|
+
const base = require("../../input-generators/_base");
|
|
20
21
|
|
|
21
22
|
// the out of date fallback
|
|
22
23
|
const unixStart = "1970-01-01T00:00:00.000Z";
|
|
@@ -44,6 +45,7 @@ const changeFreq = {
|
|
|
44
45
|
*/
|
|
45
46
|
function stillCurrent (urlNode, options) {
|
|
46
47
|
let lesser, greater, oPath;
|
|
48
|
+
const statOpts = {throwIfNoEntry: false};
|
|
47
49
|
const now = Date.now();
|
|
48
50
|
const lMod = _.first(urlNode.lastmod);
|
|
49
51
|
const cFreq = _.first(urlNode.changefreq) ? _.first(urlNode.changefreq).toLowerCase() : null;
|
|
@@ -53,7 +55,7 @@ function stillCurrent (urlNode, options) {
|
|
|
53
55
|
// if sitemap is malformed, just blow up
|
|
54
56
|
oPath = base.outputFile(options, urlNode.loc[0]);
|
|
55
57
|
|
|
56
|
-
lesser = now - (
|
|
58
|
+
lesser = now - (fs.statSync(oPath, statOpts)?.mtime?.getTime() ?? unixStart);
|
|
57
59
|
greater = now - Date.parse(lMod);
|
|
58
60
|
}
|
|
59
61
|
// only changefreq specified
|
|
@@ -61,7 +63,7 @@ function stillCurrent (urlNode, options) {
|
|
|
61
63
|
// if sitemap is malformed, just blow up
|
|
62
64
|
oPath = base.outputFile(options, urlNode.loc[0]);
|
|
63
65
|
|
|
64
|
-
lesser = now - (
|
|
66
|
+
lesser = now - (fs.statSync(oPath, statOpts)?.mtime?.getTime() ?? unixStart);
|
|
65
67
|
greater = changeFreq[cFreq] || changeFreq.always;
|
|
66
68
|
}
|
|
67
69
|
// both or neither were specified
|
|
@@ -91,43 +93,49 @@ function parse (options, document, callback) {
|
|
|
91
93
|
normalize: true
|
|
92
94
|
}, (err, result) => {
|
|
93
95
|
let source = options.source;
|
|
94
|
-
|
|
95
96
|
if (!err) {
|
|
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
|
-
|
|
97
|
+
if (result.sitemapindex) {
|
|
98
|
+
// actually a sitemap index
|
|
99
|
+
return smi.sitemapIndex(module.exports, options, result)
|
|
100
|
+
.then(() => callback())
|
|
101
|
+
.catch(callback);
|
|
102
|
+
} else {
|
|
103
|
+
// Process the url input, but break if base.input returns false.
|
|
104
|
+
// In other words, _.find is looking for a non-falsy err.
|
|
105
|
+
// For now, this can only happen if no outputDir is defined,
|
|
106
|
+
// which is a fatal bad option problem and will happen immediately.
|
|
107
|
+
_.find(
|
|
108
|
+
// if the sitemap is malformed, just blow up
|
|
109
|
+
result.urlset.url,
|
|
110
|
+
urlNode => {
|
|
111
|
+
// optionally ignore current urls by sitemap policy
|
|
112
|
+
let url;
|
|
113
|
+
const process = !options.sitemapPolicy ||
|
|
114
|
+
!stillCurrent(urlNode, options);
|
|
115
|
+
|
|
116
|
+
if (process) {
|
|
117
|
+
// if sitemap is malformed, just blow up
|
|
118
|
+
url = urlm.parse(urlNode.loc[0]);
|
|
119
|
+
if (!base.input(_.extend({}, options, {
|
|
120
|
+
protocol: url.protocol,
|
|
121
|
+
auth: url.auth,
|
|
122
|
+
hostname: url.hostname,
|
|
123
|
+
port: url.port
|
|
124
|
+
}),
|
|
125
|
+
urlNode.loc[0])
|
|
126
|
+
) {
|
|
127
|
+
source = urlNode.loc[0];
|
|
128
|
+
err = base.generatorError();
|
|
129
|
+
}
|
|
123
130
|
}
|
|
124
|
-
}
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
return err;
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
129
136
|
}
|
|
130
137
|
|
|
138
|
+
// NOTE: if !err, then prependMsgToErr returns `undefined`
|
|
131
139
|
callback(common.prependMsgToErr(err, source, true));
|
|
132
140
|
});
|
|
133
141
|
}
|
|
@@ -165,21 +173,25 @@ function convert (options, buffer, next, callback) {
|
|
|
165
173
|
* @param {String} options.source - Sitemap URL.
|
|
166
174
|
* @param {Function} options.timeout - User supplied run timeout.
|
|
167
175
|
* @param {Function} parseFn - A data parser function.
|
|
168
|
-
* @
|
|
176
|
+
* @return {Promise} resolves to data on completion.
|
|
169
177
|
*/
|
|
170
|
-
function getUrl (options, parseFn
|
|
171
|
-
|
|
178
|
+
async function getUrl (options, parseFn) {
|
|
179
|
+
const { default:got } = await import("got");
|
|
180
|
+
return got({
|
|
172
181
|
url: options.source,
|
|
173
|
-
|
|
174
|
-
timeout:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
responseType: "buffer",
|
|
183
|
+
timeout: {
|
|
184
|
+
request: options.timeout() // get the default timeout
|
|
185
|
+
}
|
|
186
|
+
}).then(res => {
|
|
187
|
+
let error = common.checkResponse(res, ["text/xml", "application/xml"]);
|
|
178
188
|
if (error) {
|
|
179
|
-
|
|
180
|
-
} else {
|
|
181
|
-
convert(options, body, parseFn, callback);
|
|
189
|
+
throw new Error(error);
|
|
182
190
|
}
|
|
191
|
+
const conv = util.promisify(convert);
|
|
192
|
+
return conv(options, res.body, parseFn);
|
|
193
|
+
}).catch(err => {
|
|
194
|
+
throw new Error(common.prependMsgToErr(err, options.source, true));
|
|
183
195
|
});
|
|
184
196
|
}
|
|
185
197
|
|
|
@@ -189,16 +201,15 @@ function getUrl (options, parseFn, callback) {
|
|
|
189
201
|
* @param {Object} options - Sitemap options.
|
|
190
202
|
* @param {String} options.source - Sitemap file path.
|
|
191
203
|
* @param {Function} parseFn - A data parser function.
|
|
192
|
-
* @
|
|
204
|
+
* @return {Promise} resolves to data on completion.
|
|
193
205
|
*/
|
|
194
|
-
function getFile (options, parseFn
|
|
195
|
-
fs.readFile
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
});
|
|
206
|
+
function getFile (options, parseFn) {
|
|
207
|
+
const readFile = util.promisify(fs.readFile);
|
|
208
|
+
const conv = util.promisify(convert);
|
|
209
|
+
return readFile(options.source).then(data => conv(options, data, parseFn))
|
|
210
|
+
.catch(err => {
|
|
211
|
+
throw new Error(common.prependMsgToErr(err, options.source, true));
|
|
212
|
+
});
|
|
202
213
|
}
|
|
203
214
|
|
|
204
215
|
module.exports = {
|
package/lib/html-snapshots.js
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* Copyright (c) 2013 - 2022 Alex Grant, LocalNerve, contributors
|
|
10
10
|
* Licensed under the MIT license.
|
|
11
11
|
*/
|
|
12
|
-
/* global Promise */
|
|
13
12
|
|
|
14
13
|
const spawn = require("child_process").spawn;
|
|
15
14
|
const path = require("path");
|
|
@@ -21,8 +20,6 @@ const _ = require("lodash");
|
|
|
21
20
|
const common = require("./common");
|
|
22
21
|
const inputFactory = require("./input-generators");
|
|
23
22
|
const Notifier = require("./async").Notifier;
|
|
24
|
-
const phantomDir = "./phantom";
|
|
25
|
-
const snapshotScript = path.join(phantomDir, "default.js");
|
|
26
23
|
|
|
27
24
|
/**
|
|
28
25
|
* Determine the default phantomJS module path. This is overridden by the
|
|
@@ -57,13 +54,21 @@ function defaultPhantomJSExePath () {
|
|
|
57
54
|
return phantomSource;
|
|
58
55
|
}
|
|
59
56
|
|
|
57
|
+
const phantomDir = "./phantom";
|
|
58
|
+
const phantomSnapshotScript = path.join(phantomDir, "default.js");
|
|
59
|
+
const puppeteerDir = "./puppeteer";
|
|
60
|
+
const puppeteerSnapshotScript = path.join(puppeteerDir, "index.js");
|
|
61
|
+
|
|
60
62
|
/**
|
|
61
63
|
* This module's defaults
|
|
62
64
|
*/
|
|
63
65
|
const defaults = Object.freeze({
|
|
64
66
|
input: "robots",
|
|
67
|
+
browser: "puppeteer",
|
|
65
68
|
phantomjs: defaultPhantomJSExePath(),
|
|
66
|
-
|
|
69
|
+
phantomSnapshotScript: path.join(__dirname, phantomSnapshotScript),
|
|
70
|
+
puppeteer: path.join(__dirname, puppeteerSnapshotScript),
|
|
71
|
+
snapshotScript: path.join(__dirname, puppeteerSnapshotScript),
|
|
67
72
|
outputDirClean: false,
|
|
68
73
|
pollInterval: 500,
|
|
69
74
|
processLimit: 4
|
|
@@ -93,7 +98,7 @@ const defaults = Object.freeze({
|
|
|
93
98
|
* @param {Function} notifier.known - Check if a file is or has been processed.
|
|
94
99
|
* @param {Function} qcb - async.queue callback function.
|
|
95
100
|
*/
|
|
96
|
-
function
|
|
101
|
+
function phantomjsWorker (input, options, notifier, qcb) {
|
|
97
102
|
let cp, customModule;
|
|
98
103
|
let snapshotScript = options.snapshotScript;
|
|
99
104
|
const phantomjsOptions =
|
|
@@ -143,6 +148,73 @@ function worker (input, options, notifier, qcb) {
|
|
|
143
148
|
}
|
|
144
149
|
}
|
|
145
150
|
|
|
151
|
+
/**
|
|
152
|
+
* @param {Object} input - An input object from an input generator.
|
|
153
|
+
* @param {String} input.outputFile - The output file that the html is written to.
|
|
154
|
+
* @param {String} input.url - The url to get the html from.
|
|
155
|
+
* @param {String} input.selector - The selector to wait for.
|
|
156
|
+
* @param {String} input.timeout - The entire process timeout.
|
|
157
|
+
* @param {String} input.debug - The debug object.
|
|
158
|
+
* @param {Object} options - Input options.
|
|
159
|
+
* @param {Object} options.snapshotScript - Snapshot script options.
|
|
160
|
+
* @param {String} options.snapshotScript.script - Snapshot script name.
|
|
161
|
+
* @param {String} options.snapshotScript.module - Snapshot script module.
|
|
162
|
+
* @param {String} options.puppeteer - Full path to the puppeteer exec.
|
|
163
|
+
* @param {Object} notifier - The async Notifier instance for this run.
|
|
164
|
+
* @param {Function} notifier.remove - Remove an outputFile from notifier.
|
|
165
|
+
* @param {Function} notifier.setError - Set an error on the notifier.
|
|
166
|
+
* @param {Function} notifier.add - Add a file, timeout to the notifier.
|
|
167
|
+
* @param {Function} notifier.known - Check if a file is or has been processed.
|
|
168
|
+
* @param {Function} qcb - async.queue callback function.
|
|
169
|
+
*/
|
|
170
|
+
function puppeteerWorker (input, options, notifier, qcb) {
|
|
171
|
+
let filter = "false";
|
|
172
|
+
let snapshotScript = options.snapshotScript;
|
|
173
|
+
|
|
174
|
+
// If the outputFile has NOT already been seen by the notifier, process.
|
|
175
|
+
if (!notifier.known(input.outputFile)) {
|
|
176
|
+
|
|
177
|
+
// map snapshotScript object script
|
|
178
|
+
if (_.isObject(options.snapshotScript)) {
|
|
179
|
+
snapshotScript = options.puppeteer;
|
|
180
|
+
if (options.snapshotScript.script === "removeScripts") {
|
|
181
|
+
filter = "./removeScripts";
|
|
182
|
+
} else {
|
|
183
|
+
filter = options.snapshotScript.module;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const cp = spawn(
|
|
188
|
+
snapshotScript,
|
|
189
|
+
[ input.outputFile,
|
|
190
|
+
input.url,
|
|
191
|
+
input.selector,
|
|
192
|
+
input.timeout,
|
|
193
|
+
filter,
|
|
194
|
+
input.debug.flag,
|
|
195
|
+
input.debug.slowMo
|
|
196
|
+
], { cwd: process.cwd(), stdio: "inherit", detached: true }
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
cp.on("error", function (e) {
|
|
200
|
+
notifier.remove(input.outputFile);
|
|
201
|
+
notifier.setError(e);
|
|
202
|
+
console.error(e);
|
|
203
|
+
qcb(e);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
cp.on("exit", function (code) {
|
|
207
|
+
qcb(code);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// start counting
|
|
211
|
+
notifier.add(input.outputFile, input.timeout);
|
|
212
|
+
} else {
|
|
213
|
+
// The input.outputFile is being or has been processed this run.
|
|
214
|
+
qcb(0);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
146
218
|
/**
|
|
147
219
|
* Prepare html snapshots options.
|
|
148
220
|
*
|
|
@@ -157,6 +229,13 @@ function prepOptions (options) {
|
|
|
157
229
|
if (Array.isArray(options.source)) {
|
|
158
230
|
options.input = "array";
|
|
159
231
|
}
|
|
232
|
+
|
|
233
|
+
// If phantomjs browser, make sure the default snapshotScript is correctly set.
|
|
234
|
+
if (options.browser === 'phantomjs') {
|
|
235
|
+
if (!options.snapshotScript || options.snapshotScript === options.puppeteer) {
|
|
236
|
+
options.snapshotScript = options.phantomSnapshotScript;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
160
239
|
}
|
|
161
240
|
|
|
162
241
|
module.exports = {
|
|
@@ -227,6 +306,9 @@ module.exports = {
|
|
|
227
306
|
// expose abort callback to input generators via options.
|
|
228
307
|
options._abort = notifier.abort.bind(notifier, q);
|
|
229
308
|
|
|
309
|
+
const worker =
|
|
310
|
+
options.browser === 'puppeteer' ? puppeteerWorker : phantomjsWorker;
|
|
311
|
+
|
|
230
312
|
// generate input for the snapshots.
|
|
231
313
|
return inputGenerator.run(options, input => {
|
|
232
314
|
q.push(_.partial(worker, input, options, notifier));
|
|
@@ -26,7 +26,11 @@ const defaults = Object.freeze({
|
|
|
26
26
|
checkInterval: 250,
|
|
27
27
|
useJQuery: false,
|
|
28
28
|
verbose: false,
|
|
29
|
-
phantomjsOptions: ""
|
|
29
|
+
phantomjsOptions: "",
|
|
30
|
+
debug: {
|
|
31
|
+
flag: "false",
|
|
32
|
+
slowMo: 500
|
|
33
|
+
}
|
|
30
34
|
});
|
|
31
35
|
|
|
32
36
|
/**
|
|
@@ -224,6 +228,7 @@ module.exports = {
|
|
|
224
228
|
* @param {Function} options.userJQuery - Produces a jquery bool given a page url.
|
|
225
229
|
* @param {Function} options.verbose - Produces a verbose bool given a page url.
|
|
226
230
|
* @param {Function} options.phantomjsOptions - Produces phantomjs options given a page url.
|
|
231
|
+
* @param {Function} options.debug - Produces debug options given a page url.
|
|
227
232
|
* @param {Function} options._inputEmitter - The EventEmitter to generate input.
|
|
228
233
|
* @param {String} page - The url to the page resource.
|
|
229
234
|
* @returns {String} The full output file path.
|
|
@@ -258,6 +263,7 @@ module.exports = {
|
|
|
258
263
|
// map the input page to phantomJS options
|
|
259
264
|
phantomjsOptions: options.phantomjsOptions(page),
|
|
260
265
|
// useful for testing, debugging
|
|
266
|
+
debug: options.debug,
|
|
261
267
|
__page: page
|
|
262
268
|
});
|
|
263
269
|
|