course-renderer
Version:
Manages CA School Courses file system storage and HTML conversion
152 lines (151 loc) • 5.84 kB
JavaScript
;
/**
* @module answer-generator
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs-extra");
const yaml = require("js-yaml");
const path = require("path");
const _ = require("lodash");
const replaceExtension = require('replace-ext');
const { promisify } = require('util');
const read = promisify(fs.readFile);
const append = promisify(fs.appendFile);
const statFile = promisify(fs.stat);
const access = promisify(fs.access);
const readDir = promisify(fs.readdir);
/**
* answerGenerator - Generates an answer.yml file for each course
*/
function answerGenerator(tokens, courseDest, courseSource, callback) {
return __awaiter(this, void 0, void 0, function* () {
const pathSep = path.sep;
const output = path.resolve(courseDest, 'answer.yml');
let answerOutput = {};
try {
let mapping;
try {
yield access(path.resolve(courseSource, 'mapping.json'), fs.constants.F_OK);
mapping = JSON.parse(yield read(path.resolve(courseSource, 'mapping.json'), 'utf-8'));
}
catch (e) {
mapping = {};
}
yield createTokensAnswer(tokens, answerOutput, courseSource, mapping);
if (!_.isEmpty(answerOutput)) {
yield append(output, yaml.safeDump(answerOutput));
}
callback(null, tokens);
}
catch (e) {
callback(e);
}
});
}
exports.answerGenerator = answerGenerator;
function createTokensAnswer(tokens, answerOutput, courseSource, mapping) {
return __awaiter(this, void 0, void 0, function* () {
for (let token of tokens) {
if (token.children instanceof Array) {
yield createTokensAnswer(token.children, answerOutput, courseSource, mapping);
}
else if (token.type && token.type !== 'text' && token.type !== 'REPL') {
const answer = createTokenAnswer(token);
if (token.type === 'CR') {
answer.hint = yield getQuestionHint(courseSource, answer.answer, token.id);
}
else if (token.type === 'MS') {
// Sort MS answer just in case the authors did not sort the answer on the annotation. The reader is expecting a sorted answer
const answers = answer.answer.split(',');
answers.sort((a, b) => {
return a - b;
});
answer.answer = answers.join(',');
}
delete token.answer;
if (mapping[token.id]) {
answer.provisionedId = mapping[token.id];
1;
}
answerOutput[token.id] = answer;
}
}
});
}
function createTokenAnswer(token) {
return {
text: token.content,
chapter: token.chapter,
answer: token.answer,
type: token.type
};
}
function readHintFile(hintFile) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield read(hintFile, 'utf-8');
}
catch (e) {
console.log(e);
throw new Error(`Unable to read Proof file ${hintFile}: ${e.message}`);
}
});
}
function hintFileExists(hintFile) {
return __awaiter(this, void 0, void 0, function* () {
try {
const stat = yield statFile(hintFile);
return true;
}
catch (e) {
return false;
}
});
}
function readHintDirectory(hintDirectory) {
return __awaiter(this, void 0, void 0, function* () {
try {
const files = yield readDir(hintDirectory);
if (files.length == 0) {
throw new Error(`Hint directory ${hintDirectory} is empty`);
}
const hints = [];
for (let i = 0; i < files.length; i++) {
const file = path.resolve(hintDirectory, files[i]);
const content = yield read(file, 'utf-8');
hints.push({ fileName: files[i], answer: content });
}
return hints;
}
catch (e) {
throw e;
}
});
}
function getQuestionHint(source, answerPath, id) {
return __awaiter(this, void 0, void 0, function* () {
let hintFile = path.resolve(source, answerPath.replace(/^tests/, 'answers'));
if (yield hintFileExists(hintFile)) {
const fileName = path.basename(hintFile);
return [{ fileName: fileName, answer: yield readHintFile(hintFile) }];
}
else if (yield hintFileExists(replaceExtension(hintFile, ''))) {
hintFile = replaceExtension(hintFile, '');
const fileName = path.basename(hintFile);
return [{ fileName: fileName, answer: yield readHintFile(hintFile) }];
}
else {
// Assume the hint is in a directory
const hintPath = path.resolve(path.dirname(path.resolve(source, answerPath.replace(/^tests/, 'answers'))), id);
return yield readHintDirectory(hintPath);
}
});
}