diff --git a/src/resolver.js b/src/resolver.js index cfd763b..29a96cd 100644 --- a/src/resolver.js +++ b/src/resolver.js @@ -12,6 +12,9 @@ export async function resolve(...paths) { // seems to be an URL, fetch it const resource = last; const response = await fetch(resource); + if (response.status >= 400) { + throw new Error('Not Found'); + } const contentType = response.headers.get('Content-Type'); if (!contentType || !contentType.startsWith('text')) { return await response.buffer(); diff --git a/src/transforms/template-data.js b/src/transforms/template-data.js index b191b55..b42e775 100644 --- a/src/transforms/template-data.js +++ b/src/transforms/template-data.js @@ -88,10 +88,12 @@ export function template(str) { */ export async function handleTemplateFile(config, data, inputFile) { const content = await (config.resolve || resolve)(config.dir.input, inputFile); + if (typeof content === "undefined") { + throw new Error('Not Found'); + } if (content === null) { return null; - } - + } const parsed = path.parse(inputFile); const ext = parsed.ext?.slice(1); if (! config.extensions.has(ext)) { @@ -120,7 +122,11 @@ export async function handleTemplateFile(config, data, inputFile) { const layoutFilePath = path.normalize(path.join(config.dir.layouts, fileData.layout)); const l = await handleTemplateFile(config, {...fileData, content: fileContent, layout: null}, layoutFilePath); - fileContent = l.content; + if (l) { + fileContent = l.content;; + } else { + throw new Error('Layout not found:' + layoutFilePath); + } } return {content: fileContent, filename: outputFile}; diff --git a/tests/resolver.test.js b/tests/resolver.test.js index f72faa9..aa47b55 100644 --- a/tests/resolver.test.js +++ b/tests/resolver.test.js @@ -31,6 +31,7 @@ describe('resolve', () => { headers.set('Content-Type', 'text/css'); return ({ + status: 200, headers, async text() {return ':where(html){}'} }) @@ -43,4 +44,22 @@ describe('resolve', () => { globalThis.fetch = originalFetch; }); + it('should not fetch stuff from the internet when the status code is an error', () => { + const originalFetch = globalThis.fetch; + globalThis.fetch = mock.fn(async () => { + const headers = new Map(); + headers.set('Content-Type', 'text/html'); + return ({ + status: 404, + headers, + async text() {return 'Not Found'} + }) + }); + + assert.rejects(async () => { + await resolve(config.dir.input, 'https://not-found.io/404.html'); + }); + globalThis.fetch = originalFetch; + }); + }); diff --git a/tests/transforms/template-data.test.js b/tests/transforms/template-data.test.js index f97c8fe..8efee55 100644 --- a/tests/transforms/template-data.test.js +++ b/tests/transforms/template-data.test.js @@ -21,11 +21,7 @@ const TEST_DATA = { } } -const TEST_MD = `--- -layout: base.html -author: Lea Rosema ---- -# {{ title }} +const TEST_MD = `# {{ title }} An article by {{ author }} ` @@ -112,13 +108,72 @@ describe('template function', () => { }); }); -describe('handleTemplateFile function', () => { +describe('handleTemplateFile function', {only: true}, () => { + + const withFrontmatter = (str, data) => `---json\n${JSON.stringify(data)}\n---\n${str}` + + it('should work with basic html files without specifying a layout', async () => { + const config = new SissiConfig(); + config.addExtension(md); + + const vFS = new Map(); + vFS.set('index.html', '
An article by Lea Rosema
\n') + }); + + it('should work with the default markdown plugin.', async () => { + const config = new SissiConfig(); + config.addExtension(md); + + const vFS = new Map(); + vFS.set('index.md', withFrontmatter(TEST_MD, {'layout': 'base.html', author: 'Lea Rosema'})); vFS.set('_layouts/base.html', '{{ content }}'); config.resolve = (...paths) => { @@ -131,4 +186,43 @@ describe('handleTemplateFile function', () => { assert.equal(result.filename, 'public/index.html'); assert.equal(result.content, 'An article by Lea Rosema
\n') }); + + it('should throw an error when a non-existant file is specified', async () => { + const config = new SissiConfig(); + config.addExtension(md); + + const vFS = new Map(); + vFS.set('index.md', withFrontmatter(TEST_MD, {'layout': 'notfound.html', author: 'Lea Rosema'})); + + config.resolve = (...paths) => { + const resource = path.normalize(path.join(...paths)); + if (vFS.has(resource)) { + return vFS.get(resource); + } + } + + assert.rejects(async () => { + await handleTemplateFile(config, {title: 'Lea was here'}, 'something-completely-different.md'); + }); + }); + + it('should throw an error when a non-existant file is specified as layout', {only: true}, async () => { + const config = new SissiConfig(); + config.addExtension(md); + + const vFS = new Map(); + vFS.set('index.md', withFrontmatter(TEST_MD, {'layout': 'notfound.html', author: 'Lea Rosema'})); + + config.resolve = (...paths) => { + const resource = path.normalize(path.join(...paths)); + if (vFS.has(resource)) { + return vFS.get(resource); + } + } + + assert.rejects(async () => { + await handleTemplateFile(config, {title: 'Lea was here'}, 'index.md'); + }); + }); + });