From cf2c88b1c0974ae04c31de106ceec5cd08e3dab1 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 17 Sep 2019 21:09:05 -0700 Subject: [PATCH] Add parent references to XML tree --- modern/src/Actions.ts | 9 ++++++--- modern/src/utils.ts | 34 ++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/modern/src/Actions.ts b/modern/src/Actions.ts index 3212c223..4d15b98d 100644 --- a/modern/src/Actions.ts +++ b/modern/src/Actions.ts @@ -40,9 +40,12 @@ export function gotSkinZip(zip: JSZip, store: ModernStore) { await Utils.readXml(zip, "skin.xml"), zip ); - const xmlTree = Utils.mapTree(rawXmlTree, (node: XmlNode) => { - return { ...node, uid: Utils.getId() }; - }); + const xmlTree = Utils.mapTreeBreadth( + rawXmlTree, + (node: XmlNode, parent: XmlNode) => { + return { ...node, uid: Utils.getId(), parent }; + } + ); dispatch(setXmlTree(xmlTree)); diff --git a/modern/src/utils.ts b/modern/src/utils.ts index 60cf5f22..9abe3cd5 100644 --- a/modern/src/utils.ts +++ b/modern/src/utils.ts @@ -3,30 +3,40 @@ import { xml2js } from "xml-js"; import { XmlNode } from "./types"; let nextId = 0; -export function getId() { +export function getId(): number { return nextId++; } -// Depth-first tree map -export function mapTree(node, cb) { +// Breadth-first tree map +// TODO: Type this so the return type is different than the initial type +// NOTE: This does not apply the callback to the root node. It probably should, +// but I'm too lazy to figure out how to write it. +export function mapTreeBreadth( + node: T, + cb: (node: T, parent: T) => T +) { const children = node.children || []; - return cb({ ...node, children: children.map(child => mapTree(child, cb)) }); + const mappedChildren = children.map(child => { + const newChild = cb(child, node); + return mapTreeBreadth(newChild, cb); + }); + return { ...node, children: mappedChildren }; } -export function isPromise(obj) { +export function isPromise(obj: any): boolean { return obj && typeof obj.then === "function"; } -export function isString(obj) { +export function isString(obj: any): boolean { return typeof obj === "string"; } -export function isObject(obj) { +export function isObject(obj: any): boolean { return obj === Object(obj); } // Convert windows filename slashes to forward slashes -function fixFilenameSlashes(filename) { +function fixFilenameSlashes(filename: string): string { return filename.replace(/\\/g, "/"); } @@ -200,11 +210,15 @@ export function findParent( } // Operations on trees -export function findParentNodeOfType(node, type: Set) { +export function findParentNodeOfType< + T extends { parent: T | null; name: string } +>(node: T, type: Set): T { return findParent(node, n => type.has(n.name)); } -export function findParentOrCurrentNodeOfType(node, type) { +export function findParentOrCurrentNodeOfType< + T extends { parent: T | null; name: string } +>(node: T, type: Set): T { if (type.has(node.name)) { return node; }