feat: conditionally include files (#42205)
Co-authored-by: Shaun Hamilton <51722130+ShaunSHamilton@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
7b65909522
commit
440169a7cb
@ -56,6 +56,18 @@ export const cssToHtml = cond([
|
|||||||
[stubTrue, identity]
|
[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 = [] } = {}) {
|
export function concatHtml({ required = [], template, files = [] } = {}) {
|
||||||
const createBody = template ? _template(template) : defaultTemplate;
|
const createBody = template ? _template(template) : defaultTemplate;
|
||||||
const head = required
|
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));
|
.reduce((head, element) => head.concat(element));
|
||||||
|
|
||||||
const source = files.reduce(
|
const indexHtml = findIndexHtml(files);
|
||||||
(source, file) => source.concat(file.contents, htmlCatch),
|
|
||||||
''
|
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 })}`;
|
return `<head>${head}</head>${createBody({ source })}`;
|
||||||
}
|
}
|
||||||
|
46
client/src/templates/Challenges/rechallenge/builders.test.js
Normal file
46
client/src/templates/Challenges/rechallenge/builders.test.js
Normal 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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -16,6 +16,7 @@ import {
|
|||||||
transformContents,
|
transformContents,
|
||||||
transformHeadTailAndContents,
|
transformHeadTailAndContents,
|
||||||
setExt,
|
setExt,
|
||||||
|
setImportedFiles,
|
||||||
compileHeadTail
|
compileHeadTail
|
||||||
} from '../../../../../utils/polyvinyl';
|
} from '../../../../../utils/polyvinyl';
|
||||||
import createWorker from '../utils/worker-executor';
|
import createWorker from '../utils/worker-executor';
|
||||||
@ -213,6 +214,35 @@ const transformHtml = async function (file) {
|
|||||||
return transformContents(() => div.innerHTML, 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([
|
export const composeHTML = cond([
|
||||||
[
|
[
|
||||||
testHTML,
|
testHTML,
|
||||||
@ -229,7 +259,7 @@ export const composeHTML = cond([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export const htmlTransformer = cond([
|
export const htmlTransformer = cond([
|
||||||
[testHTML, transformHtml],
|
[testHTML, flow(transformHtml, transformIncludes)],
|
||||||
[stubTrue, identity]
|
[stubTrue, identity]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -87,6 +87,16 @@ function setExt(ext, poly) {
|
|||||||
return newPoly;
|
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
|
// clearHeadTail(poly: PolyVinyl) => PolyVinyl
|
||||||
function clearHeadTail(poly) {
|
function clearHeadTail(poly) {
|
||||||
checkPoly(poly);
|
checkPoly(poly);
|
||||||
@ -139,6 +149,7 @@ module.exports = {
|
|||||||
isPoly,
|
isPoly,
|
||||||
setContent,
|
setContent,
|
||||||
setExt,
|
setExt,
|
||||||
|
setImportedFiles,
|
||||||
compileHeadTail,
|
compileHeadTail,
|
||||||
transformContents,
|
transformContents,
|
||||||
transformHeadTailAndContents
|
transformHeadTailAndContents
|
||||||
|
Reference in New Issue
Block a user