Skip to content

Commit

Permalink
feat: add support for validating emitted file assets
Browse files Browse the repository at this point in the history
  • Loading branch information
HiDeoo committed Aug 26, 2023
1 parent f6bd50a commit 675dd08
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 8 deletions.
4 changes: 2 additions & 2 deletions packages/starlight-links-validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export default function starlightLinksValidatorIntegration(): AstroIntegration {
},
})
},
'astro:build:done': ({ pages }) => {
const errors = validateLinks(pages)
'astro:build:done': ({ dir, pages }) => {
const errors = validateLinks(pages, dir)

logErrors(errors)

Expand Down
39 changes: 35 additions & 4 deletions packages/starlight-links-validator/libs/validation.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { statSync } from 'node:fs'
import { fileURLToPath } from 'node:url'

import { bgGreen, black, bold, cyan, dim, red } from 'kleur/colors'

import { getValidationData, type Headings } from './remark'

export function validateLinks(pages: PageData[]): ValidationErrors {
export function validateLinks(pages: PageData[], outputDir: URL): ValidationErrors {
process.stdout.write(`\n${bgGreen(black(` validating links `))}\n`)

const { headings, links } = getValidationData()
Expand All @@ -15,7 +18,7 @@ export function validateLinks(pages: PageData[]): ValidationErrors {
if (link.startsWith('#')) {
validateSelfAnchor(errors, link, filePath, headings)
} else {
validateLink(errors, link, filePath, headings, allPages)
validateLink(errors, link, filePath, headings, allPages, outputDir)
}
}
}
Expand Down Expand Up @@ -58,7 +61,14 @@ export function logErrors(errors: ValidationErrors) {
/**
* Validate a link to another internal page that may or may not have a hash.
*/
function validateLink(errors: ValidationErrors, link: string, filePath: string, headings: Headings, pages: Pages) {
function validateLink(
errors: ValidationErrors,
link: string,
filePath: string,
headings: Headings,
pages: Pages,
outputDir: URL
) {
const sanitizedLink = link.replace(/^\//, '')
const segments = sanitizedLink.split('#')

Expand All @@ -67,7 +77,13 @@ function validateLink(errors: ValidationErrors, link: string, filePath: string,

if (path === undefined) {
throw new Error('Failed to validate a link with no path.')
} else if (path.length > 0 && !path.endsWith('/')) {
}

if (isValidAsset(path, outputDir)) {
return
}

if (path.length > 0 && !path.endsWith('/')) {
path += '/'
}

Expand Down Expand Up @@ -100,6 +116,21 @@ function validateSelfAnchor(errors: ValidationErrors, hash: string, filePath: st
}
}

/**
* Check if a link is a valid asset in the build output directory.
*/
function isValidAsset(path: string, outputDir: URL) {
const filePath = fileURLToPath(new URL(path, outputDir))

try {
const stats = statSync(filePath)

return stats.isFile()
} catch {
return false
}
}

function addError(errors: ValidationErrors, filePath: string, link: string) {
const fileErrors = errors.get(filePath) ?? []
fileErrors.push(link)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ some content
test
</a>
</div>

<a href="/icon.svg">Link to invalid asset</a>
<a href="/guidelines/ui.pdf">Link to another invalid asset</a>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ title: Test
- [Link to invalid anchor in this page](#links)
- [Link to valid anchor in another MDX page](/guides/example/#some-links)
- [Link to invalid anchor in another MDX page](/guides/example/#links)
- [Link to invalid asset](/icon.svg)
- [Link to another invalid asset](/guidelines/ui.pdf)

<div id="aDiv">
some content
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ some content
test text
</a>
</div>

<a href="/favicon.svg">Link to an asset</a>
<a href="/guidelines/dummy.pdf">Link to another asset</a>
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ title: Index

- [Link to anchor in this page](#some-links)
- [Link to anchor in another MDX page](/guides/example/#some-links)
- [Link to an asset](/favicon.svg)
- [Link to another asset](/guidelines/dummy.pdf)

## A more `complex` heading

Expand Down
1 change: 1 addition & 0 deletions packages/starlight-links-validator/tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export async function loadFixture(name: string) {

// Copy the base fixture files.
await cp(join(baseFixturePath, 'src'), join(testPath, 'src'), { recursive: true })
await cp(join(baseFixturePath, 'public'), join(testPath, 'public'), { recursive: true })

// Copy the fixture under test files that may override the base fixture files.
await cp(join(fixturePath, 'src'), join(testPath, 'src'), { force: true, recursive: true })
Expand Down
8 changes: 6 additions & 2 deletions packages/starlight-links-validator/tests/validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ test('should not build with invalid links', async () => {
try {
await loadFixture('with-invalid-links')
} catch (error) {
expect(error).toMatch(/Found 14 invalid links in 3 files./)
expect(error).toMatch(/Found 18 invalid links in 3 files./)

expect(error).toMatch(
new RegExp(`▶ test/
Expand All @@ -27,6 +27,8 @@ test('should not build with invalid links', async () => {
├─ /unknown/#title
├─ #links
├─ /guides/example/#links
├─ /icon.svg
├─ /guidelines/ui.pdf
└─ #anotherDiv`)
)

Expand All @@ -35,7 +37,9 @@ test('should not build with invalid links', async () => {
├─ #links
├─ /unknown/#links
├─ /unknown
└─ #anotherBlock`)
├─ #anotherBlock
├─ /icon.svg
└─ /guidelines/ui.pdf`)
)

expect(error).toMatch(
Expand Down

0 comments on commit 675dd08

Please sign in to comment.