From 29c0034364d55541ead25b038d12e429e85bde00 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Thu, 10 Oct 2019 06:36:00 -0700 Subject: [PATCH] Utility to extract info about XML --- modern/resources/attribute-skin-data.json | 1 + .../tools/extract-attributes.js | 110 ++++++++++++++++++ modern/src/utils.ts | 5 +- package.json | 3 +- 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 modern/resources/attribute-skin-data.json create mode 100755 modern/src/maki-interpreter/tools/extract-attributes.js diff --git a/modern/resources/attribute-skin-data.json b/modern/resources/attribute-skin-data.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/modern/resources/attribute-skin-data.json @@ -0,0 +1 @@ +{} diff --git a/modern/src/maki-interpreter/tools/extract-attributes.js b/modern/src/maki-interpreter/tools/extract-attributes.js new file mode 100755 index 00000000..f3ef6267 --- /dev/null +++ b/modern/src/maki-interpreter/tools/extract-attributes.js @@ -0,0 +1,110 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require("path"); +const parse = require("../parser").default; +const JSZip = require("jszip"); +const Utils = require("../../utils"); +const { getClass, getFunctionObject, getFormattedId } = require("../objects"); +const glob = require("glob"); + +const CALL_OPCODES = new Set([24, 112]); +const SKIN_FILENAME_BLACKLIST = new Set(["Fuzzy_Muffins.wal"]); + +function findWals(parentDir) { + return new Promise((resolve, reject) => { + glob("**/cPro2_Aluminum_1_1.wal", { cwd: parentDir }, (err, files) => { + if (err) { + return reject(err); + } + resolve(files.map(filePath => path.join(parentDir, filePath))); + }); + }); +} + +function sumCountObjects(obj1, obj2) { + return Object.keys(obj2).reduce((summaryObj, key) => { + if (summaryObj[key] == null) { + summaryObj[key] = obj2[key]; + } else { + summaryObj[key] += obj2[key]; + } + return summaryObj; + }, Object.assign({}, obj1)); +} + +async function getAttributeDataFromWal(absolutePath) { + const buffer = fs.readFileSync(absolutePath); + const zip = await JSZip.loadAsync(buffer); + const skinXml = await Utils.readXml(zip, "skin.xml"); + if (skinXml == null) { + return []; + } + const rawXmlTree = await Utils.inlineIncludes(skinXml, zip); + + const nodeTypes = []; + Utils.mapTreeBreadth(rawXmlTree, node => { + if (node.type === "element") { + nodeTypes.push({ + name: node.name.toLowerCase(), + attributes: + node.attributes == null + ? [] + : Object.keys(node.attributes).map(attr => attr.toLowerCase()), + }); + } + return node; + }); + return nodeTypes; +} + +async function main(parentDir) { + const errors = []; + const paths = await findWals(parentDir); + const attributeData = []; + + // Originally we moved to doing one skin at a time because we thougth it was + // causing memory issues, now we know it's not, but it's still faster to do + // one at a time for some reason. ¯\_(ツ)_/¯ + for (const walPath of paths) { + try { + const fileName = path.basename(walPath); + if (SKIN_FILENAME_BLACKLIST.has(fileName)) { + continue; + } + console.error(`Working on ${walPath}`); + attributeData.push(...(await getAttributeDataFromWal(walPath))); + } catch (e) { + const errorLine = e.toString().split("\n")[0]; + errors.push({ [errorLine]: 1 }); + // TODO: Investigate these. + console.error(`Error getting call data from ${walPath}`, e); + } + } + + const summary = attributeData.reduce((sum, attrs) => { + if (sum[attrs.name] == null) { + sum[attrs.name] = { + count: 0, + attributes: {}, + }; + } + sum[attrs.name].count++; + const nodeAttrs = sum[attrs.name].attributes; + attrs.attributes.forEach(attr => { + if (nodeAttrs[attr] == null) { + nodeAttrs[attr] = 1; + } else { + nodeAttrs[attr]++; + } + }); + return sum; + }, {}); + + if (errors.length) { + console.error(JSON.stringify(errors.reduce(sumCountObjects, {}), null, 2)); + } + console.log(JSON.stringify(summary, null, 2)); +} + +main("/Volumes/Mobile Backup/skins/skins/random/Winamp Skins/Skins/"); diff --git a/modern/src/utils.ts b/modern/src/utils.ts index 76108c0a..eb9024b9 100644 --- a/modern/src/utils.ts +++ b/modern/src/utils.ts @@ -434,7 +434,10 @@ function handleMouseMove(e: MouseEvent): void { mousePosition = { x: e.clientX, y: e.clientY }; } -document.addEventListener("mousemove", handleMouseMove); +// It's possible we are in a Node envionment +if (typeof document !== "undefined") { + document.addEventListener("mousemove", handleMouseMove); +} export function getMousePosition() { return mousePosition; diff --git a/package.json b/package.json index 11f8bab3..043a0293 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "skin-info": "unzip -vl skins/base-2.91.wsz", "build-presets": "node scripts/parsePresetFiles.js > presets/builtin.json", "analyze-wals": "babel-node --extensions=\".ts,.js,.tsx\" modern/src/maki-interpreter/tools/extract-functions.js > modern/resources/maki-skin-data.json", - "extract-object-types": "babel-node --extensions=\".ts,.js,.tsx\" modern/src/maki-interpreter/tools/extract-object-types.js" + "extract-object-types": "babel-node --extensions=\".ts,.js,.tsx\" modern/src/maki-interpreter/tools/extract-object-types.js", + "extract-attributes": "babel-node --extensions=\".ts,.js,.tsx\" modern/src/maki-interpreter/tools/extract-attributes.js > modern/resources/attribute-skin-data.json" }, "repository": { "type": "git",