feat: conditionally include files (#42205)

Co-authored-by: Shaun Hamilton <51722130+ShaunSHamilton@users.noreply.github.com>
pull/42379/head
Oliver Eyton-Williams 2021-06-05 20:15:13 +02:00 committed by GitHub
parent 7b65909522
commit 440169a7cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 113 additions and 5 deletions

View File

@ -56,6 +56,18 @@ export const cssToHtml = cond([
[stubTrue, identity]
]);
export function findIndexHtml(files) {
const filtered = files.filter(file => wasHtmlFile(file));
if (filtered.length > 1) {
throw new Error('Too many html blocks in the challenge seed');
}
return filtered[0];
}
function wasHtmlFile(file) {
return file.history[0] === 'index.html';
}
export function concatHtml({ required = [], template, files = [] } = {}) {
const createBody = template ? _template(template) : defaultTemplate;
const head = required
@ -75,10 +87,19 @@ A required file can not have both a src and a link: src = ${src}, link = ${link}
})
.reduce((head, element) => head.concat(element));
const source = files.reduce(
(source, file) => source.concat(file.contents, htmlCatch),
''
);
const indexHtml = findIndexHtml(files);
const source = files.reduce((source, file) => {
if (!indexHtml) return source.concat(file.contents, htmlCatch);
if (
indexHtml.importedFiles.includes(file.history[0]) ||
wasHtmlFile(file)
) {
return source.concat(file.contents, htmlCatch);
} else {
return source;
}
}, '');
return `<head>${head}</head>${createBody({ source })}`;
}

View File

@ -0,0 +1,46 @@
/* global expect */
import { findIndexHtml } from './builders.js';
const withHTML = [
{ history: ['index.html'], contents: 'the index html' },
{ history: ['index.css', 'index.html'], contents: 'the style file' }
];
const withoutHTML = [
{ history: ['index.css', 'index.html'], contents: 'the js file' },
{ history: ['index.js', 'index.html'], contents: 'the style file' }
];
const tooMuchHTML = [
{ history: ['index.html'], contents: 'the index html' },
{ history: ['index.css', 'index.html'], contents: 'index html two' },
{ history: ['index.html'], contents: 'index html three' }
];
// TODO: write tests for concatHtml instead, since findIndexHtml should not be
// exported.
describe('findIndexHtml', () => {
it('should return the index.html file from an array', () => {
expect.assertions(1);
expect(findIndexHtml(withHTML)).toStrictEqual({
history: ['index.html'],
contents: 'the index html'
});
});
it('should return undefined when the index.html file is missing', () => {
expect.assertions(1);
expect(findIndexHtml(withoutHTML)).toBeUndefined();
});
it('should throw if there are two or more index.htmls', () => {
expect.assertions(1);
expect(() => findIndexHtml(tooMuchHTML)).toThrowError(
'Too many html blocks in the challenge seed'
);
});
});

View File

@ -16,6 +16,7 @@ import {
transformContents,
transformHeadTailAndContents,
setExt,
setImportedFiles,
compileHeadTail
} from '../../../../../utils/polyvinyl';
import createWorker from '../utils/worker-executor';
@ -213,6 +214,35 @@ const transformHtml = async function (file) {
return transformContents(() => div.innerHTML, file);
};
// Find if the base html refers to the css or js files and record if they do. If
// the link or script exists we remove those elements since those files don't
// exist on the site, only in the editor
const transformIncludes = async function (fileP) {
const file = await fileP;
const div = document.createElement('div');
div.innerHTML = file.contents;
const link =
div.querySelector('link[href="styles.css"]') ??
div.querySelector('link[href="./styles.css"]');
const script =
div.querySelector('script[src="script.js"]') ??
div.querySelector('script[src="./script.js"]');
const importedFiles = [];
if (link) {
importedFiles.push('index.css');
link.remove();
}
if (script) {
importedFiles.push('index.js');
script.remove();
}
return flow(
partial(setImportedFiles, importedFiles),
partial(transformContents, () => div.innerHTML)
)(file);
};
export const composeHTML = cond([
[
testHTML,
@ -229,7 +259,7 @@ export const composeHTML = cond([
]);
export const htmlTransformer = cond([
[testHTML, transformHtml],
[testHTML, flow(transformHtml, transformIncludes)],
[stubTrue, identity]
]);

View File

@ -87,6 +87,16 @@ function setExt(ext, poly) {
return newPoly;
}
// setImportedFiles(importedFiles: String[], poly: PolyVinyl) => PolyVinyl
function setImportedFiles(importedFiles, poly) {
checkPoly(poly);
const newPoly = {
...poly,
importedFiles: [...importedFiles]
};
return newPoly;
}
// clearHeadTail(poly: PolyVinyl) => PolyVinyl
function clearHeadTail(poly) {
checkPoly(poly);
@ -139,6 +149,7 @@ module.exports = {
isPoly,
setContent,
setExt,
setImportedFiles,
compileHeadTail,
transformContents,
transformHeadTailAndContents