UNPKG

2.42 kBJavaScriptView Raw
1'use strict';
2/*
3 Copyright 2012-2015, Yahoo Inc.
4 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
5 */
6const INDENT = ' ';
7
8function attrString(attrs) {
9 return Object.entries(attrs || {})
10 .map(([k, v]) => ` ${k}="${v}"`)
11 .join('');
12}
13
14/**
15 * a utility class to produce well-formed, indented XML
16 * @param {ContentWriter} contentWriter the content writer that this utility wraps
17 * @constructor
18 */
19class XMLWriter {
20 constructor(contentWriter) {
21 this.cw = contentWriter;
22 this.stack = [];
23 }
24
25 indent(str) {
26 return this.stack.map(() => INDENT).join('') + str;
27 }
28
29 /**
30 * writes the opening XML tag with the supplied attributes
31 * @param {String} name tag name
32 * @param {Object} [attrs=null] attrs attributes for the tag
33 */
34 openTag(name, attrs) {
35 const str = this.indent(`<${name + attrString(attrs)}>`);
36 this.cw.println(str);
37 this.stack.push(name);
38 }
39
40 /**
41 * closes an open XML tag.
42 * @param {String} name - tag name to close. This must match the writer's
43 * notion of the tag that is currently open.
44 */
45 closeTag(name) {
46 if (this.stack.length === 0) {
47 throw new Error(`Attempt to close tag ${name} when not opened`);
48 }
49 const stashed = this.stack.pop();
50 const str = `</${name}>`;
51
52 if (stashed !== name) {
53 throw new Error(
54 `Attempt to close tag ${name} when ${stashed} was the one open`
55 );
56 }
57 this.cw.println(this.indent(str));
58 }
59
60 /**
61 * writes a tag and its value opening and closing it at the same time
62 * @param {String} name tag name
63 * @param {Object} [attrs=null] attrs tag attributes
64 * @param {String} [content=null] content optional tag content
65 */
66 inlineTag(name, attrs, content) {
67 let str = '<' + name + attrString(attrs);
68 if (content) {
69 str += `>${content}</${name}>`;
70 } else {
71 str += '/>';
72 }
73 str = this.indent(str);
74 this.cw.println(str);
75 }
76
77 /**
78 * closes all open tags and ends the document
79 */
80 closeAll() {
81 this.stack
82 .slice()
83 .reverse()
84 .forEach(name => {
85 this.closeTag(name);
86 });
87 }
88}
89
90module.exports = XMLWriter;