UNPKG

scriptable-testlab

Version:

A lightweight, efficient tool designed to manage and update scripts for Scriptable.

187 lines (161 loc) 4.61 kB
import {AbsXMLParser} from 'scriptable-abstract'; interface XMLParserState { string: string; didStartDocument: () => void; didEndDocument: () => void; didStartElement: (name: string, attributes: {[key: string]: string}) => void; didEndElement: (name: string) => void; foundCharacters: (str: string) => void; parseErrorOccurred: (error: string) => void; } /** * Mock implementation of Scriptable's XMLParser * Used to parse XML documents */ export class MockXMLParser extends AbsXMLParser<XMLParserState> { constructor(string: string) { super({ string, didStartDocument: () => {}, didEndDocument: () => {}, didStartElement: () => {}, didEndElement: () => {}, foundCharacters: () => {}, parseErrorOccurred: () => {}, }); } /** * Text to parse */ get string(): string { return this.state.string; } /** * Sets the text to parse */ set string(value: string) { this.setState({string: value}); } /** * Function called when parsing starts */ get didStartDocument(): () => void { return this.state.didStartDocument; } /** * Sets the function called when parsing starts */ set didStartDocument(value: () => void) { this.setState({didStartDocument: value}); } /** * Function called when parsing ends */ get didEndDocument(): () => void { return this.state.didEndDocument; } /** * Sets the function called when parsing ends */ set didEndDocument(value: () => void) { this.setState({didEndDocument: value}); } /** * Function called when an element starts */ get didStartElement(): (name: string, attributes: {[key: string]: string}) => void { return this.state.didStartElement; } /** * Sets the function called when an element starts */ set didStartElement(value: (name: string, attributes: {[key: string]: string}) => void) { this.setState({didStartElement: value}); } /** * Function called when an element ends */ get didEndElement(): (name: string) => void { return this.state.didEndElement; } /** * Sets the function called when an element ends */ set didEndElement(value: (name: string) => void) { this.setState({didEndElement: value}); } /** * Function called when characters are found */ get foundCharacters(): (str: string) => void { return this.state.foundCharacters; } /** * Sets the function called when characters are found */ set foundCharacters(value: (str: string) => void) { this.setState({foundCharacters: value}); } /** * Function called when a parse error occurs */ get parseErrorOccurred(): (error: string) => void { return this.state.parseErrorOccurred; } /** * Sets the function called when a parse error occurs */ set parseErrorOccurred(value: (error: string) => void) { this.setState({parseErrorOccurred: value}); } /** * Parses the XML document * @returns true if parsing was successful, false otherwise */ parse(): boolean { try { // Call lifecycle methods in sequence this.didStartDocument(); // Simple XML parsing simulation using regex const xmlString = this.string; // Basic validation for well-formed XML if (!xmlString.match(/^<[^>]+>.*<\/[^>]+>$/s)) { this.parseErrorOccurred('Invalid XML structure'); return false; } const tagRegex = /<(\/?)([\w-]+)((?:\s+[\w-]+="[^"]*")*)\s*\/?>/g; const textRegex = />([^<]+)</g; let match; // Parse tags while ((match = tagRegex.exec(xmlString)) !== null) { const [, isClosing, tagName, attributesStr] = match; if (!isClosing) { // Opening tag const attributes: {[key: string]: string} = {}; const attrRegex = /(\w+)="([^"]*)"/g; let attrMatch; while ((attrMatch = attrRegex.exec(attributesStr)) !== null) { const [, name, value] = attrMatch; attributes[name] = value; } this.didStartElement(tagName, attributes); } else { // Closing tag this.didEndElement(tagName); } } // Parse text content while ((match = textRegex.exec(xmlString)) !== null) { const [, text] = match; if (text.trim()) { this.foundCharacters(text.trim()); } } this.didEndDocument(); return true; } catch (error) { this.parseErrorOccurred(error instanceof Error ? error.message : String(error)); return false; } } }