Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remark-lint-local-links-valid 모노레포화 #434

Merged
merged 10 commits into from
May 2, 2024
4 changes: 3 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ jobs:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 8
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install
- run: pnpm typecheck
- run: pnpm eslint .
env:
NODE_OPTIONS: '--loader ts-node/esm'
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@
"[mdx]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.rulers": [100]
}
},
"eslint.runtime": "./ts-node-eslint"
}
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
"private": true,
"type": "module",
"license": "AGPL-3.0-or-later",
"repository": "https://github.com/portone-io/developers.portone.io",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"check": "pnpm typecheck && pnpm lint",
"typecheck": "astro check",
"lint:fix": "eslint --fix .",
"lint": "eslint .",
"lint:fix": "NODE_OPTIONS=\"$NODE_OPTIONS --loader ts-node/esm\" eslint --fix .",
"lint": "NODE_OPTIONS=\"$NODE_OPTIONS --loader ts-node/esm\" eslint .",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
Expand Down Expand Up @@ -106,7 +107,7 @@
"remark-lint-list-item-content-indent": "^3.1.2",
"remark-lint-list-item-indent": "^3.1.2",
"remark-lint-list-item-spacing": "^4.1.2",
"remark-lint-local-links-valid": "github:portone-io/remark-lint-local-links-valid",
"remark-lint-local-links-valid": "workspace:^",
"remark-lint-maximum-line-length": "^3.1.3",
"remark-lint-no-blockquote-without-marker": "^5.1.2",
"remark-lint-no-consecutive-blank-lines": "^4.1.3",
Expand Down Expand Up @@ -142,14 +143,15 @@
"satori": "^0.10.13",
"sharp": "^0.33.3",
"string-width": "^5.1.2",
"ts-node": "^10.9.2",
Copy link
Member Author

@CirnoV CirnoV Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsx를 사용했을 때 여전히 import 오류가 발생해서 ts-node로 구현했습니다

"ts-pattern": "^5.1.1",
"typescript": "^5.4.5",
"unified": "^11.0.4",
"unist-util-visit": "^5.0.0",
"universal-cookie": "^7.1.4",
"unocss": "^0.59.4"
},
"packageManager": "[email protected].5",
"packageManager": "[email protected].6",
"pnpm": {
"patchedDependencies": {
"@shikijs/[email protected]": "patches/@[email protected]",
Expand Down
1 change: 1 addition & 0 deletions packages/remark-lint-local-links-valid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## remark-lint-local-links-valid
17 changes: 17 additions & 0 deletions packages/remark-lint-local-links-valid/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "remark-lint-local-links-valid",
"version": "0.1.1",
"repository": "https://github.com/portone-io/developers.portone.io",
"type": "module",
"private": true,
"main": "src/index.ts",
"scripts": {},
"dependencies": {
"unified-lint-rule": "^3.0.0",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@types/node": "^20.12.7"
},
"packageManager": "[email protected]"
}
82 changes: 82 additions & 0 deletions packages/remark-lint-local-links-valid/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import fs from "node:fs/promises";
import path from "node:path";

import { lintRule } from "unified-lint-rule";
import { visit } from "unist-util-visit";

interface Options {
baseDir: string;
excludePaths: string[];
redirects: Record<string, string>;
}
const remarkLintLocalLinksValid = lintRule(
"remark-lint:local-links-valid",
async (tree, file, options: Partial<Options>) => {
if (!options.baseDir) {
throw new Error("Missing required option `baseDir`");
}
const baseDir = path.resolve(options.baseDir);
const filePath = path.resolve(file.cwd, file.history[0] ?? "");
const excludePaths =
options.excludePaths?.map((p) => path.join(baseDir, p)) ?? [];
const redirects = options.redirects ?? {};
const tasks: Promise<void>[] = [];
visit(tree, (node) => {
if (
"url" in node &&
typeof node.url === "string" &&
node.type === "link" &&
isLocalLink(node.url)
) {
const url = node.url.split(/[#?]/)[0] || "";
let absPath = "";
if (path.isAbsolute(url)) {
absPath = path.join(baseDir, url);
} else {
absPath = path.join(path.dirname(filePath), url);
}
const resolvedPath = resolveRedirect(
redirects,
path.relative(baseDir, absPath),
);
if (isLocalLink(resolvedPath) === false) {
return;
}
absPath = path.join(baseDir, resolvedPath);
if (excludePaths.some((p) => absPath.startsWith(p))) {
return;
}
if (path.extname(absPath) !== "") {
file.message("Local link should not have an extension", node);
return;
}
const task = Promise.any(
[".md", ".mdx"].map((ext) => fs.access(absPath + ext)),
).catch(() => {
file.message(`File not found: ${absPath}`, node);
});
tasks.push(task);
}
});
await Promise.all(tasks);
},
);
const isLocalLink = (url: string): boolean => {
try {
new URL(url);
} catch {
return true;
}
return false;
};
const resolveRedirect = (
redirects: Record<string, string>,
url: string,
): string => {
let resolved = url;
while (redirects[resolved]) {
resolved = redirects[resolved]?.split(/[#?]/)[0] ?? resolved;
}
return resolved;
};
export default remarkLintLocalLinksValid;
13 changes: 13 additions & 0 deletions packages/remark-lint-local-links-valid/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"include": ["src"]
}
Loading