Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

linkinator

Package Overview
Dependencies
Maintainers
1
Versions
114
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

linkinator - npm Package Compare versions

Comparing version 2.4.0 to 2.5.0

4

build/src/cli.js

@@ -79,3 +79,3 @@ #!/usr/bin/env node

async function main() {
if (cli.input.length !== 1) {
if (cli.input.length < 1) {
cli.showHelp();

@@ -116,3 +116,3 @@ return;

const opts = {
path: cli.input[0],
path: cli.input,
recurse: flags.recurse,

@@ -119,0 +119,0 @@ timeout: Number(flags.timeout),

@@ -9,3 +9,3 @@ /// <reference types="node" />

port?: number;
path: string;
path: string | string[];
recurse?: boolean;

@@ -40,2 +40,3 @@ timeout?: number;

queue: PQueue<PriorityQueue, DefaultAddOptions>;
rootPath: string;
}

@@ -51,3 +52,3 @@ /**

*/
check(options: CheckOptions): Promise<{
check(opts: CheckOptions): Promise<{
links: LinkResult[];

@@ -60,10 +61,4 @@ passed: boolean;

*/
private validateOptions;
private processOptions;
/**
* Figure out which directory should be used as the root for the web server,
* and how that impacts the path to the file for the first request.
* @param options CheckOptions passed in from the CLI or API
*/
private getServerRoot;
/**
* Spin up a local HTTP server to serve static requests from disk

@@ -70,0 +65,0 @@ * @param root The local path that should be mounted as a static web server

@@ -32,14 +32,24 @@ "use strict";

*/
async check(options) {
this.validateOptions(options);
async check(opts) {
const options = await this.processOptions(opts);
if (!Array.isArray(options.path)) {
options.path = [options.path];
}
options.linksToSkip = options.linksToSkip || [];
options.path = path.normalize(options.path);
let server;
if (!options.path.startsWith('http')) {
const serverOptions = await this.getServerRoot(options);
const hasHttpPaths = options.path.find(x => x.startsWith('http'));
if (!hasHttpPaths) {
const port = options.port || 5000 + Math.round(Math.random() * 1000);
server = await this.startWebServer(serverOptions.serverRoot, port, options.markdown);
server = await this.startWebServer(options.serverRoot, port, options.markdown);
enableDestroy(server);
options.path = `http://localhost:${port}${serverOptions.path}`;
for (let i = 0; i < options.path.length; i++) {
if (options.path[i].startsWith('/')) {
options.path[i] = options.path[i].slice(1);
}
options.path[i] = `http://localhost:${port}/${options.path[i]}`;
}
}
if (process.env.LINKINATOR_DEBUG) {
console.log(options);
}
const queue = new p_queue_1.default({

@@ -49,15 +59,18 @@ concurrency: options.concurrency || 100,

const results = new Array();
const url = new url_1.URL(options.path);
const initCache = new Set();
initCache.add(url.href);
queue.add(async () => {
await this.crawl({
url: new url_1.URL(options.path),
crawl: true,
checkOptions: options,
results,
cache: initCache,
queue,
for (const path of options.path) {
const url = new url_1.URL(path);
initCache.add(url.href);
queue.add(async () => {
await this.crawl({
url,
crawl: true,
checkOptions: options,
results,
cache: initCache,
queue,
rootPath: path,
});
});
});
}
await queue.onIdle();

@@ -77,34 +90,54 @@ const result = {

*/
validateOptions(options) {
if (options.serverRoot && options.path.startsWith('http')) {
async processOptions(opts) {
const options = Object.assign({}, opts);
// ensure at least one path is provided
if (options.path.length === 0) {
throw new Error('At least one path must be provided');
}
// normalize options.path to an array of strings
if (!Array.isArray(options.path)) {
options.path = [options.path];
}
// Ensure we do not mix http:// and file system paths. The paths passed in
// must all be filesystem paths, or HTTP paths.
let isUrlType = undefined;
for (const path of options.path) {
const innerIsUrlType = path.startsWith('http');
if (isUrlType === undefined) {
isUrlType = innerIsUrlType;
}
else if (innerIsUrlType !== isUrlType) {
throw new Error('Paths cannot be mixed between HTTP and local filesystem paths.');
}
}
// if there is a server root, make sure there are no HTTP paths
if (options.serverRoot && isUrlType) {
throw new Error("'serverRoot' cannot be defined when the 'path' points to an HTTP endpoint.");
}
}
/**
* Figure out which directory should be used as the root for the web server,
* and how that impacts the path to the file for the first request.
* @param options CheckOptions passed in from the CLI or API
*/
async getServerRoot(options) {
if (options.serverRoot) {
const filePath = options.path.startsWith('/')
? options.path
: '/' + options.path;
return {
serverRoot: options.serverRoot,
path: filePath,
};
// Figure out which directory should be used as the root for the web server,
// and how that impacts the path to the file for the first request.
if (!options.serverRoot && !isUrlType) {
// if the serverRoot wasn't defined, and there are multiple paths, just
// use process.cwd().
if (options.path.length > 1) {
options.serverRoot = process.cwd();
}
else {
// if there's a single path, try to be smart and figure it out
const s = await stat(options.path[0]);
options.serverRoot = options.path[0];
if (s.isFile()) {
const pathParts = options.path[0].split(path.sep);
options.path = [path.sep + pathParts[pathParts.length - 1]];
options.serverRoot = pathParts
.slice(0, pathParts.length - 1)
.join(path.sep);
}
else {
options.serverRoot = options.path[0];
options.path = '/';
}
}
}
let localDirectory = options.path;
let localFile = '';
const s = await stat(options.path);
if (s.isFile()) {
const pathParts = options.path.split(path.sep);
localFile = path.sep + pathParts[pathParts.length - 1];
localDirectory = pathParts.slice(0, pathParts.length - 1).join(path.sep);
}
return {
serverRoot: localDirectory,
path: localFile,
};
return options;
}

@@ -126,5 +159,2 @@ /**

const pathParts = req.path.split('/').filter(x => !!x);
if (pathParts.length === 0) {
return next();
}
const ext = path.extname(pathParts[pathParts.length - 1]);

@@ -153,2 +183,3 @@ if (ext.toLowerCase() === '.md') {

async crawl(opts) {
var _a;
// explicitly skip non-http[s] links before making the request

@@ -284,12 +315,10 @@ const proto = opts.url.protocol;

}
let crawl = (opts.checkOptions.recurse &&
result.url &&
result.url.href.startsWith(opts.checkOptions.path));
let crawl = (opts.checkOptions.recurse && ((_a = result.url) === null || _a === void 0 ? void 0 : _a.href.startsWith(opts.rootPath)));
// only crawl links that start with the same host
if (crawl) {
try {
const pathUrl = new url_1.URL(opts.checkOptions.path);
const pathUrl = new url_1.URL(opts.rootPath);
crawl = result.url.host === pathUrl.host;
}
catch (_a) {
catch (_b) {
// ignore errors

@@ -311,2 +340,3 @@ }

parent: opts.url.href,
rootPath: opts.rootPath,
});

@@ -313,0 +343,0 @@ });

{
"name": "linkinator",
"description": "Find broken links, missing images, etc in your HTML. Scurry around your site and find all those broken links.",
"version": "2.4.0",
"version": "2.5.0",
"license": "MIT",

@@ -6,0 +6,0 @@ "repository": "JustinBeckwith/linkinator",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc