webamp/modern/src/Actions.ts
Jordan Eldredge 3f6dfd91dd
Improve typing of .ts files in /modern (#950)
* Improve typing of Actions

* Make typing of MakiObjects more explicit

* Make parent optional

* Allow group to be initialized with all nulls

* Whitelist all runtime ts files for type checking

* Typecheck the entire modern codebase!

* Ignore typescript
2019-10-18 06:34:10 -07:00

121 lines
3.4 KiB
TypeScript

import {
MakiTree,
ModernAction,
ModernStore,
XmlTree,
XmlNode,
Thunk,
} from "./types";
import JSZip from "jszip";
import * as Utils from "./utils";
import initialize from "./initialize";
import initializeStateTree from "./initializeStateTree";
import { run } from "./maki-interpreter/virtualMachine";
import System from "./runtime/System";
import runtime from "./runtime";
import MakiObject from "./runtime/MakiObject";
import JsScript from "./runtime/JsScript";
export function setMakiTree(makiTree: MakiTree): ModernAction {
return { type: "SET_MAKI_TREE", makiTree };
}
export function setXmlTree(xmlTree: XmlTree): Thunk {
return async dispatch => {
dispatch({
type: "SET_XML_TREE",
xmlTree: await initializeStateTree(xmlTree),
});
};
}
export function gotSkinUrl(skinUrl: string, store: ModernStore): Thunk {
return async dispatch => {
const resp = await fetch(skinUrl);
dispatch(gotSkinBlob(await resp.blob(), store));
};
}
export function gotSkinBlob(blob: Blob, store: ModernStore): Thunk {
return async dispatch => {
dispatch(gotSkinZip(await JSZip.loadAsync(blob), store));
};
}
async function unloadSkin(makiTree: MakiTree): Promise<void> {
await Utils.asyncTreeFlatMap(makiTree, async (node: MakiObject) => {
if (node instanceof JsScript && node.system) {
node.system.onscriptunloading();
}
return node;
});
}
export function gotSkinZip(zip: JSZip, store: ModernStore): Thunk {
return async dispatch => {
// unload current skin if one has been loaded
if (store.getState().modernSkin.skinLoaded) {
await unloadSkin(store.getState().modernSkin.makiTree);
dispatch({ type: "SKIN_UNLOADED" });
}
const skinXml = await Utils.readXml(zip, "skin.xml");
if (skinXml == null) {
throw new Error("Could not find skin.xml in skin");
}
const rawXmlTree = await Utils.inlineIncludes(skinXml, zip);
const xmlTree = Utils.mapTreeBreadth(
rawXmlTree,
(node: XmlNode, parent: XmlNode) => {
return { ...node, uid: Utils.getId(), parent };
}
);
dispatch(setXmlTree(xmlTree));
const makiTree: MakiObject = await initialize(zip, xmlTree);
// Execute scripts
await Utils.asyncTreeFlatMap(makiTree, async (node: MakiObject) => {
if (!(node instanceof JsScript)) {
return node;
}
const scriptPath = node.getScriptPath();
if (scriptPath == null) {
return node;
}
if (scriptPath.endsWith("standardframe.maki")) {
// TODO: stop ignoring standardframe
return node;
}
// removes groupdefs from consideration (only run scripts when actually referenced by group)
if (Utils.findParentNodeOfType(node, new Set(["groupdef"]))) {
return node;
}
const scriptGroup = Utils.findParentNodeOfType(
node,
new Set(["group", "winampabstractionlayer", "wasabixml"])
);
node.system = new System(scriptGroup, store);
const script = await Utils.readUint8array(zip, scriptPath);
if (script == null) {
console.warn(`Unable to find script at ${scriptPath}`);
return node;
}
run({
runtime,
data: script,
system: node.system,
log: false,
});
return node;
});
dispatch(setMakiTree(makiTree));
};
}
export function setVolume(volume: number): ModernAction {
return { type: "SET_VOLUME", volume };
}