@djangocfg/nextjs 2.1.48 ā 2.1.50
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/README.md +0 -1
- package/dist/config/index.mjs +1 -10
- package/dist/config/index.mjs.map +1 -1
- package/dist/index.mjs +1 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -13
- package/dist/scripts/index.d.mts +0 -45
- package/dist/scripts/index.mjs +0 -40383
- package/dist/scripts/index.mjs.map +0 -1
- package/src/scripts/check-links.ts +0 -477
- package/src/scripts/index.ts +0 -6
|
@@ -1,477 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Smart Link Checker using linkinator
|
|
5
|
-
*
|
|
6
|
-
* Checks all links on a website with proper error handling,
|
|
7
|
-
* timeout management, and filtering of problematic URLs.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```bash
|
|
11
|
-
* node check-links.ts https://example.com
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { mkdir, writeFile } from 'fs/promises';
|
|
16
|
-
import * as linkinator from 'linkinator';
|
|
17
|
-
import { dirname } from 'path';
|
|
18
|
-
import pc from 'picocolors';
|
|
19
|
-
import prompts from 'prompts';
|
|
20
|
-
|
|
21
|
-
import type { CheckOptions } from 'linkinator';
|
|
22
|
-
export interface CheckLinksOptions {
|
|
23
|
-
/** Base URL to check */
|
|
24
|
-
url: string;
|
|
25
|
-
/** Timeout in milliseconds (default: 60000) */
|
|
26
|
-
timeout?: number;
|
|
27
|
-
/** URLs to skip (regex pattern) */
|
|
28
|
-
skipPattern?: string;
|
|
29
|
-
/** Show only broken links (default: true) */
|
|
30
|
-
showOnlyBroken?: boolean;
|
|
31
|
-
/** Maximum number of concurrent requests (default: 50) */
|
|
32
|
-
concurrency?: number;
|
|
33
|
-
/** Output file path for report (optional) */
|
|
34
|
-
outputFile?: string;
|
|
35
|
-
/** Report format: 'json', 'markdown', 'text' (default: 'text') */
|
|
36
|
-
reportFormat?: 'json' | 'markdown' | 'text';
|
|
37
|
-
/** Verbose logging (default: true) */
|
|
38
|
-
verbose?: boolean;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const DEFAULT_SKIP_PATTERN = [
|
|
42
|
-
'github.com',
|
|
43
|
-
'twitter.com',
|
|
44
|
-
'linkedin.com',
|
|
45
|
-
'x.com',
|
|
46
|
-
'127.0.0.1',
|
|
47
|
-
'uneralon.com',
|
|
48
|
-
'localhost:[0-9]+',
|
|
49
|
-
'api\\.localhost',
|
|
50
|
-
'demo\\.localhost',
|
|
51
|
-
'cdn-cgi', // Cloudflare email protection
|
|
52
|
-
'mailto:', // Email links
|
|
53
|
-
'tel:', // Phone links
|
|
54
|
-
'javascript:', // JavaScript links
|
|
55
|
-
].join('|');
|
|
56
|
-
|
|
57
|
-
export interface CheckLinksResult {
|
|
58
|
-
success: boolean;
|
|
59
|
-
broken: number;
|
|
60
|
-
total: number;
|
|
61
|
-
errors: Array<{ url: string; status: number | string; reason?: string }>;
|
|
62
|
-
url: string;
|
|
63
|
-
timestamp: string;
|
|
64
|
-
duration?: number;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export async function checkLinks(options: CheckLinksOptions): Promise<CheckLinksResult> {
|
|
68
|
-
const {
|
|
69
|
-
url,
|
|
70
|
-
timeout = 60000, // Increased to 60 seconds
|
|
71
|
-
skipPattern = DEFAULT_SKIP_PATTERN,
|
|
72
|
-
showOnlyBroken = true,
|
|
73
|
-
concurrency = 50, // Increased to 50 concurrent requests
|
|
74
|
-
outputFile,
|
|
75
|
-
reportFormat = 'text',
|
|
76
|
-
verbose = true,
|
|
77
|
-
} = options;
|
|
78
|
-
|
|
79
|
-
const startTime = Date.now();
|
|
80
|
-
|
|
81
|
-
if (verbose) {
|
|
82
|
-
console.log(pc.cyan(`\nš Starting link check for: ${pc.bold(url)}`));
|
|
83
|
-
console.log(pc.dim(` Timeout: ${timeout}ms | Concurrency: ${concurrency}`));
|
|
84
|
-
console.log('');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Build linksToSkip array from regex pattern
|
|
88
|
-
const skipRegex = new RegExp(skipPattern);
|
|
89
|
-
const linksToSkip: string[] = [];
|
|
90
|
-
|
|
91
|
-
const checkOptions: CheckOptions = {
|
|
92
|
-
path: url,
|
|
93
|
-
recurse: true,
|
|
94
|
-
timeout,
|
|
95
|
-
concurrency,
|
|
96
|
-
linksToSkip: (link: string) => {
|
|
97
|
-
return Promise.resolve(skipRegex.test(link));
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
const broken: Array<{ url: string; status: number | string; reason?: string }> = [];
|
|
101
|
-
let total = 0;
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
const results = await linkinator.check(checkOptions);
|
|
105
|
-
|
|
106
|
-
// linkinator.check() returns { links: LinkResult[], passed: boolean }
|
|
107
|
-
for (const result of results.links) {
|
|
108
|
-
total++;
|
|
109
|
-
const status = result.status || 0;
|
|
110
|
-
|
|
111
|
-
// Consider broken: non-2xx status codes, timeouts, errors
|
|
112
|
-
if (status < 200 || status >= 400 || result.state === 'BROKEN') {
|
|
113
|
-
broken.push({
|
|
114
|
-
url: result.url,
|
|
115
|
-
status: status || 'TIMEOUT',
|
|
116
|
-
reason: result.state === 'BROKEN' ? 'BROKEN' : undefined,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const success = broken.length === 0;
|
|
122
|
-
|
|
123
|
-
if (!showOnlyBroken || broken.length > 0) {
|
|
124
|
-
if (success) {
|
|
125
|
-
console.log(`ā
All links are valid!`);
|
|
126
|
-
console.log(` Checked ${total} links.`);
|
|
127
|
-
} else {
|
|
128
|
-
console.log(`ā Found ${broken.length} broken links out of ${total} total:`);
|
|
129
|
-
console.log('');
|
|
130
|
-
for (const { url, status, reason } of broken) {
|
|
131
|
-
console.log(` [${status}] ${url}${reason ? ` (${reason})` : ''}`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const duration = Date.now() - startTime;
|
|
137
|
-
const result: CheckLinksResult = {
|
|
138
|
-
success,
|
|
139
|
-
broken: broken.length,
|
|
140
|
-
total,
|
|
141
|
-
errors: broken,
|
|
142
|
-
url,
|
|
143
|
-
timestamp: new Date().toISOString(),
|
|
144
|
-
duration,
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// Save report if output file is specified
|
|
148
|
-
if (outputFile) {
|
|
149
|
-
await saveReport(result, outputFile, reportFormat);
|
|
150
|
-
console.log(pc.green(`\nš Report saved to: ${pc.cyan(outputFile)}`));
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return result;
|
|
154
|
-
} catch (error) {
|
|
155
|
-
// Handle timeout and other errors gracefully
|
|
156
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
157
|
-
const errorName = error instanceof Error ? error.name : 'UnknownError';
|
|
158
|
-
|
|
159
|
-
if (
|
|
160
|
-
errorMessage.includes('timeout') ||
|
|
161
|
-
errorMessage.includes('TimeoutError') ||
|
|
162
|
-
errorName === 'TimeoutError' ||
|
|
163
|
-
errorMessage.includes('aborted')
|
|
164
|
-
) {
|
|
165
|
-
console.warn(pc.yellow(`ā ļø Some links timed out after ${timeout}ms`));
|
|
166
|
-
console.warn(pc.dim(` This is normal for slow or protected URLs.`));
|
|
167
|
-
if (total > 0) {
|
|
168
|
-
console.warn(pc.dim(` Checked ${total} links before timeout.`));
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// If we have some broken links, show them
|
|
172
|
-
if (broken.length > 0) {
|
|
173
|
-
console.log(pc.red(`\nā Found ${broken.length} broken links:`));
|
|
174
|
-
for (const { url, status, reason } of broken) {
|
|
175
|
-
const statusColor = typeof status === 'number' && status >= 500 ? pc.red : pc.yellow;
|
|
176
|
-
console.log(` ${statusColor(`[${status}]`)} ${pc.cyan(url)}${reason ? pc.dim(` (${reason})`) : ''}`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
console.error(pc.red(`ā Error checking links: ${errorMessage}`));
|
|
181
|
-
if (error instanceof Error && error.stack) {
|
|
182
|
-
console.error(pc.dim(error.stack));
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const duration = Date.now() - startTime;
|
|
187
|
-
// Return partial results even on error
|
|
188
|
-
const result: CheckLinksResult = {
|
|
189
|
-
success: broken.length === 0 && total > 0, // Success only if no broken links and we checked something
|
|
190
|
-
broken: broken.length,
|
|
191
|
-
total,
|
|
192
|
-
errors: broken,
|
|
193
|
-
url,
|
|
194
|
-
timestamp: new Date().toISOString(),
|
|
195
|
-
duration,
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
// Save report if output file is specified
|
|
199
|
-
if (outputFile) {
|
|
200
|
-
try {
|
|
201
|
-
await saveReport(result, outputFile, reportFormat);
|
|
202
|
-
console.log(pc.green(`\nš Report saved to: ${pc.cyan(outputFile)}`));
|
|
203
|
-
} catch (saveError) {
|
|
204
|
-
console.warn(pc.yellow(`\nā ļø Failed to save report: ${saveError instanceof Error ? saveError.message : String(saveError)}`));
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return result;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Save report to file in specified format
|
|
214
|
-
*/
|
|
215
|
-
async function saveReport(
|
|
216
|
-
result: CheckLinksResult,
|
|
217
|
-
filePath: string,
|
|
218
|
-
format: 'json' | 'markdown' | 'text'
|
|
219
|
-
): Promise<void> {
|
|
220
|
-
// Ensure directory exists
|
|
221
|
-
const dir = dirname(filePath);
|
|
222
|
-
if (dir !== '.') {
|
|
223
|
-
await mkdir(dir, { recursive: true });
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
let content: string;
|
|
227
|
-
|
|
228
|
-
switch (format) {
|
|
229
|
-
case 'json':
|
|
230
|
-
content = JSON.stringify(result, null, 2);
|
|
231
|
-
break;
|
|
232
|
-
|
|
233
|
-
case 'markdown':
|
|
234
|
-
content = generateMarkdownReport(result);
|
|
235
|
-
break;
|
|
236
|
-
|
|
237
|
-
case 'text':
|
|
238
|
-
default:
|
|
239
|
-
content = generateTextReport(result);
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
await writeFile(filePath, content, 'utf-8');
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Generate markdown report
|
|
248
|
-
*/
|
|
249
|
-
function generateMarkdownReport(result: CheckLinksResult): string {
|
|
250
|
-
const lines: string[] = [];
|
|
251
|
-
|
|
252
|
-
lines.push('# Link Check Report');
|
|
253
|
-
lines.push('');
|
|
254
|
-
lines.push(`**URL:** ${result.url}`);
|
|
255
|
-
lines.push(`**Timestamp:** ${result.timestamp}`);
|
|
256
|
-
if (result.duration) {
|
|
257
|
-
lines.push(`**Duration:** ${(result.duration / 1000).toFixed(2)}s`);
|
|
258
|
-
}
|
|
259
|
-
lines.push('');
|
|
260
|
-
lines.push(`**Status:** ${result.success ? 'ā
All links valid' : 'ā Broken links found'}`);
|
|
261
|
-
lines.push(`**Total links:** ${result.total}`);
|
|
262
|
-
lines.push(`**Broken links:** ${result.broken}`);
|
|
263
|
-
lines.push('');
|
|
264
|
-
|
|
265
|
-
if (result.errors.length > 0) {
|
|
266
|
-
lines.push('## Broken Links');
|
|
267
|
-
lines.push('');
|
|
268
|
-
lines.push('| Status | URL | Reason |');
|
|
269
|
-
lines.push('|--------|-----|--------|');
|
|
270
|
-
for (const { url, status, reason } of result.errors) {
|
|
271
|
-
lines.push(`| ${status} | ${url} | ${reason || '-'} |`);
|
|
272
|
-
}
|
|
273
|
-
lines.push('');
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return lines.join('\n');
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Generate text report
|
|
281
|
-
*/
|
|
282
|
-
function generateTextReport(result: CheckLinksResult): string {
|
|
283
|
-
const lines: string[] = [];
|
|
284
|
-
|
|
285
|
-
lines.push('Link Check Report');
|
|
286
|
-
lines.push('='.repeat(50));
|
|
287
|
-
lines.push(`URL: ${result.url}`);
|
|
288
|
-
lines.push(`Timestamp: ${result.timestamp}`);
|
|
289
|
-
if (result.duration) {
|
|
290
|
-
lines.push(`Duration: ${(result.duration / 1000).toFixed(2)}s`);
|
|
291
|
-
}
|
|
292
|
-
lines.push('');
|
|
293
|
-
lines.push(`Status: ${result.success ? 'ā
All links valid' : 'ā Broken links found'}`);
|
|
294
|
-
lines.push(`Total links: ${result.total}`);
|
|
295
|
-
lines.push(`Broken links: ${result.broken}`);
|
|
296
|
-
lines.push('');
|
|
297
|
-
|
|
298
|
-
if (result.errors.length > 0) {
|
|
299
|
-
lines.push('Broken Links:');
|
|
300
|
-
lines.push('-'.repeat(50));
|
|
301
|
-
for (const { url, status, reason } of result.errors) {
|
|
302
|
-
lines.push(`[${status}] ${url}${reason ? ` (${reason})` : ''}`);
|
|
303
|
-
}
|
|
304
|
-
lines.push('');
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return lines.join('\n');
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// CLI interface
|
|
311
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
312
|
-
// Handle unhandled promise rejections and errors
|
|
313
|
-
process.on('unhandledRejection', (error) => {
|
|
314
|
-
if (error instanceof Error) {
|
|
315
|
-
if (error.message.includes('timeout') || error.message.includes('TimeoutError') || error.name === 'TimeoutError') {
|
|
316
|
-
console.warn(pc.yellow(`\nā ļø Operation timed out. This is normal for slow or protected URLs.`));
|
|
317
|
-
process.exit(0); // Exit gracefully
|
|
318
|
-
} else {
|
|
319
|
-
console.error(pc.red(`\nā Unhandled error: ${error.message}`));
|
|
320
|
-
process.exit(1);
|
|
321
|
-
}
|
|
322
|
-
} else {
|
|
323
|
-
console.error(pc.red(`\nā Unhandled error:`), error);
|
|
324
|
-
process.exit(1);
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
process.on('uncaughtException', (error) => {
|
|
329
|
-
if (error.message.includes('timeout') || error.message.includes('TimeoutError') || error.name === 'TimeoutError') {
|
|
330
|
-
console.warn(pc.yellow(`\nā ļø Operation timed out. This is normal for slow or protected URLs.`));
|
|
331
|
-
process.exit(0); // Exit gracefully
|
|
332
|
-
} else {
|
|
333
|
-
console.error(pc.red(`\nā Uncaught exception: ${error.message}`));
|
|
334
|
-
process.exit(1);
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const args = process.argv.slice(2);
|
|
339
|
-
|
|
340
|
-
// Interactive mode if no arguments
|
|
341
|
-
if (args.length === 0) {
|
|
342
|
-
(async () => {
|
|
343
|
-
console.log(pc.bold(pc.cyan('\nš Link Checker\n')));
|
|
344
|
-
|
|
345
|
-
const response = await prompts([
|
|
346
|
-
{
|
|
347
|
-
type: 'text',
|
|
348
|
-
name: 'url',
|
|
349
|
-
message: 'Enter URL to check:',
|
|
350
|
-
validate: (value) => value.length > 0 || 'URL is required',
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
type: 'number',
|
|
354
|
-
name: 'timeout',
|
|
355
|
-
message: 'Timeout (ms):',
|
|
356
|
-
initial: 60000,
|
|
357
|
-
min: 1000,
|
|
358
|
-
},
|
|
359
|
-
{
|
|
360
|
-
type: 'number',
|
|
361
|
-
name: 'concurrency',
|
|
362
|
-
message: 'Concurrency:',
|
|
363
|
-
initial: 50,
|
|
364
|
-
min: 1,
|
|
365
|
-
max: 200,
|
|
366
|
-
},
|
|
367
|
-
{
|
|
368
|
-
type: 'confirm',
|
|
369
|
-
name: 'verbose',
|
|
370
|
-
message: 'Verbose logging (show progress)?',
|
|
371
|
-
initial: true,
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
type: 'confirm',
|
|
375
|
-
name: 'showAll',
|
|
376
|
-
message: 'Show all links (not just broken)?',
|
|
377
|
-
initial: false,
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
type: 'text',
|
|
381
|
-
name: 'outputFile',
|
|
382
|
-
message: 'Save report to file (optional, leave empty to skip):',
|
|
383
|
-
initial: '',
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
type: (prev) => prev ? 'select' : null,
|
|
387
|
-
name: 'reportFormat',
|
|
388
|
-
message: 'Report format:',
|
|
389
|
-
choices: [
|
|
390
|
-
{ title: 'Text', value: 'text' },
|
|
391
|
-
{ title: 'Markdown', value: 'markdown' },
|
|
392
|
-
{ title: 'JSON', value: 'json' },
|
|
393
|
-
],
|
|
394
|
-
initial: 0,
|
|
395
|
-
},
|
|
396
|
-
]);
|
|
397
|
-
|
|
398
|
-
if (!response.url) {
|
|
399
|
-
console.log(pc.yellow('Cancelled.'));
|
|
400
|
-
process.exit(0);
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
const options: CheckLinksOptions = {
|
|
404
|
-
url: response.url,
|
|
405
|
-
timeout: response.timeout,
|
|
406
|
-
concurrency: response.concurrency,
|
|
407
|
-
showOnlyBroken: !response.showAll,
|
|
408
|
-
outputFile: response.outputFile || undefined,
|
|
409
|
-
reportFormat: response.reportFormat || 'text',
|
|
410
|
-
verbose: response.verbose !== undefined ? response.verbose : true,
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
await checkLinks(options);
|
|
414
|
-
process.exit(0);
|
|
415
|
-
})().catch((error) => {
|
|
416
|
-
console.error(pc.red('Fatal error:'), error);
|
|
417
|
-
process.exit(1);
|
|
418
|
-
});
|
|
419
|
-
} else {
|
|
420
|
-
// Non-interactive mode with arguments
|
|
421
|
-
if (args[0] === '--help' || args[0] === '-h') {
|
|
422
|
-
console.log(pc.bold('Usage: check-links.ts <url> [options]'));
|
|
423
|
-
console.log('');
|
|
424
|
-
console.log(pc.bold('Options:'));
|
|
425
|
-
console.log(` ${pc.cyan('--timeout <ms>')} Timeout in milliseconds (default: 60000)`);
|
|
426
|
-
console.log(` ${pc.cyan('--skip <pattern>')} Regex pattern for URLs to skip`);
|
|
427
|
-
console.log(` ${pc.cyan('--show-all')} Show all links, not just broken ones`);
|
|
428
|
-
console.log(` ${pc.cyan('--concurrency <num>')} Max concurrent requests (default: 50)`);
|
|
429
|
-
console.log(` ${pc.cyan('--output <file>')} Save report to file`);
|
|
430
|
-
console.log(` ${pc.cyan('--format <format>')} Report format: json, markdown, text (default: text)`);
|
|
431
|
-
console.log(` ${pc.cyan('--quiet, -q')} Disable verbose logging`);
|
|
432
|
-
console.log(` ${pc.cyan('--help, -h')} Show this help message`);
|
|
433
|
-
console.log('');
|
|
434
|
-
console.log(pc.dim('If no arguments provided, interactive mode will start.'));
|
|
435
|
-
process.exit(0);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
const url = args[0];
|
|
439
|
-
const options: CheckLinksOptions = { url };
|
|
440
|
-
|
|
441
|
-
// Parse options
|
|
442
|
-
for (let i = 1; i < args.length; i++) {
|
|
443
|
-
const arg = args[i];
|
|
444
|
-
if (arg === '--timeout' && args[i + 1]) {
|
|
445
|
-
options.timeout = parseInt(args[++i], 10);
|
|
446
|
-
} else if (arg === '--skip' && args[i + 1]) {
|
|
447
|
-
options.skipPattern = args[++i];
|
|
448
|
-
} else if (arg === '--show-all') {
|
|
449
|
-
options.showOnlyBroken = false;
|
|
450
|
-
} else if (arg === '--concurrency' && args[i + 1]) {
|
|
451
|
-
options.concurrency = parseInt(args[++i], 10);
|
|
452
|
-
} else if ((arg === '--output' || arg === '-o') && args[i + 1]) {
|
|
453
|
-
options.outputFile = args[++i];
|
|
454
|
-
} else if (arg === '--format' && args[i + 1]) {
|
|
455
|
-
const format = args[++i] as 'json' | 'markdown' | 'text';
|
|
456
|
-
if (['json', 'markdown', 'text'].includes(format)) {
|
|
457
|
-
options.reportFormat = format;
|
|
458
|
-
} else {
|
|
459
|
-
console.error(pc.red(`Invalid format: ${format}. Use: json, markdown, or text`));
|
|
460
|
-
process.exit(1);
|
|
461
|
-
}
|
|
462
|
-
} else if (arg === '--quiet' || arg === '-q') {
|
|
463
|
-
options.verbose = false;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
checkLinks(options)
|
|
468
|
-
.then((result) => {
|
|
469
|
-
process.exit(result.success ? 0 : 1);
|
|
470
|
-
})
|
|
471
|
-
.catch((error) => {
|
|
472
|
-
console.error(pc.red('Fatal error:'), error);
|
|
473
|
-
process.exit(1);
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|