UNPKG

@atomist/rug

Version:

TypeScript model for Atomist Rugs, see http://docs.atomist.com/

332 lines (282 loc) 10.2 kB
import { TextTreeNode } from "../../tree/PathExpression"; /** * Extended by classes that know how to handle YAML strings or sequences. */ export interface YamlStringOps { /** * Returns the actual text, not the raw value, * which may contain quotes etc. */ text(): string; /** * Update the actual text, taking care of quotes, newlines etc. */ updateText(to: string): void; } export type YamlString = YamlStringOps & TextTreeNode; /** * String without quotes or newlines. Leave it alone. */ export class YamlRawValue implements YamlStringOps { constructor(private node: TextTreeNode) { } public text() { return this.node.value(); } public updateText(to: string) { this.node.update(to); } } /** * String enclosed in "". Simply strips them. */ export class YamlQuotedValue implements YamlStringOps { constructor(private node: TextTreeNode) { } public text() { return this.node.value().slice(1, this.node.value().length - 1); } public updateText(to: string) { const newValue = `"${to}"`; this.node.update(newValue); } } /** * String using >. Strip newlines. */ export class YamlFoldedBlockScalar implements YamlStringOps { // Indent for each line private indent: string; private leading: string; constructor(private node: TextTreeNode) { const raw = node.value(); if (raw.charAt(0) !== ">") { throw new Error("Illegal argument: Must begin with >"); } if (raw.charAt(1) !== "\n") { throw new Error("Illegal argument: Must begin with >\n"); } let index = 2; let ch = raw.charAt(index); while (ch === " " || ch === "\t" || ch === "\n") { ch = raw.charAt(++index); } this.leading = raw.substr(0, index); this.indent = this.leading.substring(2); } public text() { return this.node.value().substr(this.leading.length) .replace(new RegExp("^" + this.indent, "mg"), "") .replace(new RegExp("\n+$"), "") .replace(new RegExp("([^\n])\n([^\n])", "g"), "$1 $2") .replace(new RegExp("\n\n", "g"), "\n") + "\n"; } public updateText(to: string) { const newValue = `${this.leading}${to}`; // console.log(`Update from [${this.node.value()}] to [${newValue}]`) this.node.update(newValue); } } /** * String using >-. */ export class YamlFoldedBlockWithStripChomping implements YamlStringOps { // Indent for each line private indent: string; private leading: string; constructor(private node: TextTreeNode) { const raw = node.value(); if (raw.charAt(0) !== ">" && raw.charAt(1) !== "-") { throw new Error("Illegal argument: Must begin with >-"); } if (raw.charAt(2) !== "\n") { throw new Error("Illegal argument: Must begin with >-\n"); } let index = 3; let ch = raw.charAt(index); while (ch === " " || ch === "\t" || ch === "\n") { ch = raw.charAt(++index); } this.leading = raw.substr(0, index); this.indent = this.leading.substring(3); } public text() { return this.node.value().substr(this.leading.length) .replace(new RegExp("^" + this.indent, "mg"), "") .replace(new RegExp("\n+$"), "") .replace(new RegExp("([^\n])\n([^\n])", "g"), "$1 $2") .replace(new RegExp("\n\n", "g"), "\n"); } public updateText(to: string) { const newValue = `${this.leading}${to}`; // console.log(`Update from [${this.node.value()}] to [${newValue}]`) this.node.update(newValue); } } /** * String using >+. */ export class YamlFoldedBlockWithKeepChomping implements YamlStringOps { // Indent for each line private indent: string; private leading: string; constructor(private node: TextTreeNode) { const raw = node.value(); if (raw.charAt(0) !== ">" && raw.charAt(1) !== "+") { throw new Error("Illegal argument: Must begin with >+"); } if (raw.charAt(2) !== "\n") { throw new Error("Illegal argument: Must begin with >+\n"); } let index = 3; let ch = raw.charAt(index); while (ch === " " || ch === "\t" || ch === "\n") { ch = raw.charAt(++index); } this.leading = raw.substr(0, index); this.indent = this.leading.substring(3); } public text() { const raw = this.node.value(); const newlines = raw.match(new RegExp("\n+$")); return raw.substr(this.leading.length) .replace(new RegExp("^" + this.indent, "mg"), "") .replace(new RegExp("\n+$"), "") .replace(new RegExp("([^\n])\n([^\n])", "g"), "$1 $2") .replace(new RegExp("\n\n", "g"), "\n") + newlines[0].toString(); } public updateText(to: string) { const newValue = `${this.leading}${to}`; // console.log(`Update from [${this.node.value()}] to [${newValue}]`) this.node.update(newValue); } } /** * String using |. Maintain newlines. */ export class YamlLiteralBlockScalar implements YamlStringOps { // Indent for each line private indent: string; private leading: string; constructor(private node: TextTreeNode) { const raw = node.value(); if (raw.charAt(0) !== "|") { throw new Error("Illegal argument: Must begin with |"); } if (raw.charAt(1) !== "\n") { throw new Error("Illegal argument: Must begin with |\n"); } let index = 2; let ch = raw.charAt(index); while (ch === " " || ch === "\t" || ch === "\n") { ch = raw.charAt(++index); } this.leading = raw.substr(0, index); this.indent = this.leading.substring(2); } public text() { return this.node.value().substr(this.leading.length) .replace(new RegExp("^" + this.indent, "mg"), "") .replace(new RegExp("\n+$"), "\n"); } public updateText(to: string) { const newValue = `${this.leading}${to}`; // console.log(`Update from [${this.node.value()}] to [${newValue}]`) this.node.update(newValue); } } /** * String using |-. */ export class YamlLiteralBlockWithStripChomping implements YamlStringOps { // Indent for each line private indent: string; private leading: string; constructor(private node: TextTreeNode) { const raw = node.value(); if (raw.charAt(0) !== "|" && raw.charAt(1) !== "-") { throw new Error("Illegal argument: Must begin with |-"); } if (raw.charAt(2) !== "\n") { throw new Error("Illegal argument: Must begin with |-\n"); } let index = 3; let ch = raw.charAt(index); while (ch === " " || ch === "\t" || ch === "\n") { ch = raw.charAt(++index); } this.leading = raw.substr(0, index); this.indent = this.leading.substring(3); } public text() { return this.node.value().substr(this.leading.length) .replace(new RegExp("^" + this.indent, "mg"), "") .replace(new RegExp("\n+$"), ""); } public updateText(to: string) { const newValue = `${this.leading}${to}`; // console.log(`Update from [${this.node.value()}] to [${newValue}]`) this.node.update(newValue); } } /** * String using |+. */ export class YamlLiteralBlockWithKeepChomping implements YamlStringOps { // Indent for each line private indent: string; private leading: string; constructor(private node: TextTreeNode) { const raw = node.value(); if (raw.charAt(0) !== "|" && raw.charAt(1) !== "+") { throw new Error("Illegal argument: Must begin with |+"); } if (raw.charAt(2) !== "\n") { throw new Error("Illegal argument: Must begin with |+\n"); } let index = 3; let ch = raw.charAt(index); while (ch === " " || ch === "\t" || ch === "\n") { ch = raw.charAt(++index); } this.leading = raw.substr(0, index); this.indent = this.leading.substring(3); } public text() { const raw = this.node.value(); const newlines = raw.match(new RegExp("\n+$")); return raw.substr(this.leading.length) .replace(new RegExp("^" + this.indent, "mg"), "") .replace(new RegExp("\n+$"), "") + newlines[0].toString(); } public updateText(to: string) { const newValue = `${this.leading}${to}`; // console.log(`Update from [${this.node.value()}] to [${newValue}]`) this.node.update(newValue); } } /** * Works with a raw node value to add and remove sequence elements, observing YAML formatting. */ export class YamlSequenceOps { private items: string[]; constructor(private node: TextTreeNode) { this.items = node.value().trim().split("\n"); } /** * Adds an element to a sequence. * * @param elem the new element */ public addElement(elem: string) { const lastItem = this.items[this.items.length - 1]; this.items.push(lastItem.substring(0, lastItem.indexOf("-")) + "- " + elem); const newValue = this.items.join("\n") + "\n"; this.node.update(newValue); // console.log(this.node.value()) } /** * Removes an element, if it exists, from a sequence. * * @param elem the element to remove */ public removeElement(elem: string) { const lastItem = this.items[this.items.length - 1]; const index = this.items.indexOf(lastItem.substring(0, lastItem.indexOf("-")) + "- " + elem); if (index > -1) { this.items.splice(index, 1); const newValue = this.items.join("\n") + "\n"; this.node.update(newValue); // console.log(this.node.value()) } } /** * Update a key. * * @param the new key name */ public updateKey(key: string) { this.node.update(key); // this currently only updates the value } } export type YamlSequence = YamlSequenceOps & TextTreeNode;