course-renderer
Version:
Manages CA School Courses file system storage and HTML conversion
165 lines (126 loc) • 4.03 kB
text/typescript
import { isSpace, isLineFeed, isWhiteSpace } from './utils'
export default class Reader {
source: string
length: number
currentLine: number
startLinePos: number[]
endLinePos: number[]
maxLine: number
constructor(src: string) {
this.source = src.replace(/\r\n/g, "\n")
this.length = this.source.length
this.currentLine = 0 // Initial line position for reading
this.parseSource()
}
parseSource() {
this.startLinePos = []
this.endLinePos = []
let start, pos, len
for ( start = pos = 0, len = this.length; pos < len; pos++) {
let ch = this.getCharCode(pos)
if (ch === 0x0A || pos === len - 1) {
if (ch !== 0x0A) pos++
this.startLinePos.push(start)
this.endLinePos.push(pos)
start = pos + 1
}
}
this.maxLine = this.startLinePos.length
}
getCharCode(pos: number = this.getCurrentLineStartPos()) {
return this.source.charCodeAt(pos)
}
getCurrentLineStartPos() {
return this.getLineStartPos()
}
getLineStartPos(line: number = this.currentLine) {
return this.startLinePos[line]
}
getCurrentLineEndPos() {
return this.getLineEndPos()
}
getLineEndPos(line: number = this.currentLine) {
return this.endLinePos[line]
}
getLine(line: number) {
return this.source.slice(this.getLineStartPos(line), this.getLineEndPos(line))
}
getLines( start: number, end: number) {
let queue = []
if (start === end) {
return this.getLine(start)
}
while ( start <= end ) {
queue.push(this.getLine(start))
start++
}
return queue.join('\n')
}
// Moves the position to the next line. Needs to REDO
nextLine() {
this.currentLine++;
}
isEnd() {
return this.currentLine >= this.maxLine
}
isEmpty(line: number) {
let pos: number
let max = this.getLineEndPos(line)
let isEmpty = true
for (pos = this.getLineStartPos(line); pos <= max; pos++) {
if (!isSpace(this.getCharCode(pos)) && !isLineFeed(this.getCharCode(pos))) {
isEmpty = false
break
}
}
return isEmpty
}
nextNonEmptyLines() {
this.nextLine()
this.skipEmptyLines()
}
jumpBeforeEmptyLines(line: number = this.currentLine) {
while (line < this.maxLine) {
if (!this.isEmpty(line)) break
line++
}
return line
}
skipEmptyChars(startPos: number = this.getCurrentLineStartPos()) {
let pos: number
for (pos = startPos; pos < this.length; pos++) {
if (!isWhiteSpace(this.getCharCode(pos))) break
}
return pos
}
// Skip empty lines from the current pos
skipEmptyLines() {
let pos: number
let currentLine: number
let exit = false
for (currentLine = this.currentLine; currentLine < this.maxLine; currentLine++) {
for (pos = this.startLinePos[currentLine]; pos <= this.endLinePos[currentLine]; pos++) {
let ch = this.getCharCode(pos)
if (!isLineFeed(ch) && !isSpace(this.getCharCode(pos))) {
this.currentLine = currentLine
exit = true
break
}
}
if (exit) break
}
}
skipSpaces(pos: number) {
for (let max = this.length; pos < max; pos++) {
let ch = this.getCharCode(pos)
if (!isSpace(ch)) break
}
return pos
}
skipChars(pos: number = this.getCurrentLineStartPos(), code: any) {
for (const max = this.length; pos < max; pos++) {
if (this.getCharCode(pos) !== code) break
}
return pos
}
}