Skip to content

Commit a8da3de

Browse files
Show an error if there’s a file with no extension (#437)
This aims to help catch a common error: people adding a markdown file for a post but forgetting to add the `.md` file extension. If a file is found, the build will fail with an helpful error.
1 parent e0bb463 commit a8da3de

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

eleventy.config.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import fs from 'node:fs/promises'
2+
import path from 'node:path'
23

34
import { nhsukEleventyPlugin } from '@x-govuk/nhsuk-eleventy-plugin'
45

6+
import { findFileWithoutExtension } from './lib/find-file-without-extension.js'
7+
58
const serviceName = 'Digital prevention services design history'
69

710
export default function (eleventyConfig) {
@@ -174,6 +177,17 @@ export default function (eleventyConfig) {
174177

175178
// Reset contents of output directory before each build
176179
eleventyConfig.on('eleventy.before', async ({ directories, runMode }) => {
180+
// Check for files without extensions in the app directory
181+
const fileWithoutExtension = await findFileWithoutExtension(
182+
directories.input
183+
)
184+
185+
if (fileWithoutExtension) {
186+
throw new Error(
187+
`Found file called '${path.basename(fileWithoutExtension)}' without an extension. Did you forget to add .md to it?\nFile path: ${fileWithoutExtension}`
188+
)
189+
}
190+
177191
if (runMode === 'build') {
178192
await fs.rm(directories.output, {
179193
force: true,

lib/find-file-without-extension.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import fs from 'node:fs/promises'
2+
import path from 'node:path'
3+
4+
/**
5+
* Recursively find the first file without an extension in a directory
6+
*
7+
* @param {string} dir - Directory to search
8+
* @returns {Promise<string|null>} - Path of first file without extension, or null
9+
*/
10+
export async function findFileWithoutExtension(dir) {
11+
async function scan(currentDir) {
12+
const entries = await fs.readdir(currentDir, { withFileTypes: true })
13+
14+
for (const entry of entries) {
15+
const fullPath = path.join(currentDir, entry.name)
16+
17+
if (entry.isDirectory()) {
18+
// Skip directories starting with underscore (e.g. _layouts, _components)
19+
if (!entry.name.startsWith('_')) {
20+
const found = await scan(fullPath)
21+
if (found) return found
22+
}
23+
} else if (entry.isFile()) {
24+
// Skip hidden files (e.g. .gitkeep)
25+
if (!entry.name.startsWith('.')) {
26+
// Check if the file has no extension
27+
const ext = path.extname(entry.name)
28+
if (ext === '') {
29+
return fullPath
30+
}
31+
}
32+
}
33+
}
34+
return null
35+
}
36+
37+
return scan(dir)
38+
}

0 commit comments

Comments
 (0)