Skip to content

Commit e603124

Browse files
Merge pull request #77 from justindhillon/file&line
CLI outputs broken link, path, and line number.
2 parents 99fe91f + a415a15 commit e603124

File tree

4 files changed

+43
-27
lines changed

4 files changed

+43
-27
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The `arg` can be a link, file path, or directory path. The `callback` will be gi
1818
import linkInspector from 'link-inspector';
1919

2020
linkInspector('http://example.com', function (link) {
21-
console.log(`Broken link found: ${link}`);
21+
console.log(`Broken link found: ${link}`);
2222
});
2323
```
2424

@@ -27,8 +27,8 @@ If you want to use linkInspector on all the files in a directory:
2727
```js
2828
import linkInspector from 'link-inspector';
2929

30-
linkInspector('./path/to/directory', function (link, path) {
31-
console.log(`Broken link ${link} found in ${path}`);
30+
linkInspector('./path/to/directory', function (link, path, lineNumber) {
31+
console.log(`Broken link ${link} found in ${path} on line ${lineNumber}`);
3232
});
3333
```
3434

bin.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,31 @@ if (args.length === 0) {
1010
console.error("no link or path given");
1111
}
1212

13-
async function writeLink(link: string, path: string) {
13+
async function writeLink(link: string, path: string, lineNumber: number) {
14+
path = path.replace(/\/\//g, '/');
15+
1416
console.log("Broken Link:", link);
17+
if (path) console.log("Path:", path);
18+
if (lineNumber) console.log("Line:", lineNumber);
19+
console.log("");
1520

1621
if (path) {
1722
path = "output/" + path;
18-
if (!fs.existsSync(path)) {
23+
if (!fs.existsSync(path))
1924
fs.mkdirSync(dirname(path), { recursive: true });
20-
}
25+
2126
fs.appendFileSync(path, link + "\n");
2227
}
2328
}
2429

2530
for (const arg of args) {
2631
let path: string = '';
2732

28-
try {new URL(arg)}
33+
try { new URL(arg) }
2934
catch {
3035
path = basename(arg);
3136
}
3237

3338
linkInspector(arg, writeLink, path);
39+
console.log("");
3440
}

checkLink.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@ export async function checkLink(link: string): Promise<boolean> {
2323
await axios.head(link, params);
2424
} catch (err: any) {
2525
// If false positive, return false
26-
if (falsePositives.has(err.response.status)) return false;
26+
if (falsePositives.has(err.response.status))
27+
return false;
2728

2829
// If HEAD is not allowed try GET
2930
if (err.response.status === 405) {
3031
try {
3132
await axios.get(link, params);
3233
} catch (error: any) {
3334
// If false positive, return false
34-
if (falsePositives.has(err.response.status)) return false;
35+
if (falsePositives.has(err.response.status))
36+
return false;
3537

3638
return true;
3739
}

index.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { checkLink } from "./checkLink";
22
import fs from 'fs';
33

4+
const urlRegex: RegExp = /(?<!xmlns=['"])(?<!xmlns:.*=['"])(?<!targetNamespace=['"])(\bhttps?:\/\/(?!.*\$)(?!.*{)(?!.*"\s\+)[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
5+
46
let QUEUE:Record<number, string[]> = {};
57
let PROCESS: number = 0;
68
let CURRENTPROCESS: number = 0;
@@ -11,14 +13,13 @@ async function runProcess(callback: any) {
1113
if (MAXPROCESSES <= RUNNINGPROCESSES || !QUEUE[PROCESS-1]) return;
1214

1315
RUNNINGPROCESSES++;
14-
const [link, path] = QUEUE[CURRENTPROCESS]!;
16+
const [link, path, lineNumber] = QUEUE[CURRENTPROCESS]!;
1517
delete QUEUE[CURRENTPROCESS];
1618
CURRENTPROCESS++;
1719

1820
try {
19-
if (await checkLink(link!)) {
20-
callback(link, path);
21-
}
21+
if (await checkLink(link!))
22+
callback(link, path, lineNumber);
2223
} catch {} // Skip invalid urls
2324

2425
RUNNINGPROCESSES--;
@@ -38,10 +39,12 @@ export default async function linkInspector(arg: string, callback: any, path: st
3839
const stats: fs.Stats = fs.lstatSync(arg);
3940

4041
// Skip symbolic links
41-
if (stats.isSymbolicLink()) return;
42+
if (stats.isSymbolicLink())
43+
return;
4244

4345
// Skip files over 100mb
44-
if (100*1024*1024 < stats.size) return
46+
if (100*1024*1024 < stats.size)
47+
return
4548

4649
// Handle directory
4750
if (stats.isDirectory()) {
@@ -56,22 +59,27 @@ export default async function linkInspector(arg: string, callback: any, path: st
5659
const content: string = fs.readFileSync(arg, 'utf8');
5760

5861
// Skip binary files
59-
if (!/^[\x00-\x7F]*$/.test(content)) return;
62+
if (!/^[\x00-\x7F]*$/.test(content))
63+
return;
6064

6165
// Get all the links
62-
const urlRegex: RegExp = /(?<!xmlns=['"])(?<!xmlns:.*=['"])(?<!targetNamespace=['"])(\bhttps?:\/\/(?!.*\$)(?!.*{)(?!.*"\s\+)[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
63-
const links: string[] = content.match(urlRegex) || [];
66+
const lines = content.split('\n');
67+
68+
for (let i = 0; i < lines.length; i++) {
69+
const line = lines[i];
70+
const matches = line!.match(urlRegex) || [];
6471

65-
const directoryIndex: number = arg.indexOf(path);
66-
const pathAfterDirectory: string = arg.substring(directoryIndex);
72+
const directoryIndex: number = arg.indexOf(path);
73+
const pathAfterDirectory: string = arg.substring(directoryIndex);
6774

68-
for (const link of links) {
69-
try { // Runs link inspector on each link
70-
new URL(link);
71-
QUEUE[PROCESS] = [link, pathAfterDirectory];
72-
PROCESS++;
73-
runProcess(callback);
74-
} catch {}
75+
for (const link of matches) {
76+
try { // Runs link inspector on each link
77+
new URL(link);
78+
QUEUE[PROCESS] = [link, pathAfterDirectory, (i+1).toString()];
79+
PROCESS++;
80+
runProcess(callback);
81+
} catch {}
82+
}
7583
}
7684
} catch {
7785
console.error(`Error: ${arg} is not a valid link or path`);

0 commit comments

Comments
 (0)