course-renderer
Version:
Manages CA School Courses file system storage and HTML conversion
163 lines (120 loc) • 5.21 kB
text/typescript
import Token from '../Token'
import Reader from '../reader'
import * as rules from '../rules'
import { AnnotationInterface } from '../rules/annotation'
import { HandlerOptionInterface } from './HandlerOptionInterface'
const MARKER_CODE = 0x2F/* / */
export function question(reader: Reader, tokens: Token[], silent: boolean = false, options: HandlerOptionInterface): boolean {
if (!rules.annotation(reader, true)) return false
if (silent) return true
const parsedAnnotation = rules.annotation(reader, false)
reader.skipEmptyLines()
if (parsedAnnotation.type === 'CR') {
tokenizeCR(reader, tokens, parsedAnnotation, options)
} else if (parsedAnnotation.type === 'SS' || parsedAnnotation.type === 'MS') {
tokenizeOption(reader, tokens, parsedAnnotation, options)
} else if (parsedAnnotation.type === 'TI') {
tokenizeTI(reader, tokens, parsedAnnotation, options)
}
return true
}
function tokenizeCR(reader: Reader, tokens: Token[], parsedAnnotation: AnnotationInterface, options: HandlerOptionInterface) {
if (rules.fence(reader, tokens, true, options )) throw new Error(`A CR question must not start with a fence markup at line ${reader.currentLine + 1}`)
const label = getLabel(reader, parsedAnnotation, options)
const token = new Token(parsedAnnotation.type)
token.setContent(label)
token.setAnswer(parsedAnnotation.answer)
token.setId(parsedAnnotation.id)
if (parsedAnnotation.init != null) {
token.setInitialization(parsedAnnotation.init)
}
if (parsedAnnotation.files != null) {
const files = parsedAnnotation.files.split(/,\s*/);
files.forEach((file: string) => {
token.addFile(file)
});
}
appendToken(tokens, token, options)
reader.nextNonEmptyLines()
rules.fence(reader, tokens, false, options)
// Let us check if there is another fence block after this.
while(true) {
reader.nextNonEmptyLines();
if (rules.fence(reader, tokens, true, options)) {
rules.fence(reader, tokens, false, options);
continue;
}
break;
}
//reader.nextNonEmptyLines()
}
function tokenizeOption(reader: Reader, tokens: Token[], parsedAnnotation: AnnotationInterface, options: HandlerOptionInterface) {
if (rules.option(reader, tokens, true, options)) throw new Error(`SS or MS question must not start with an option marker at line ${reader.currentLine + 1}`)
const label = getLabel(reader, parsedAnnotation, options)
const token = new Token(parsedAnnotation.type)
token.setContent(label)
token.setAnswer(parsedAnnotation.answer)
token.setId(parsedAnnotation.id)
token.setChoiceType(parsedAnnotation.choiceType);
if (parsedAnnotation.init != null) {
token.setInitialization(parsedAnnotation.init)
}
appendToken(tokens, token, options)
reader.nextNonEmptyLines()
while(!reader.isEnd()) {
if (rules.option(reader, tokens, true, options)) {
rules.option(reader, tokens, false, options)
reader.nextNonEmptyLines()
} else {
break
}
}
}
function tokenizeTI(reader: Reader, tokens: Token[], parsedAnnotation: AnnotationInterface, options: HandlerOptionInterface) {
const label = getLabel(reader, parsedAnnotation, options)
const token = new Token(parsedAnnotation.type)
token.setContent(label)
token.setAnswer(parsedAnnotation.answer)
token.setId(parsedAnnotation.id)
if (parsedAnnotation.init != null) {
token.setInitialization(parsedAnnotation.init)
}
appendToken(tokens, token, options)
reader.nextNonEmptyLines()
}
function getLabel(reader: Reader, parsedAnnotation: AnnotationInterface, options: HandlerOptionInterface) {
const start = reader.currentLine
if (parsedAnnotation.type === 'CR') {
while(!reader.isEnd()) {
if (rules.fence(reader, [], true, options)) {
// we need to jump 2 lines up since that is the
reader.currentLine--
break
}
reader.nextLine()
}
} else if (parsedAnnotation.type === 'SS' || parsedAnnotation.type === 'MS') {
while(!reader.isEnd()) {
if (rules.option(reader, [], true, options)) break
reader.nextLine()
}
} else if (parsedAnnotation.type === 'TI') {
while(!reader.isEnd()) {
if (reader.isEmpty(reader.currentLine)) break
reader.nextLine()
}
}
return reader.getLines(start, reader.currentLine)
}
function appendToken(tokens: Token[], token: Token, options: HandlerOptionInterface) {
token.setChapter(options.chapter)
if (options.sectionMode && options.replMode) {
const sectionTokChildren = tokens[tokens.length - 1].children
const replTok = sectionTokChildren[sectionTokChildren.length - 1]
replTok.addChild(token)
} else if (options.sectionMode || options.replMode) {
tokens[tokens.length - 1].addChild(token)
} else {
tokens.push(token)
}
}