@atomist/automation-client
Version:
Atomist API for software low-level client
101 lines (82 loc) • 2.61 kB
text/typescript
import {
defineDynamicProperties,
fillInEmptyNonTerminalValues,
TreeNode,
} from "@atomist/tree-path";
import { File } from "../../../project/File";
import { FileParser } from "../FileParser";
/**
* Parameters to RegexFileParser
*/
export interface RegexOptions {
/**
* Name of the root element within a document
*/
readonly rootName: string;
/**
* Path element name for each match
*/
readonly matchName: string;
/**
* Regex. May contain capture groups: If so name them with captureGroupNames.
*/
readonly regex: RegExp;
/**
* Names of the capture groups, if any. This is used to populate the tree structure.
*/
readonly captureGroupNames?: string[];
}
/**
* Allow path expressions against results from a regex with capture groups
*/
export class RegexFileParser implements FileParser {
constructor(public readonly opts: RegexOptions) {
}
get rootName(): string {
return this.opts.rootName;
}
public async toAst(f: File): Promise<TreeNode> {
const content = await f.getContent();
const matches: RegExpExecArray[] = [];
let remaining = content;
do {
const m = this.opts.regex.exec(remaining);
if (!!m) {
matches.push(m);
// Rewrite index in outer string
m.index += content.length - remaining.length;
remaining = content.substr(m.index + m[0].length);
} else {
break;
}
} while (true);
const root: TreeNode = {
$name: this.opts.rootName,
};
root.$children = matches.map(match => new RegexTreeNode(this.opts, match, root));
defineDynamicProperties(root);
fillInEmptyNonTerminalValues(root, content);
return root;
}
}
class RegexTreeNode implements TreeNode {
public readonly $children: TreeNode[];
public readonly $name: string;
public readonly $value: string;
public readonly $offset: number;
constructor(reo: RegexOptions, m: RegExpExecArray, public $parent: TreeNode) {
this.$name = reo.matchName;
this.$offset = m.index;
this.$value = m[0];
this.$children = !!reo.captureGroupNames ?
reo.captureGroupNames.map(($name, i) => {
const tn: any = {
$name,
$value: m[i + 1],
};
tn.$offset = m.index + m[0].indexOf(tn.$value);
return tn;
}) :
undefined;
}
}