docutils-ts
Version:
Port of the Python Docutils library to TypeScript
142 lines (141 loc) • 4.7 kB
JavaScript
import BaseWriter from '../writer.js';
import * as docutils from '../index.js';
import * as nodes from '../nodes.js';
import { InvalidStateError } from "../exceptions.js";
export function escapeXml(unsafe) {
if (typeof unsafe === 'undefined') {
throw new Error('need unsafE');
}
return unsafe.replace(/[<>&'"]/g, (c) => {
switch (c) {
case '<': return '<';
case '>': return '>';
case '&': return '&';
case '\'': return ''';
case '"': return '"';
default: return c;
}
});
}
class XMLTranslator extends nodes.GenericNodeVisitor {
constructor(document) {
super(document);
this.simple_nodes = [];
this.doctype = '';
this.generator = `<!-- generated by Docutils ${docutils.__version__} -->\n`;
this.document = document;
this.warn = this.document.reporter.warning;
this.error = this.document.reporter.error;
this.output = [];
this.settings = document.settings;
const settings = this.settings;
this.newline = '';
this.indent = '';
const core = this.settings;
const outputEncoding = core.outputEncoding;
let xmlWriter = settings;
if (xmlWriter !== undefined) {
if (xmlWriter.newlines) {
this.newline = '\n';
}
if (xmlWriter.indents) {
this.newline = '\n';
this.indent = ' ';
}
if (xmlWriter.xmlDeclaration && outputEncoding !== undefined) {
this.output.push(this.xmlDeclaration(outputEncoding));
}
if (xmlWriter.doctypeDeclaration) {
this.output.push(this.doctype);
}
}
this.level = 0;
this.inSimple = 0;
this.fixedText = 0;
this.output.push(this.generator);
}
default_visit(node) {
this.simple_nodes = [nodes.TextElement]; // nodes.image, nodes.colspec, nodes.transition]
if (!this.inSimple) {
this.output.push(Array(this.level + 1).join(this.indent));
}
this.output.push(node.starttag());
this.level += 1;
// fixme should probably pick this code up
if (false) { // node instanceof nodes.FixedTextElement || node instanceof nodes.literal) {
this.fixedText += 1;
}
else {
if (this.simple_nodes.findIndex((nt) => node instanceof nt) !== -1) {
this.inSimple++;
}
}
if (!this.inSimple) {
this.output.push('\n');
}
}
default_departure(node) {
this.level -= 1;
if (!this.inSimple) {
this.output.push(Array(this.level + 1).join(this.indent));
}
this.output.push(node.endtag());
// if(node instanceof nodes['FixedTextElement'] || node instanceof nodes.literal) {
// this.fixedText -= 1;
// }
// bla
}
visit_Text(node) {
const text = escapeXml(node.astext());
this.output.push(text);
}
depart_Text(node) {
}
xmlDeclaration(outputEncoding) {
return '';
}
}
export default class XMLWriter extends BaseWriter {
constructor() {
super(...arguments);
this.translatorClass = XMLTranslator;
}
translate() {
if (this.document === undefined) {
throw new InvalidStateError('No document');
}
const TranslatorClass = this.translatorClass;
const visitor = new TranslatorClass(this.document);
this.visitor = visitor;
this.document.walkabout(visitor);
this.output = visitor.output.join('');
}
}
/*
Writer.settingsSpec = [
'"Docutils XML" Writer Options',
null,
[['Generate XML with newlines before and after tags.',
['--newlines'],
{ action: 'store_true', validator: 'frontend.validate_boolean' }],
['Generate XML with indents and newlines.',
['--indents'], // #@ TODO use integer value for number of spaces?
{ action: 'store_true', validator: 'frontend.validate_boolean' }],
['Omit the XML declaration. Use with caution.',
['--no-xml-declaration'],
{
dest: 'xml_declaration',
default: 1,
action: 'store_false',
validator: 'frontend.validate_boolean',
}],
['Omit the DOCTYPE declaration.',
['--no-doctype'],
{
dest: 'doctype_declaration',
default: 1,
action: 'store_false',
validator: 'frontend.validate_boolean',
}]]];
*/
export { XMLWriter };