Skip to content

Commit c4119ae

Browse files
azuclaude
andauthored
refactor: remove get-url-origin dependency (#164)
* refactor: remove get-url-origin dependency Replace get-url-origin package with native URL object for getting URL origins. This reduces external dependencies and uses built-in Node.js functionality. Fixes #160 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * fix: use fileURLToPath for proper cross-platform file:// URL handling Use Node.js built-in fileURLToPath function instead of manual string manipulation for converting file:// URLs to file paths. This ensures proper handling across all platforms including Windows. --------- Co-authored-by: Claude <[email protected]>
1 parent a2fa689 commit c4119ae

File tree

3 files changed

+34
-20
lines changed

3 files changed

+34
-20
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
"trailingComma": "none"
4141
},
4242
"dependencies": {
43-
"get-url-origin": "^1.0.1",
4443
"minimatch": "^3.0.4",
4544
"p-memoize": "^3.1.0",
4645
"p-queue": "^6.2.0",

pnpm-lock.yaml

Lines changed: 0 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/no-dead-link.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { RuleHelper } from "textlint-rule-helper";
2-
import URL from "url";
32
import fs from "fs/promises";
43
import minimatch from "minimatch";
54
import { isAbsolute } from "path";
6-
import { getURLOrigin } from "get-url-origin";
5+
import { fileURLToPath } from "url";
76
import pMemoize from "p-memoize";
87
import PQueue from "p-queue";
98
import type { TextlintRuleReporter } from "@textlint/types";
@@ -50,8 +49,8 @@ const URI_REGEXP =
5049
* @return {boolean}
5150
*/
5251
function isHttp(uri: string) {
53-
const { protocol } = URL.parse(uri);
54-
return protocol === "http:" || protocol === "https:";
52+
const url = URL.parse(uri);
53+
return url ? url.protocol === "http:" || url.protocol === "https:" : false;
5554
}
5655

5756
/**
@@ -61,8 +60,18 @@ function isHttp(uri: string) {
6160
* @see https://github.com/panosoft/is-local-path
6261
*/
6362
function isRelative(uri: string) {
64-
const { host } = URL.parse(uri);
65-
return host === null || host === "";
63+
const url = URL.parse(uri);
64+
// If URL.parse returns null and it's not an absolute path, it's relative
65+
if (!url) {
66+
return !isAbsolute(uri);
67+
}
68+
// If it has a protocol but no host (except for file://), it's not relative
69+
// URLs like mailto:, ftp:, ws: etc. have protocol but no host
70+
if (url.protocol && url.protocol !== "file:") {
71+
return false;
72+
}
73+
// file:// URLs or URLs without protocol but with no host are relative
74+
return !url.host && !isAbsolute(uri);
6675
}
6776

6877
/**
@@ -105,7 +114,8 @@ function waitTimeMs(ms: number) {
105114

106115
const createFetchWithRuleDefaults = (ruleOptions: Options) => {
107116
return (uri: string, fetchOptions: RequestInit) => {
108-
const { host } = URL.parse(uri);
117+
const url = URL.parse(uri);
118+
const host = url?.host;
109119
return fetch(uri, {
110120
...fetchOptions,
111121
// Some website require UserAgent and Accept header
@@ -184,7 +194,8 @@ const createCheckAliveURL = (ruleOptions: Options) => {
184194
};
185195
}
186196
const finalRes = await fetchWithDefaults(redirectedUrl, { ...opts, redirect: "follow" });
187-
const { hash } = URL.parse(uri);
197+
const url = URL.parse(uri);
198+
const hash = url?.hash || null;
188199
return {
189200
ok: finalRes.ok,
190201
redirected: true,
@@ -244,7 +255,10 @@ const createCheckAliveURL = (ruleOptions: Options) => {
244255
*/
245256
async function isAliveLocalFile(filePath: string): Promise<AliveFunctionReturn> {
246257
try {
247-
await fs.access(filePath.replace(/[?#].*?$/, ""));
258+
// Convert file:// URL to path if needed, otherwise use as-is
259+
const pathToCheck = filePath.startsWith("file://") ? fileURLToPath(filePath) : filePath;
260+
261+
await fs.access(pathToCheck.replace(/[?#].*?$/, ""));
248262
return {
249263
ok: true,
250264
message: "OK"
@@ -294,7 +308,12 @@ const reporter: TextlintRuleReporter<Options> = (context, options) => {
294308
}
295309

296310
// eslint-disable-next-line no-param-reassign
297-
uri = URL.resolve(base, uri);
311+
// Convert file path to file:// URL if needed
312+
const baseURL = base.startsWith("http") || base.startsWith("file://") ? base : `file://${base}`;
313+
const resolved = URL.parse(uri, baseURL);
314+
if (resolved) {
315+
uri = resolved.href;
316+
}
298317
}
299318

300319
// Ignore non http external link
@@ -304,7 +323,11 @@ const reporter: TextlintRuleReporter<Options> = (context, options) => {
304323
}
305324

306325
const method =
307-
ruleOptions.preferGET.filter((origin) => getURLOrigin(uri) === getURLOrigin(origin)).length > 0
326+
ruleOptions.preferGET.filter((origin) => {
327+
const uriURL = URL.parse(uri);
328+
const originURL = URL.parse(origin);
329+
return uriURL && originURL && uriURL.origin === originURL.origin;
330+
}).length > 0
308331
? "GET"
309332
: "HEAD";
310333

0 commit comments

Comments
 (0)