UNPKG

@4dsas/doc_preprocessing

Version:

Preprocess 4D doc to be built by docusaurus

308 lines (258 loc) 9.36 kB
var { Instruction, TYPE } = require("./instruction.js") const { MESSAGE } = require("../log.js") var fs = require('fs'); class Ref extends Instruction { constructor(inType) { super() this.content = ""; this._id = ""; this._filePath = ""; this._type = inType; } getType() { return TYPE.REF } set ID(inID) { this._id = inID } get ID() { return this._id } set filePath(inFilePath) { this._filePath = inFilePath } get filePath() { return this._filePath } resolve(inContent) { this.content = inContent.substr(this._start, this._end - this._start) } equalsTo(inRef) { return this.content === inRef.content && this._id === inRef._id && this._filePath === inRef._filePath; } } class REFManager { constructor(logger, inEscapeList) { this._ref = new Map() this._logger = logger; this._escapeList = inEscapeList } push(inRef, inUpdate) { let isNew = false if (!this._ref.has(inRef.ID)) { this._ref.set(inRef.ID, inRef) isNew = true; } else { if (inUpdate) { if (this._ref.get(inRef.ID).equalsTo(inRef)) { //log.show(MESSAGE.WARNING, "The reference \'" + inRef.ID + "\' located in " + inRef.filePath + " is already used in " + this._ref.get(inRef.ID).filePath) } else { this._ref.set(inRef.ID, inRef) isNew = true; } } else { this._logger(MESSAGE.WARNING, "The reference \'" + inRef.ID + "\' located in " + inRef.filePath + " is already used in " + this._ref.get(inRef.ID).filePath) } } return isNew } collectFile(inCurrentPath, inUpdate = false) { let isNew = false const content = fs.readFileSync(inCurrentPath, 'utf8'); const re = /(<!--)(.*?)(-->)/g let stack = [] let match while ((match = re.exec(content)) != null) { const keywords = match[2].trim().split(" ") const type = keywords[0] switch (type) { case TYPE.REF: if (keywords.length > 1) { let item = new Ref(type) item.start = match.index + match[0].length item.ID = Instruction.convertID2Args(keywords) item.filePath = inCurrentPath; stack.push(item) } else { this._logger(MESSAGE.ERROR, "Missing id for reference") } break case TYPE.IREF: { if (keywords.length > 1) { let item = new Ref(type) item.start = match.index + match[0].length item.end = match.start; item.ID = Instruction.convertID2Args(keywords) item.filePath = inCurrentPath; isNew |= this.push(item, inUpdate) } break; } case TYPE.END: if (stack.length > 0) { let item = stack.pop() if (item.getType() === TYPE.REF) { item.end = match.index item.resolve(content) isNew |= this.push(item, inUpdate) } } else { this._logger(MESSAGE.ERROR, "Too many 'END' in file " + inCurrentPath) } break } } while (stack.length > 0) { let item = stack.pop() this._logger(MESSAGE.ERROR, "Missing 'END' for reference " + item.ID + " in " + inCurrentPath) } return isNew } getContentFromID(inID) { if (this._ref.has(inID)) { return { content: this._ref.get(inID).content, found: true, type: this._ref.get(inID)._type } } return { content: "", found: false, type: TYPE.UNKNOWN }; } removeFromPath(inPath) { for (let entry of this._ref.entries()) { if (entry[1].filePath === inPath) { this._ref.delete(entry[0]) } } } _fillAlias(withDelimiter, inHaveCharacter) { let alias = new Map() for (let entry of this._ref.entries()) { let key = entry[0] let value = entry[1].content; if (key[0] !== inHaveCharacter) continue key = key.substring(1) let splitID = key.split(withDelimiter) if (splitID.length > 1) { if (splitID[1] == "_alias_") { alias.set(splitID[0], value) } } } return alias; } _getRealKey(inAlias, inKey) { if (inAlias.has(inKey)) { return inAlias.get(inKey) } return inKey } _jsonEscape(str) { str = str.replace(/(<!--)(.*?)(-->)/g, "") .replace(/\r\n/g, "\n") .replace(/\r/g, "\n") .replace(/\\n/g, "\\n") .replace(/\\'/g, "\\'") .replace(/\\"/g, '\\"') .replace(/\\&/g, "\\&") .replace(/\\r/g, "\\r") .replace(/\\t/g, "\\t") .replace(/\\b/g, "\\b") .replace(/\\{/g, "{") .replace(/\\}/g, "}") .replace(/(\[(.*?)\])\(.*?\)/g, '$2') .replace(/\\f/g, "\\f"); if (this._escapeList) { for (let escape of this._escapeList) { if (escape.from && escape.to) str = str.replaceAll(escape.from, escape.to); } } if (str[0] == '\n') str = str.substr(1) if (str.slice(-1) == '\n') str = str.slice(0, -1) return str } _isIDValid(inIDs) { for (let i = 0; i < inIDs.length; ++i) { if (inIDs[i] === "_alias_") { return false } } return true } formatIndex(withDelimiter, inHaveCharacter) { let alias = this._fillAlias(withDelimiter, inHaveCharacter) let json = {} for (let entry of this._ref.entries()) { const key = entry[0] if (key[0] !== inHaveCharacter) continue let splitID = key.substring(1).split(withDelimiter) if (!this._isIDValid(splitID)) continue if (splitID.length > 1) { splitID[0] = this._getRealKey(alias, splitID[0]) } json[splitID.join('.')] = entry[1].filePath } return json } formatToJSON(withDelimiter, inHaveCharacter) { let alias = this._fillAlias(withDelimiter, inHaveCharacter) let json = {} for (let entry of this._ref.entries()) { let key = entry[0], value = entry[1].content; if (key[0] !== inHaveCharacter) continue key = key.substring(1) const type = entry[1]._type let splitID = key.split(withDelimiter) if (!this._isIDValid(splitID)) continue let currentJSON = json; let lastID = "" if (splitID.length > 1) { splitID[0] = this._getRealKey(alias, splitID[0]) } for (let i = 0; i < splitID.length - 1; i++) { if (!(splitID[i] in currentJSON)) { currentJSON[splitID[i]] = {} } currentJSON = currentJSON[splitID[i]] } lastID = splitID[splitID.length - 1] let content = this._jsonEscape(value.trim()) if (content[0] == '|') {//It's an array let lines = content.split('\n') for (let i = 0; i < lines.length; i++) { let columns = lines[i].split('|').filter(function (v, index, array) { return !((index == 0 || index == array.length - 1) && v == '') }) if (i == 0) {//|title1|title2| currentJSON[lastID] = [] } else if (i == 1) { }// |----|----| else {//Content let obj = new Array(columns.length) for (let j = 0; j < columns.length; j++) { obj[j] = columns[j].trim() } currentJSON[lastID].push(obj) } } } else { try { if (type === TYPE.REF) { currentJSON[lastID] = content } else if (type === TYPE.IREF) { currentJSON[lastID] = true; } } catch (e) { } } } return json } } exports.Ref = Ref exports.REFManager = REFManager