Skip to content

Instantly share code, notes, and snippets.

@quin2
Created February 22, 2024 16:48
Show Gist options
  • Save quin2/458293b02b692d5c9921f1445b5750f9 to your computer and use it in GitHub Desktop.
Save quin2/458293b02b692d5c9921f1445b5750f9 to your computer and use it in GitHub Desktop.
html/react native parser in typescript
const input2 = '"<View><ExpoStatusBar style=\"{ \"flex\": 1}\" yeet="yaw"></ExpoStatusBar></View>"'
class Attrib {
name: string;
val: string;
constructor(name: string, val: string){
this.name = name
this.val = val
}
}
class Tag {
name: string
children: Tag[] = []
attributes: Attrib[] = []
text: string = ""
constructor(name: string){
this.name = name
}
}
enum ParseState {
INTAG,
INATTRIB,
INTAGTERM,
INATTRIBVALUE,
POSTATTRIB,
INQUOTEDATTRIBVALUE,
NONE
}
class AccessibilityTree {
head = new Tag("")
constructor(rn: string) {
let state: ParseState = ParseState.NONE
let word = ""
let memory: Tag[] = []
let attribs: Attrib[] = []
let attribName = ""
let openMarker = ""
let closeMarker = ""
for(let i = 0; i < rn.length; i++){
let char = rn.charAt(i);
//token check
if(char == "<"){
if(word != " " && word != ""){
console.log("Found add'l text " + word)
let nt = new Tag("")
nt.text = word
if(memory[0] != undefined){
console.log("adding as child")
this.head = memory[memory.length - 1];
this.head.children.push(nt)
}
}
state = ParseState.INTAG
word = ""
attribs = []
continue;
}
if(state == ParseState.INTAG && char == ">"){
console.log("Found tag " + word + " with attribs " + attribs)
let nt = new Tag(word)
nt.attributes = attribs
if(memory[0] != undefined){
this.head = memory[memory.length - 1];
this.head.children.push(nt)
}
memory.push(nt)
this.head = nt;
state = ParseState.NONE
word = ""
continue;
}
if(state == ParseState.INTAG && char == " "){
console.log("Found tag " + word + " with attribs " + attribs)
let nt = new Tag(word)
nt.attributes = attribs
if(memory[0] != undefined){
this.head = memory[memory.length - 1]
this.head.children.push(nt)
}
memory.push(nt)
this.head = nt;
word = ""
state = ParseState.INATTRIB
continue;
}
if(state == ParseState.INTAGTERM && char == ">"){
console.log("Found tag termination " + word)
let children = memory.pop()
if (memory.length > 0) {
this.head = memory[memory.length - 1]; // Update head to parent tag
} else {
break;
}
state = ParseState.NONE
word = ""
continue;
}
if(state == ParseState.INTAG && char == "/"){
word = ""
state = ParseState.INTAGTERM
continue;
}
// Attribute parsing lives below here
if((state == ParseState.INATTRIB || state == ParseState.POSTATTRIB) && char == "="){
console.log("Found attrib " + word)
attribName = word
word = ""
state = ParseState.INATTRIBVALUE
continue;
}
if(state == ParseState.INATTRIBVALUE && char == " "){
console.log("Found attrib value " + word)
attribs.push(new Attrib(attribName, word))
word = ""
state = ParseState.POSTATTRIB
continue;
}
if(state == ParseState.INATTRIBVALUE && char == ">"){
console.log("Found attrib value " + word)
attribs.push(new Attrib(attribName, word))
word = ""
state = ParseState.NONE
continue;
}
if(state == ParseState.INATTRIBVALUE && (char == '{' || char == "[")){
openMarker = char
if(char == "{") {
closeMarker = "}"
}
if(char == "[") {
closeMarker = "]"
}
word = ""
state = ParseState.INQUOTEDATTRIBVALUE
continue;
}
if(state == ParseState.INQUOTEDATTRIBVALUE && char == closeMarker){
console.log("Found attrib value thruough quotes " + word)
attribs.push(new Attrib(attribName, `"${openMarker}${word}${closeMarker}"`))
word = ""
openMarker = ""
closeMarker = ""
state = ParseState.POSTATTRIB
continue;
}
if(state == ParseState.POSTATTRIB && char == " "){
word = ""
state = ParseState.POSTATTRIB
continue;
}
if(state == ParseState.POSTATTRIB && char == ">") {
console.log("Found attrib value " + word)
attribs.push(new Attrib(attribName, word))
word = ""
state = ParseState.NONE
continue;
}
word += char
}
}
print() {
function printAttributes(node: Tag){
if(node.attributes.length == 0){
return ""
}
return " " + node.attributes.map(x => `${x.name}=${x.val}`).join(" ")
}
function printOutput(node: Tag): String{
let result = ""
if(node.name.length > 0) {
result += `<${node.name}${printAttributes(node)}>`
}
if(node.text.length > 0){
result += node.text;
}
for(let i = 0; i < node.children.length; i++){
result += printOutput(node.children[i])
}
if(node.name.length > 0) {
result += `</${node.name}>`
}
return result
}
console.log(printOutput(this.head))
}
addAttribute(tagName: string, key: string, value: string) {
function addAttributeInner(node: Tag, tagName: string, key: string, value: string){
if(node.name.toLowerCase() == tagName.toLowerCase()) {
node.attributes.push(new Attrib(key, value))
}
for(let i = 0; i < node.children.length; i++){
addAttributeInner(node.children[i], tagName, key, value)
}
}
addAttributeInner(this.head, tagName, key, value)
}
}
//print original
console.log(input2)
console.log()
//print parsed version
let result = new AccessibilityTree(input2)
console.log()
result.print()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment