docutils-ts
Version:
Port of the Python Docutils library to TypeScript
273 lines (271 loc) • 11.3 kB
JavaScript
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;