Skip to content

Commit

Permalink
perf: parse matter only with files
Browse files Browse the repository at this point in the history
  • Loading branch information
fuma-nama committed Nov 4, 2024
1 parent 2942597 commit 873a9a3
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 58 deletions.
5 changes: 5 additions & 0 deletions .changeset/eight-wombats-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'next-validate-link': patch
---

parse frontmatter only with files
14 changes: 8 additions & 6 deletions src/check-external-url.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
export async function checkExternalUrl(url: string): Promise<boolean> {
import type { ErrorReason } from './validate';

export async function checkExternalUrl(
url: string,
): Promise<ErrorReason | undefined> {
const parsed = new URL(url);
if (parsed.hostname === 'localhost') return true;
if (parsed.hostname === 'localhost') return;

const res = await fetch(parsed, {
method: 'HEAD',
}).catch(() => undefined);

if (!res) return false;
if (!res) return 'not-found';

if (!res.ok) {
if (res.status === 404) return false;
if (res.status === 404) return 'not-found';

console.warn(`${url} responded status ${res.status}, is it expected?`);
}

return true;
}
22 changes: 20 additions & 2 deletions src/sample.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
import path from 'node:path';
import fs from 'node:fs/promises';
import FastGlob, { type Pattern } from 'fast-glob';
import type { FileObject } from './validate';
import matter from 'gray-matter';

export async function readFileFromPath(file: string) {
export async function readFileFromPath(file: string): Promise<
FileObject & {
data?: object;
}
> {
const content = await fs
.readFile(path.resolve(file))
.then((res) => res.toString());

const parsed = matter(content);

return {
path: file,
content: content,
data: parsed.data,
content: parsed.content,
};
}

export async function readFiles(
patterns: Pattern | Pattern[],
): Promise<FileObject[]> {
const files = await FastGlob(patterns);

return await Promise.all(files.map(readFileFromPath));
}
7 changes: 0 additions & 7 deletions src/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@ type UrlMeta = {

const defaultMeta = {};
const defaultPopulate: PopulateParams[string] = [{}];
const defaultPopulateOptional: PopulateParams[string] = [
{},
{
// case when it's empty
value: [],
},
];

export async function scanURLs(options: ScanOptions): Promise<ScanResult> {
async function getFiles() {
Expand Down
40 changes: 15 additions & 25 deletions src/validate.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { readFile } from 'node:fs/promises';
import { remark } from 'remark';
import { visit } from 'unist-util-visit';
import type { ScanResult } from '@/scan';
import path from 'node:path';
import matter from 'gray-matter';
import * as path from 'node:path';
import { checkExternalUrl } from './check-external-url';
import remarkGfm from 'remark-gfm';
import { readFileFromPath } from './sample';

const processor = remark().use(remarkGfm);

Expand All @@ -14,8 +13,8 @@ export type ValidateError = {
detected: DetectedError[];
};

type ErrorReason = 'not-found' | 'invalid-fragment' | 'invalid-query';
type DetectedError = [
export type ErrorReason = 'not-found' | 'invalid-fragment' | 'invalid-query';
export type DetectedError = [
url: string,
line: number,
column: number,
Expand Down Expand Up @@ -50,12 +49,12 @@ export type ValidateConfig = {
checkExternal?: boolean;
};

type File =
| string
| {
path: string;
content: string;
};
export type FileObject = {
path: string;
content: string;

data?: object;
};

/**
* Validate markdown files
Expand All @@ -64,21 +63,14 @@ type File =
* @param config - configurations
*/
export async function validateFiles(
files: File[],
files: (string | FileObject)[],
config: ValidateConfig,
): Promise<ValidateError[]> {
const mdExtensions = ['.md', '.mdx'];

async function run(file: File): Promise<ValidateError> {
async function run(file: string | FileObject): Promise<ValidateError> {
const finalFile =
typeof file === 'string'
? {
path: file,
content: await readFile(file)
.then((res) => res.toString())
.catch(() => ''),
}
: file;
typeof file === 'string' ? await readFileFromPath(file) : file;

if (!mdExtensions.includes(path.extname(finalFile.path))) {
console.warn(
Expand All @@ -103,7 +95,7 @@ export async function validateMarkdown(
content: string,
config: ValidateConfig,
) {
const tree = processor.parse({ value: matter({ content }).content });
const tree = processor.parse({ value: content });
const detected: DetectedError[] = [];
const tasks: Promise<void>[] = [];

Expand Down Expand Up @@ -132,9 +124,7 @@ export async function detect(
): Promise<ErrorReason | undefined> {
if (href.match(/https?:\/\//)) {
if (config.checkExternal) {
const isValid = await checkExternalUrl(href);

if (!isValid) return 'not-found';
return await checkExternalUrl(href);
}

return;
Expand Down
18 changes: 0 additions & 18 deletions test/validate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,6 @@ test('validate links: valid', async () => {
).lengthOf(0, 'no error');
});

test('validate links: valid with frontmatter', async () => {
expect(
await validateFiles(
[
{
path: 'a.md',
content: `---
title: hello world [hello](/sfd)
---
[hello](/)`,
},
],
{ scanned },
),
).lengthOf(0, 'no error');
});

test('validate links: not found', async () => {
expect(
await validateFiles(
Expand Down

0 comments on commit 873a9a3

Please sign in to comment.