Files
freeCodeCamp/utils/polyvinyl.js
Oliver Eyton-Williams c11bd163b2 feat: display multifile projects (#45220)
* refactor: DRY up certification and ProjectModal

* fix: use sensible keys for SolutionViewer

* refactor: handle legacy solutions like new ones

* refactor: correct CompletedChallenge type

* fix: store challengeType for multifile projects

* fix: use challengeType to set display type

* feat: use dropdown to display project + code

* refactor: isOpen -> showCode to avoid a clash

We need to be able both show the code and show the completed project

* refactor: remove redundant parts of projectPreview

* refactor: fix project preview types

* feat: wip, using existing modal to show project

* feat: show projects on timeline

* feat: display projects on time-line

* chore: use consistent case for GitHub

* fix(a11y): translate show solution/view

* refactor: rename showFilesSolution

* refactor: use self-closing tag

* fix: remove hardcoding (certification + timeline)

* fix: remove hardcoding (settings)

* test: supply store and mock ga

* fix: include challengeType for projects

Co-authored-by: Tom <20648924+moT01@users.noreply.github.com>

* refactor: remove space

Co-authored-by: Tom <20648924+moT01@users.noreply.github.com>

* fix: key -> filekey on challenge submission

* fix: handle submissions without files

Co-authored-by: Tom <20648924+moT01@users.noreply.github.com>
2022-03-02 19:49:54 -06:00

171 lines
3.8 KiB
JavaScript

// originally based off of https://github.com/gulpjs/vinyl
const invariant = require('invariant');
// interface PolyVinyl {
// source: String,
// contents: String,
// name: String,
// ext: String,
// path: String,
// key: String,
// head: String,
// tail: String,
// history: [...String],
// error: Null|Object|Error
// }
// createPoly({
// name: String,
// ext: String,
// contents: String,
// history?: [...String],
// }) => PolyVinyl, throws
function createPoly({ name, ext, contents, history, ...rest } = {}) {
invariant(typeof name === 'string', 'name must be a string but got %s', name);
invariant(typeof ext === 'string', 'ext must be a string, but was %s', ext);
invariant(
typeof contents === 'string',
'contents must be a string but got %s',
contents
);
return {
...rest,
history: Array.isArray(history) ? history : [name + '.' + ext],
name,
ext,
path: name + '.' + ext,
fileKey: name + ext,
contents,
error: null
};
}
// isPoly(poly: Any) => Boolean
function isPoly(poly) {
return (
poly &&
typeof poly.contents === 'string' &&
typeof poly.name === 'string' &&
typeof poly.ext === 'string' &&
Array.isArray(poly.history)
);
}
// checkPoly(poly: Any) => Void, throws
function checkPoly(poly) {
invariant(
isPoly(poly),
'function should receive a PolyVinyl, but got %s',
poly
);
}
// setContent(contents: String, poly: PolyVinyl) => PolyVinyl
// setContent will loose source if set
function setContent(contents, poly) {
checkPoly(poly);
return {
...poly,
contents,
source: null
};
}
// setExt(ext: String, poly: PolyVinyl) => PolyVinyl
function setExt(ext, poly) {
checkPoly(poly);
const newPoly = {
...poly,
ext,
path: poly.name + '.' + ext,
fileKey: poly.name + ext
};
newPoly.history = [...poly.history, newPoly.path];
return newPoly;
}
// setImportedFiles(importedFiles: String[], poly: PolyVinyl) => PolyVinyl
function setImportedFiles(importedFiles, poly) {
checkPoly(poly);
const newPoly = {
...poly,
importedFiles: [...importedFiles]
};
return newPoly;
}
// This is currently only used to add back properties that are not stored in the
// database.
function regeneratePathAndHistory(poly) {
const newPath = poly.name + '.' + poly.ext;
const newPoly = {
...poly,
path: newPath,
history: [newPath]
};
checkPoly(newPoly);
return newPoly;
}
// clearHeadTail(poly: PolyVinyl) => PolyVinyl
function clearHeadTail(poly) {
checkPoly(poly);
return {
...poly,
head: '',
tail: ''
};
}
// compileHeadTail(padding: String, poly: PolyVinyl) => PolyVinyl
function compileHeadTail(padding = '', poly) {
return clearHeadTail(
transformContents(
() => [poly.head, poly.contents, poly.tail].join(padding),
poly
)
);
}
// transformContents(
// wrap: (contents: String) => String,
// poly: PolyVinyl
// ) => PolyVinyl
// transformContents will keep a copy of the original
// code in the `source` property. If the original polyvinyl
// already contains a source, this version will continue as
// the source property
function transformContents(wrap, poly) {
const newPoly = setContent(wrap(poly.contents), poly);
// if no source exist, set the original contents as source
newPoly.source = poly.source || poly.contents;
return newPoly;
}
// transformHeadTailAndContents(
// wrap: (source: String) => String,
// poly: PolyVinyl
// ) => PolyVinyl
function transformHeadTailAndContents(wrap, poly) {
return {
...transformContents(wrap, poly),
head: wrap(poly.head),
tail: wrap(poly.tail)
};
}
module.exports = {
createPoly,
isPoly,
setContent,
setExt,
setImportedFiles,
compileHeadTail,
regeneratePathAndHistory,
transformContents,
transformHeadTailAndContents
};