* 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>
		
			
				
	
	
		
			171 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			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
 | 
						|
};
 |