@ckeditor/ckeditor5-dev-docs 30.0.1 → 30.1.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/lib/web-crawler/index.js +76 -19
- package/lib/web-crawler/utils.js +0 -11
- package/package.json +3 -3
package/lib/web-crawler/index.js
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
const puppeteer = require( 'puppeteer' );
|
|
11
11
|
const chalk = require( 'chalk' );
|
|
12
|
+
const util = require( 'util' );
|
|
12
13
|
const stripAnsiEscapeCodes = require( 'strip-ansi' );
|
|
13
|
-
const { getBaseUrl,
|
|
14
|
+
const { getBaseUrl, toArray } = require( './utils' );
|
|
14
15
|
const { createSpinner, getProgressHandler } = require( './spinner' );
|
|
15
16
|
|
|
16
17
|
const {
|
|
@@ -32,20 +33,40 @@ const {
|
|
|
32
33
|
*
|
|
33
34
|
* @param {Object} options Parsed CLI arguments.
|
|
34
35
|
* @param {String} options.url The URL to start crawling. This argument is required.
|
|
35
|
-
* @param {Number} options.depth Defines how many nested page levels should be examined. Infinity by default.
|
|
36
|
-
* @param {Array.<String>} options.exclusions An array of patterns to exclude links. Empty array by default to not exclude anything.
|
|
37
|
-
* @param {Number} options.concurrency Number of concurrent pages (browser tabs) to be used during crawling. One by default.
|
|
38
|
-
* @param {Boolean} options.quit Terminates the scan as soon as an error is found. False (off) by default.
|
|
36
|
+
* @param {Number} [options.depth=Infinity] Defines how many nested page levels should be examined. Infinity by default.
|
|
37
|
+
* @param {Array.<String>} [options.exclusions=[]] An array of patterns to exclude links. Empty array by default to not exclude anything.
|
|
38
|
+
* @param {Number} [options.concurrency=1] Number of concurrent pages (browser tabs) to be used during crawling. One by default.
|
|
39
|
+
* @param {Boolean} [options.quit=false] Terminates the scan as soon as an error is found. False (off) by default.
|
|
39
40
|
* @param {Boolean} [options.disableBrowserSandbox=false] Whether the browser should be created with the `--no-sandbox` flag.
|
|
40
41
|
* @param {Boolean} [options.noSpinner=false] Whether to display the spinner with progress or a raw message with current progress.
|
|
41
42
|
* @param {Boolean} [options.ignoreHTTPSErrors=false] Whether the browser should ignore invalid (self-signed) certificates.
|
|
42
43
|
* @returns {Promise} Promise is resolved, when the crawler has finished the whole crawling procedure.
|
|
43
44
|
*/
|
|
44
45
|
module.exports = async function verify( options ) {
|
|
45
|
-
const {
|
|
46
|
+
const {
|
|
47
|
+
url,
|
|
48
|
+
depth = Infinity,
|
|
49
|
+
exclusions = [],
|
|
50
|
+
concurrency = 1,
|
|
51
|
+
quit = false,
|
|
52
|
+
disableBrowserSandbox = false,
|
|
53
|
+
noSpinner = false,
|
|
54
|
+
ignoreHTTPSErrors = false
|
|
55
|
+
} = options;
|
|
46
56
|
|
|
47
57
|
console.log( chalk.bold( '\n🔎 Starting the Crawler\n' ) );
|
|
48
58
|
|
|
59
|
+
process.on( 'unhandledRejection', reason => {
|
|
60
|
+
const error = util.inspect( reason, {
|
|
61
|
+
breakLength: Infinity,
|
|
62
|
+
compact: true
|
|
63
|
+
} );
|
|
64
|
+
|
|
65
|
+
console.log( chalk.red.bold( `\n🔥 Caught the \`unhandledRejection\` error: ${ error }\n` ) );
|
|
66
|
+
|
|
67
|
+
process.exit( 1 );
|
|
68
|
+
} );
|
|
69
|
+
|
|
49
70
|
const spinner = createSpinner( { noSpinner } );
|
|
50
71
|
const errors = new Map();
|
|
51
72
|
const browser = await createBrowser( { disableBrowserSandbox, ignoreHTTPSErrors } );
|
|
@@ -128,18 +149,26 @@ function getErrorHandler( errors ) {
|
|
|
128
149
|
errors.set( error.type, new Map() );
|
|
129
150
|
}
|
|
130
151
|
|
|
131
|
-
|
|
152
|
+
// Split the message into the first line and all the rest. The first line is the key by which the errors are grouped together.
|
|
153
|
+
// All errors are grouped together only by the first message line (without the error call stack and other details, that could
|
|
154
|
+
// possibly exist after the first line), because there is a good chance that the same error can be triggered in a different
|
|
155
|
+
// contexts (so in a different call stacks). In order not to duplicate almost the same errors, we need to determine their common
|
|
156
|
+
// part.
|
|
157
|
+
const messageLines = error.message.split( '\n' );
|
|
158
|
+
const firstMessageLine = messageLines.shift();
|
|
159
|
+
const nextMessageLines = messageLines.join( '\n' );
|
|
132
160
|
|
|
133
161
|
const errorCollection = errors.get( error.type );
|
|
134
162
|
|
|
135
|
-
if ( !errorCollection.has(
|
|
136
|
-
errorCollection.set(
|
|
163
|
+
if ( !errorCollection.has( firstMessageLine ) ) {
|
|
164
|
+
errorCollection.set( firstMessageLine, {
|
|
137
165
|
// Store only unique pages, because given error can occur multiple times on the same page.
|
|
138
|
-
pages: new Set()
|
|
166
|
+
pages: new Set(),
|
|
167
|
+
details: nextMessageLines
|
|
139
168
|
} );
|
|
140
169
|
}
|
|
141
170
|
|
|
142
|
-
errorCollection.get(
|
|
171
|
+
errorCollection.get( firstMessageLine ).pages.add( error.pageUrl );
|
|
143
172
|
};
|
|
144
173
|
}
|
|
145
174
|
|
|
@@ -240,7 +269,7 @@ async function openLink( browser, { baseUrl, link, foundLinks, exclusions } ) {
|
|
|
240
269
|
// Consider navigation to be finished when the `load` event is fired and there are no network connections for at least 500 ms.
|
|
241
270
|
await page.goto( link.url, { waitUntil: [ 'load', 'networkidle0' ] } );
|
|
242
271
|
} catch ( error ) {
|
|
243
|
-
const errorMessage = error.message || '
|
|
272
|
+
const errorMessage = error.message || '(empty message)';
|
|
244
273
|
|
|
245
274
|
// All navigation errors starting with the `net::` prefix are already covered by the "request" error handler, so it should
|
|
246
275
|
// not be also reported as the "navigation error".
|
|
@@ -261,6 +290,8 @@ async function openLink( browser, { baseUrl, link, foundLinks, exclusions } ) {
|
|
|
261
290
|
// the page yet, because the page may contain error exclusions, that should be taken into account. Such a case can happen when,
|
|
262
291
|
// for example, the `load` event was not fired because the external resource was not loaded yet.
|
|
263
292
|
if ( !isResponding || page.url() !== link.url ) {
|
|
293
|
+
page.removeAllListeners();
|
|
294
|
+
|
|
264
295
|
await page.close();
|
|
265
296
|
|
|
266
297
|
return {
|
|
@@ -281,6 +312,8 @@ async function openLink( browser, { baseUrl, link, foundLinks, exclusions } ) {
|
|
|
281
312
|
[] :
|
|
282
313
|
await getLinksFromPage( page, { baseUrl, foundLinks, exclusions } );
|
|
283
314
|
|
|
315
|
+
page.removeAllListeners();
|
|
316
|
+
|
|
284
317
|
await page.close();
|
|
285
318
|
|
|
286
319
|
return {
|
|
@@ -424,9 +457,9 @@ function markErrorsAsIgnored( errors, errorIgnorePatterns ) {
|
|
|
424
457
|
async function createPage( browser, { link, onError } ) {
|
|
425
458
|
const page = await browser.newPage();
|
|
426
459
|
|
|
427
|
-
page.setDefaultTimeout( DEFAULT_TIMEOUT );
|
|
460
|
+
await page.setDefaultTimeout( DEFAULT_TIMEOUT );
|
|
428
461
|
|
|
429
|
-
page.setCacheEnabled( false );
|
|
462
|
+
await page.setCacheEnabled( false );
|
|
430
463
|
|
|
431
464
|
dismissDialogs( page );
|
|
432
465
|
|
|
@@ -460,13 +493,13 @@ function registerErrorHandlers( page, { link, onError } ) {
|
|
|
460
493
|
page.on( ERROR_TYPES.PAGE_CRASH.event, error => onError( {
|
|
461
494
|
pageUrl: page.url(),
|
|
462
495
|
type: ERROR_TYPES.PAGE_CRASH,
|
|
463
|
-
message: error.message
|
|
496
|
+
message: error.message || '(empty message)'
|
|
464
497
|
} ) );
|
|
465
498
|
|
|
466
499
|
page.on( ERROR_TYPES.UNCAUGHT_EXCEPTION.event, error => onError( {
|
|
467
500
|
pageUrl: page.url(),
|
|
468
501
|
type: ERROR_TYPES.UNCAUGHT_EXCEPTION,
|
|
469
|
-
message: error.message
|
|
502
|
+
message: error.message || '(empty message)'
|
|
470
503
|
} ) );
|
|
471
504
|
|
|
472
505
|
page.on( ERROR_TYPES.REQUEST_FAILURE.event, request => {
|
|
@@ -524,9 +557,14 @@ function registerErrorHandlers( page, { link, onError } ) {
|
|
|
524
557
|
}
|
|
525
558
|
|
|
526
559
|
const serializeArgumentInPageContext = argument => {
|
|
527
|
-
// Since errors are not serializable, return message
|
|
560
|
+
// Since errors are not serializable, return the message with the call stack as the output text.
|
|
528
561
|
if ( argument instanceof Error ) {
|
|
529
|
-
return argument.
|
|
562
|
+
return argument.stack;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Cast non-string iterable argument to an array.
|
|
566
|
+
if ( typeof argument !== 'string' && argument[ Symbol.iterator ] ) {
|
|
567
|
+
return [ ...argument ];
|
|
530
568
|
}
|
|
531
569
|
|
|
532
570
|
// Return argument right away. Since we use `executionContext().evaluate()`, it'll return JSON value of the
|
|
@@ -540,10 +578,24 @@ function registerErrorHandlers( page, { link, onError } ) {
|
|
|
540
578
|
|
|
541
579
|
const serializedArguments = await Promise.all( message.args().map( serializeArguments ) );
|
|
542
580
|
|
|
581
|
+
const serializedMessage = serializedArguments
|
|
582
|
+
.map( argument => {
|
|
583
|
+
// Do not wrap the string in additional quotes and just return it as is.
|
|
584
|
+
if ( typeof argument === 'string' ) {
|
|
585
|
+
return argument;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return util.inspect( argument, {
|
|
589
|
+
breakLength: Infinity,
|
|
590
|
+
compact: true
|
|
591
|
+
} );
|
|
592
|
+
} )
|
|
593
|
+
.join( ' ' );
|
|
594
|
+
|
|
543
595
|
onError( {
|
|
544
596
|
pageUrl: page.url(),
|
|
545
597
|
type: ERROR_TYPES.CONSOLE_ERROR,
|
|
546
|
-
message:
|
|
598
|
+
message: serializedMessage || message.text() || '(empty message)'
|
|
547
599
|
} );
|
|
548
600
|
} );
|
|
549
601
|
}
|
|
@@ -617,6 +669,10 @@ function logErrors( errors ) {
|
|
|
617
669
|
errorCollection.forEach( ( error, message ) => {
|
|
618
670
|
console.group( `\n❌ ${ message }` );
|
|
619
671
|
|
|
672
|
+
if ( error.details ) {
|
|
673
|
+
console.log( error.details );
|
|
674
|
+
}
|
|
675
|
+
|
|
620
676
|
console.log( chalk.red( `\n…found on the following ${ error.pages.size > 1 ? 'pages' : 'page' }:` ) );
|
|
621
677
|
|
|
622
678
|
error.pages.forEach( pageUrl => console.log( chalk.gray( `➥ ${ pageUrl }` ) ) );
|
|
@@ -658,6 +714,7 @@ function logErrors( errors ) {
|
|
|
658
714
|
/**
|
|
659
715
|
* @typedef {Object.<String, Set.<String>>} ErrorOccurrence
|
|
660
716
|
* @property {Set.<String>} pages A set of unique pages, where error has been found.
|
|
717
|
+
* @property {Set.<String>} [details] Additional error details (i.e. an error stack).
|
|
661
718
|
*/
|
|
662
719
|
|
|
663
720
|
/**
|
package/lib/web-crawler/utils.js
CHANGED
|
@@ -20,16 +20,6 @@ function getBaseUrl( url ) {
|
|
|
20
20
|
return `${ origin }${ pathname }`;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/**
|
|
24
|
-
* Extracts first line from error message.
|
|
25
|
-
*
|
|
26
|
-
* @param {String} message Error message.
|
|
27
|
-
* @returns {String}
|
|
28
|
-
*/
|
|
29
|
-
function getFirstLineFromErrorMessage( message ) {
|
|
30
|
-
return message.split( '\n' ).shift();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
23
|
/**
|
|
34
24
|
* Checks, if provided string is a valid URL utilizing the HTTP or HTTPS protocols.
|
|
35
25
|
*
|
|
@@ -56,7 +46,6 @@ function toArray( data ) {
|
|
|
56
46
|
|
|
57
47
|
module.exports = {
|
|
58
48
|
getBaseUrl,
|
|
59
|
-
getFirstLineFromErrorMessage,
|
|
60
49
|
isUrlValid,
|
|
61
50
|
toArray
|
|
62
51
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-dev-docs",
|
|
3
|
-
"version": "30.0
|
|
3
|
+
"version": "30.1.0",
|
|
4
4
|
"description": "Tasks used to build and verify the documentation for CKEditor 5.",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@ckeditor/ckeditor5-dev-utils": "^30.0
|
|
9
|
-
"@ckeditor/jsdoc-plugins": "^30.0
|
|
8
|
+
"@ckeditor/ckeditor5-dev-utils": "^30.1.0",
|
|
9
|
+
"@ckeditor/jsdoc-plugins": "^30.1.0",
|
|
10
10
|
"fast-glob": "^3.2.4",
|
|
11
11
|
"fs-extra": "^9.0.0",
|
|
12
12
|
"puppeteer": "^13.1.3",
|