course-renderer
Version:
Manages CA School Courses file system storage and HTML conversion
113 lines (112 loc) • 4.35 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const ANNOTATION_MARKER = 0x2F; /* / */
function annotation(reader, silent) {
let pos = reader.getCurrentLineStartPos();
if (reader.getCharCode(pos++) !== ANNOTATION_MARKER
|| reader.getCharCode(pos++) !== ANNOTATION_MARKER
|| reader.getCharCode(pos++) !== ANNOTATION_MARKER) {
return false;
}
if (silent)
return true;
// If we're still here, then we need to parse the annotation line and move the position of the reader cursor
const annotationText = reader.getLine(reader.currentLine);
const parsed = {
type: getType(annotationText),
answer: getAnswer(annotationText),
readonly: getReadonly(annotationText),
caption: getCaption(annotationText),
id: getId(annotationText),
init: getInit(annotationText),
files: getFiles(annotationText),
choiceType: getChoiceType(annotationText),
raw: annotationText
};
if (parsed.type == null) {
throw new Error(`Expecting a 'type' on the annotation but found '${annotationText}`);
}
if ((parsed.type === 'SS' || parsed.type === 'MS' || parsed.type === 'CR') && parsed.id == null) {
throw new Error(`SS, MS and CR questions must have an ID at annotation ${annotationText}`);
}
if (parsed.type !== 'SS' && parsed.type !== 'MS' && parsed.type !== 'CR' && parsed.type !== 'TI' && parsed.type !== 'REPL') {
throw new Error(`Annotation type may only have the following value 'SS', 'MS', 'CR' and 'TI' but found ${parsed.type} at annotation ${annotationText}`);
}
if (parsed.type !== 'REPL' && parsed.answer == null) {
throw new Error(`Annotation type CR, SS, MS and TI must have an answer specified at annotation ${annotationText}`);
}
if (parsed.type === 'REPL' && parsed.answer != null) {
throw new Error(`Annotation type REPL cannot have an answer annotation at ${annotationText}`);
}
if (parsed.type != 'REPL' && parsed.readonly != null) {
throw new Error(`readonly annotation can only be applied to REPL type at ${annotationText}`);
}
if (parsed.type == 'REPL' && parsed.readonly != null && parsed.readonly != 'true') {
throw new Error(`readonly annotation can only support a 'true' value at ${annotationText}`);
}
if (parsed.type == 'SS' && parsed.answer.toString().split(',').length > 1) {
throw new Error(`Annotation type SS must only have a single answer at ${annotationText}`);
}
if (parsed.choiceType != 'TEXT' && parsed.choiceType != 'HTML') {
throw new Error(`choiceType annotation can only support a 'TEXT' and 'HTML' value at ${annotationText}`);
}
reader.nextLine();
return parsed;
}
exports.annotation = annotation;
function getId(annotation) {
const ID_RE = /id=(\w+-\w+-\w+-\w+-\w+)/;
const match = annotation.match(ID_RE);
if (match === null)
return null;
return match[1];
}
function getType(annotation) {
const TYPE_RE = /type=(\w\w(\w\w)?)/;
const match = annotation.match(TYPE_RE);
if (match == null)
return null;
return match[1];
}
function getAnswer(annotation) {
const ANSWER_RE = /answer=\[(.+?)\]/;
const match = annotation.match(ANSWER_RE);
if (match == null)
return null;
return match[1];
}
function getReadonly(annotation) {
const READONLY_RE = /readonly=(\w+)/;
const match = annotation.match(READONLY_RE);
if (match == null)
return null;
return match[1];
}
function getInit(annotation) {
const INITIALIZATION_RE = /init=\[(.+?)\]/;
const match = annotation.match(INITIALIZATION_RE);
if (match == null)
return null;
return match[1];
}
function getCaption(annotation) {
const CAPTION_RE = /caption="(.+)"/;
const match = annotation.match(CAPTION_RE);
if (match == null)
return null;
return match[1];
}
function getFiles(annotation) {
const FILES_RE = /filename=\[(.+?)\]/;
const match = annotation.match(FILES_RE);
if (match == null)
return null;
return match[1];
}
function getChoiceType(annotation) {
const CHOICE_RE = /choiceType=(\w+)/;
const match = annotation.match(CHOICE_RE);
if (match == null)
return 'TEXT';
return match[1];
}