Skip to content
Snippets Groups Projects
utils.ts 2.68 KiB
Newer Older
  • Learn to ignore specific revisions
  • import type { DialogMap, DialogOption, DialogSet } from "./types";
    
    
    /**
     * Returns true, if input is a valid name of a dialogSet.
     * Intended to protect from loading anything other than dialogSet json.
     * @param input input to check
     */
    function isValidDialogSetName(input: unknown) {
      if (typeof input !== "string") {
        return false;
      }
      if (input.length === 0) {
        return false;
      }
      if (input.length > 50) {
        return false;
      }
      return !/[^a-zA-Z0-9\-\_]/i.test(input);
    }
    
    function getHashValue(): string {
      return window.location.hash.substr(1);
    }
    
    /**
     * Fetch a dialogSet based on the hash value
     */
    export async function fetchDialogSet(): Promise<DialogSet> {
      const setName = getHashValue();
      if (!isValidDialogSetName(setName))
        throw new Error("Name is not valid dialogSet name");
    
      const dialogSetUrl = "./dialogs/" + setName + ".json";
    
      try {
        const dialogSet: DialogSet = await (await fetch(dialogSetUrl)).json();
        return dialogSet;
      } catch (error) {
        throw error;
      }
    }
    
    
    export function findDialogSetProblems(dialogSet: DialogSet) {
      const dialogReferenceProblems = checkForInvalidDialogReferences(dialogSet);
      return [...dialogReferenceProblems];
    }
    
    interface DialogReferenceProblem {
      type: "DialogReferenceProblem";
      sourceDialog: string;
      text: string;
    }
    
    function checkForInvalidDialogReferences(
      dialogSet: DialogSet
    ): DialogReferenceProblem[] {
      const dialogs = dialogSet.dialogs;
      const problems: DialogReferenceProblem[] = [];
      const allDialogKeys = Object.keys(dialogs);
      const allLinkedToDialogKeys: Set<string> = new Set();
      for (const dialogName of allDialogKeys) {
        // TODO check all buttons for invalid references
        for (const { text, linksToDialog } of dialogs[dialogName].options) {
          allLinkedToDialogKeys.add(linksToDialog);
          if (!allDialogKeys.includes(linksToDialog)) {
            problems.push({
              type: "DialogReferenceProblem",
              sourceDialog: dialogName,
              text: `Dialog ${dialogName}'s option "${text}" links to unknown dialog '${linksToDialog}'`,
            });
          }
    
          if (linksToDialog === dialogName) {
            problems.push({
              type: "DialogReferenceProblem",
              sourceDialog: dialogName,
              text: `Dialog ${dialogName}'s option "${text}" links to itself!`,
            });
          }
        }
      }
    
      for (const dialogName of allDialogKeys) {
        if (
          !allLinkedToDialogKeys.has(dialogName) &&
          dialogSet.startDialogName !== dialogName
        ) {
          problems.push({
            type: "DialogReferenceProblem",
            sourceDialog: dialogName,
            text: `Dialog ${dialogName} is unreachable: Neither linked to from any other dialog, nor startDialog`,
          });
        }
      }
      return problems;
    }