UNPKG

docutils-ts

Version:

Port of the Python Docutils library to TypeScript

273 lines (271 loc) 11.3 kB
import StateWS from "../../../states/stateWS.js"; import NestedStateMachine from "../nestedStateMachine.js"; import * as nodes from "../../../nodes.js"; import { EOFError, InvalidArgumentsError, InvalidStateError } from "../../../exceptions.js"; import { fullyNormalizeName } from "../../../nodeUtils.js"; class RSTState extends StateWS { get explicit() { return this._explicit; } set explicit(value) { // console.log(`explicit ${JSON.stringify(value)}`) this._explicit = value; } constructor(stateMachine, debug = false) { super(stateMachine, debug); this.messages = []; /** Padding character for East Asian double-width text. */ this.doubleWidthPadChar = ''; this.logger = stateMachine.logger; //this.logger.silly('constructor'); this.rstStateMachine = stateMachine; this.createNestedStateMachine = () => NestedStateMachine.createStateMachine(this.rstStateMachine); //, undefined, this.rstStateMachine.stateFactory!.withStateClasses(["QuotedLiteralBlock"])); this.createIndentedStateMachine = this.createNestedStateMachine; this.rstStateMachine = stateMachine; //this.nestedSm = NestedStateMachine; //this.nestedSmCache = []; //this.stateClasses = args.stateClasses || []; // // if(this.stateClasses.length == 0) { // throw new InvalidStateError('No stateClasses') // } // KM2 // this.nestedSmKwargs = { // stateFactory: this.rstStateMachine.stateFactory.withStateClasses(this.stateClasses), // initialState: 'Body', // debug: args && stateMachine ? stateMachine.debug : false, // debugFn: args && stateMachine ? stateMachine.debugFn : console.log, // }; //this.logger.silly('end constructor'); } runtimeInit() { // this.logger.silly('runtimeInit'); super.runtimeInit(); const { memo } = this.rstStateMachine; this.memo = memo; if (!memo) { throw new Error('need memo'); } this.reporter = memo.reporter; this.inliner = memo.inliner; this.document = memo.document; this.parent = this.rstStateMachine.node; if (!this.reporter.getSourceAndLine) { //this.reporter!.getSourceAndLine = this.rstStateMachine.getSourceAndLine; } } gotoLine(absLineOffset) { try { this.rstStateMachine.gotoLine(absLineOffset); } catch (ex) { /* test for eof error? */ } } /* istanbul ignore next */ noMatch(context, transitions) { this.reporter.severe(`Internal error: no transition pattern match. State: "${this.constructor.name}"; transitions: ${transitions}; context: ${context}; current line: ${this.rstStateMachine.line}.`); return [context, undefined, []]; } bof() { return [[], []]; } nestedParse(inputLines, inputOffset, node, matchTitles = false, factoryFunction) { if (!this.memo || !this.memo.document) { throw new Error('need memo'); } let fn; if (factoryFunction !== undefined) { fn = factoryFunction; } else if (this.createNestedStateMachine !== undefined) { fn = this.createNestedStateMachine; } const block = inputLines; if (!block) { throw new Error('need block'); } let useDefault = 0; /*if (!mCopy.stateMachineClass) { mCopy.stateMachineClass = this.nestedSm; useDefault += 1; } if (!mCopy.stateMachineKwargs) { mCopy.stateMachineKwargs = this.nestedSmKwargs; useDefault += 1; }*/ const blockLength = block.length; /* let stateMachine; if (useDefault === 2 && this.nestedSmCache.length > 0) { stateMachine = this.nestedSmCache.pop(); } */ if (fn === undefined) { throw new InvalidStateError('factoryFunction'); } let stateMachine = fn(); if (stateMachine.run === undefined) { throw new InvalidStateError(`stateMachine.run`); } stateMachine.run(block, inputOffset, undefined, undefined, undefined, node, matchTitles, this.memo); /* if (useDefault === 2) { this.nestedSmCache.push(stateMachine); } else { stateMachine.unlink(); }*/ const newOffset = stateMachine.absLineOffset(); if (block.parent && (block.length - blockLength) !== 0) { this.rstStateMachine.nextLine(block.length - blockLength); } return newOffset; } nestedListParse(block, args) { this.logger.debug('nestedListParse', { value: block.join('\n') }); const myargs = { ...args }; if (myargs.createStateMachine !== undefined) { throw Error('not expecing that'); } /* istanbul ignore next */ if (myargs.extraSettings == null) { myargs.extraSettings = {}; } // if (!myargs.stateMachineClass) { // myargs.stateMachineClass = this.nestedSm; // } // if (!myargs.stateMachineKwargs) { // myargs.stateMachineKwargs = {...this.nestedSmKwargs}; // } // Copy the initial state if (myargs.createStateMachine === undefined && this.createIndentedStateMachine !== undefined) { myargs.createStateMachine = this.createIndentedStateMachine; } if (myargs.createStateMachine === undefined) { throw new InvalidStateError('createStateMachine'); } const stateMachine = myargs.createStateMachine(); //myargs.stateMachineArgs!.initialState = myargs.initialState; if (!myargs.blankFinishState) { myargs.blankFinishState = myargs.initialState; } if (!(stateMachine.hasState(myargs.blankFinishState))) { throw new InvalidArgumentsError(`invalid state ${myargs.blankFinishState}`); } stateMachine.getState2(myargs.blankFinishState).blankFinish = myargs.blankFinish; // Object.keys(myargs.extraSettings).forEach((key) => { // stateMachine.states[myargs.initialState][key] = myargs.extraSettings[key]; // }); stateMachine.run(block, myargs.inputOffset || 0, undefined, undefined, myargs.initialState, myargs.node, myargs.matchTitles, this.memo); this.logger.debug(`checking blank finish state of ${myargs.blankFinishState}`); const { blankFinish } = stateMachine.getState2(myargs.blankFinishState); stateMachine.unlink(); return [stateMachine.absLineOffset() || 0, blankFinish || false]; } section(args) { const { source, style, title, lineno, messages } = args; if (this.checkSubsection({ source, style, lineno })) { this.newSubsection({ title, lineno, messages }); } } checkSubsection(args) { const { source, style, lineno } = args; const memo = this.memo; const titleStyles = memo.titleStyles; // console.log(titleStyles); const mylevel = memo.sectionLevel; let level = 0; level = titleStyles.findIndex(tStyle => (style.length === 1 ? tStyle.length === 1 && tStyle[0] === style[0] : style.length === 2 && tStyle.length === 2 && tStyle[0] === style[0] && tStyle[1] === style[1])) + 1; if (level === 0) { if (titleStyles.length === memo.sectionLevel) { // new subsection titleStyles.push(style); return true; } this.parent.add(this.title_inconsistent(source, lineno)); return false; } if (level <= mylevel) { // // sibling or supersection memo.sectionLevel = level; // bubble up to parent section if (style.length === 2) { memo.sectionBubbleUpKludge = true; } // back up 2 lines for underline title, 3 for overline title this.rstStateMachine.previousLine(style.length + 1); throw new EOFError(); // let parent section re-evaluate } if (level === mylevel + 1) { // immediate subsection return true; } this.parent.add(this.title_inconsistent(source, lineno)); return false; } title_inconsistent(sourcetext, lineno) { const error = this.reporter.severe('Title level inconsistent:', [new nodes.literal_block('', sourcetext)], { line: lineno }); return error; } newSubsection(args) { const { title, lineno, messages } = args; const memo = this.memo; const myLevel = memo.sectionLevel; memo.sectionLevel += 1; const sectionNode = new nodes.section(); this.parent.add(sectionNode); const [textNodes, titleMessages] = this.inline_text(title, lineno); const titleNode = new nodes.title(title, '', textNodes); const name = fullyNormalizeName(titleNode.astext()); sectionNode.attributes.names.push(name); sectionNode.add(titleNode); sectionNode.add(messages); sectionNode.add(titleMessages); this.document.noteImplicitTarget(sectionNode, sectionNode); const offset = this.rstStateMachine.lineOffset + 1; const absoffset = this.rstStateMachine.absLineOffset() + 1; const newabsoffset = this.nestedParse(this.rstStateMachine.inputLines.slice(offset), absoffset, sectionNode, true); this.gotoLine(newabsoffset); if (memo.sectionLevel <= myLevel) { throw new EOFError(); } memo.sectionLevel = myLevel; } unindentWarning(nodeName) { const lineno = this.rstStateMachine.absLineNumber() + 1; return this.reporter.warning(`${nodeName} ends without a blank line; unexpected unindent.`, [], { line: lineno }); } paragraph(lines, lineno) { const data = lines.join('\n').trimRight(); let text; let literalNext; if (/(?<!\\)(\\\\)*::$/.test(data)) { if (data.length === 2) { return [[], 1]; } if (' \n'.indexOf(data[data.length - 3]) !== -1) { text = data.substring(0, data.length - 3).replace(/\s*$/, ''); } else { text = data.substring(0, data.length - 1); } literalNext = 1; } else { text = data; literalNext = 0; } const r = this.inline_text(text, lineno); const [textnodes, messages] = r; const p = new nodes.paragraph(data, '', textnodes); let sourceAndLine = this.rstStateMachine.getSourceAndLine(lineno); p.source = sourceAndLine[0]; if (sourceAndLine[1] !== undefined) { p.line = sourceAndLine[1]; } return [[p, ...messages], literalNext]; } inline_text(text, lineno) { this.logger.silly('in transition method inline_text', { value: text }); const r = this.inliner.parse(text, { lineno, memo: this.memo, parent: this.parent }); return r; } } export default RSTState;