From 3f43ab5abaedca8dad66e2b52acb7335cb60a868 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 10 Sep 2019 14:59:26 -0700 Subject: [PATCH] Fix script to extract maki methods from a directory of .wal files --- modern/src/maki-interpreter/objects.js | 22 +++- .../tools/extract-functions.js | 105 ++++++++++++------ package.json | 4 +- yarn.lock | 82 ++++++++++++-- 4 files changed, 168 insertions(+), 45 deletions(-) mode change 100644 => 100755 modern/src/maki-interpreter/tools/extract-functions.js diff --git a/modern/src/maki-interpreter/objects.js b/modern/src/maki-interpreter/objects.js index 83ef8416..6c14a8ae 100644 --- a/modern/src/maki-interpreter/objects.js +++ b/modern/src/maki-interpreter/objects.js @@ -3977,4 +3977,24 @@ function getObjectFunction(klass, functionName) { return getObjectFunction(klass.parentClass, functionName); } -module.exports = { objects, getFormattedId, getClass, getObjectFunction }; +function getFunctionObject(klass, functionName) { + const method = klass.functions.find(func => { + // TODO: This could probably be normalized at load time, or evern sooner. + return func.name.toLowerCase() === functionName.toLowerCase(); + }); + if (method != null) { + return klass; + } + if (klass.parentClass == null) { + throw new Error(`Could not find method ${functionName} on ${klass.name}.`); + } + return getFunctionObject(klass.parentClass, functionName); +} + +module.exports = { + objects, + getFormattedId, + getClass, + getObjectFunction, + getFunctionObject, +}; diff --git a/modern/src/maki-interpreter/tools/extract-functions.js b/modern/src/maki-interpreter/tools/extract-functions.js old mode 100644 new mode 100755 index 8f274536..559ea6a2 --- a/modern/src/maki-interpreter/tools/extract-functions.js +++ b/modern/src/maki-interpreter/tools/extract-functions.js @@ -1,48 +1,83 @@ -const fs = require("fs"); -const { parse } = require("../"); -const JSZip = require("jszip"); +#!/usr/bin/env node -async function getFunctionNames(absolutePath) { +const fs = require("fs"); +const path = require("path"); +const parse = require("../parser").default; +const JSZip = require("jszip"); +const { getClass, getFunctionObject } = require("../objects"); +const glob = require("glob"); + +function findWals(parentDir) { + return new Promise((resolve, reject) => { + glob("**/*.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] = 1; + } else { + summaryObj[key]++; + } + return summaryObj; + }, Object.assign({}, obj1)); +} + +async function getCallCountsFromWal(absolutePath) { const buffer = fs.readFileSync(absolutePath); const zip = await JSZip.loadAsync(buffer); const files = zip.file(/\.maki$/); const buffers = await Promise.all( files.map(file => file.async("nodebuffer")) ); - const functionNames = buffers.reduce((_functionNames, buf) => { - const maki = parse(buf); - maki.functionNames.forEach(func => { - const className = maki.types[func.classType]; - _functionNames.add(`${className}::${func.name}`); - }); - return _functionNames; - }, new Set()); - return functionNames; + return buffers.map(getCallCountsFromMaki).reduce(sumCountObjects); } -async function main(paths) { - const results = await Promise.all( - paths.map(async path => { - const functionNames = await getFunctionNames(path); - return { path, functionNames }; +function getCallCountsFromMaki(buffer) { + const maki = parse(buffer); + return maki.commands + .filter(command => command.opcode === 112) + .map(command => { + const method = maki.methods[command.arg]; + const classId = maki.classes[method.typeOffset]; + const klass = getClass(classId); + if (klass == null) { + throw new Error(`Unknown class ID: ${classId}`); + } + const parentClass = getFunctionObject(klass, method.name); + return `${parentClass.name}.${method.name.toLowerCase()}`; }) - ); - const functionCounts = {}; - results.forEach(skin => { - skin.functionNames.forEach(name => { - const originalCount = functionCounts[name]; - functionCounts[name] = (originalCount || 0) + 1; - }); - }); - console.log({ - totalFunctionCount: Object.keys(functionCounts).length, - // functionCounts - }); + .map(methodName => ({ [methodName]: 1 })) + .reduce(sumCountObjects, {}); } -const paths = [ - "/Volumes/Mobile Backup/skins/skins/dump/Stylish/micro/micro.wal", - "/Volumes/Mobile Backup/skins/skins/random/Winamp Skins/Skins/WTF/Almin_Agic_Skin.wal", -]; +function setObjectValuesToOne(obj) { + const newObj = {}; + Object.keys(obj).forEach(key => { + if (obj[key] != null) { + newObj[key] = 1; + } + }); -main(paths); + return newObj; +} + +async function main(parentDir) { + const paths = await findWals(parentDir); + const callCounts = await Promise.all(paths.map(getCallCountsFromWal)); + const totalCalls = callCounts.reduce(sumCountObjects); + const foundInSkins = callCounts + .map(setObjectValuesToOne) + .reduce(sumCountObjects); + + const result = { totalCalls, foundInSkins }; + console.log(JSON.stringify(result, null, 2)); +} + +main(path.join(__dirname, "../../../skins/")); diff --git a/package.json b/package.json index eeb4437d..20b90a9f 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "build-skin-png": "rm skins/base-2.91-png.wsz && cd skins/base-2.91-png && zip -x .* -x 'Skining Updates.txt' -r ../base-2.91-png.wsz .", "compile-skin": "node scripts/compileSkin.js > css/base-skin.css", "skin-info": "unzip -vl skins/base-2.91.wsz", - "build-presets": "node scripts/parsePresetFiles.js > presets/builtin.json" + "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" }, "repository": { "type": "git", @@ -51,6 +52,7 @@ "homepage": "https://github.com/captbaritone/webamp/", "devDependencies": { "@babel/core": "^7.0.0", + "@babel/node": "^7.6.1", "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", "@babel/plugin-syntax-dynamic-import": "^7.0.0", diff --git a/yarn.lock b/yarn.lock index 64166537..1deeaf8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -237,6 +237,18 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/node@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@babel/node/-/node-7.6.1.tgz#84f8f4f1d86647d99537a681f32e65e70bb59f19" + integrity sha512-q2sJw+7aES/5wwjccECJfOuIgM1XIbZcn7b63JZM6VpaZwvOq913jL+tXRIn41Eg/Hr+BeIGWnvnjLTuT579pA== + dependencies: + "@babel/polyfill" "^7.6.0" + "@babel/register" "^7.6.0" + commander "^2.8.1" + lodash "^4.17.13" + node-environment-flags "^1.0.5" + v8flags "^3.1.1" + "@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3": version "7.2.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.3.tgz#32f5df65744b70888d17872ec106b02434ba1489" @@ -575,6 +587,14 @@ core-js "^2.5.7" regenerator-runtime "^0.12.0" +"@babel/polyfill@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.6.0.tgz#6d89203f8b6cd323e8d946e47774ea35dc0619cc" + integrity sha512-q5BZJI0n/B10VaQQvln1IlDK3BTBJFbADx7tv+oXDPIDZuTo37H5Adb9jhlXm/fEN4Y7/64qD9mnrJJG7rmaTw== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.2" + "@babel/preset-env@^7.0.0": version "7.2.3" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.2.3.tgz#948c8df4d4609c99c7e0130169f052ea6a7a8933" @@ -638,6 +658,17 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-typescript" "^7.1.0" +"@babel/register@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.6.0.tgz#76b6f466714680f4becafd45beeb2a7b87431abf" + integrity sha512-78BomdN8el+x/nkup9KwtjJXuptW5oXMFmP11WoM2VJBjxrKv4grC3qjpLL8RGGUYUGsm57xnjYFM2uom+jWUQ== + dependencies: + find-cache-dir "^2.0.0" + lodash "^4.17.13" + mkdirp "^0.5.1" + pirates "^4.0.0" + source-map-support "^0.5.9" + "@babel/runtime@^7.0.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f" @@ -2523,6 +2554,11 @@ commander@^2.18.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" +commander@^2.8.1, commander@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + commander@^2.9.0: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" @@ -2535,11 +2571,6 @@ commander@~2.17.1: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" -commander@~2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== - commander@~2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" @@ -2715,7 +2746,7 @@ core-js@^2.4.0, core-js@^2.5.7: version "2.6.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042" -core-js@^2.5.0: +core-js@^2.5.0, core-js@^2.6.5: version "2.6.9" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== @@ -5065,6 +5096,13 @@ homedir-polyfill@^1.0.0: dependencies: parse-passwd "^1.0.0" +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + hoopy@^0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" @@ -6775,7 +6813,7 @@ lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.3 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA== -lodash@^4.17.14, lodash@^4.17.15: +lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -7350,6 +7388,14 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" +node-environment-flags@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" + integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw== + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -8036,7 +8082,7 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" -pirates@^4.0.1: +pirates@^4.0.0, pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== @@ -9481,6 +9527,11 @@ semver@5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" +semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -9761,6 +9812,14 @@ source-map-support@^0.5.6: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.5.9: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@~0.5.6: version "0.5.9" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" @@ -10797,6 +10856,13 @@ v8-compile-cache@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" +v8flags@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.1.3.tgz#fc9dc23521ca20c5433f81cc4eb9b3033bb105d8" + integrity sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w== + dependencies: + homedir-polyfill "^1.0.1" + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"