aboutsummaryrefslogtreecommitdiffstats
path: root/utils/loader.ts
blob: adfa40fb44cc70960b8ce0759e23d1134487552c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { parse } from 'yaml';
import { loadCategoriesFromJson, loadItemsFromJson, loadQuestsFromJson } from '~/lib/questsLoader';

export async function openFileSystem() {
  try {
    return await (window as any).showDirectoryPicker();
  } catch (e) {
    return undefined;
  }
}

export async function enumerateQuestDirectory(dirHandle: any) {
  let configFile: any = null;
  let categoryFile: any = null;
  let questsDirectory: any = null;
  let itemsDirectory: any = null;

  for await (const [name, handle] of dirHandle) {
    if (name === 'quests' && handle.kind === 'directory') {
      questsDirectory = handle;
    } else if (name === 'items' && handle.kind === 'directory') {
      itemsDirectory = handle;
    } else if (name === 'config.yml' && handle.kind === 'file') {
      configFile = handle;
    } else if (name === 'categories.yml' && handle.kind === 'file') {
      categoryFile = handle;
    }
  }

  if (!configFile) {
    throw Error('invalid quest directory');
  }

  const [questFiles, itemFiles] = await Promise.all([
    questsDirectory ? listAllFilesAndDirs(questsDirectory) : [],
    itemsDirectory ? listAllFilesAndDirs(itemsDirectory) : [],
  ]);
  const [categories, quests, items] = await Promise.all([
    (async () => {
      if (!categoryFile) {
        return [];
      }

      const file: any = await categoryFile.getFile();
      const text: string = await file.text();
      const parsedYaml: any = parse(text);

      return loadCategoriesFromJson(parsedYaml.categories);
    })(),
    (async () => {
      if (!questFiles) {
        return [];
      }

      const allQuests = await Promise.all(
        questFiles
          .filter(({ name, handle, kind }) => name.endsWith('.yml'))
          .map(async ({ name, handle, kind }) => {
            const file: any = await handle.getFile();
            const text: string = await file.text();
            return [name.replace('.yml', ''), parse(text)];
          })
      );

      return loadQuestsFromJson(Object.fromEntries(allQuests));
    })(),
    (async () => {
      if (!itemFiles) {
        return [];
      }

      const allItems = await Promise.all(
        itemFiles
          .filter(({ name, handle, kind }) => name.endsWith('.yml'))
          .map(async ({ name, handle, kind }) => {
            const file: any = await handle.getFile();
            const text: string = await file.text();
            return [name.replace('.yml', ''), parse(text)];
          })
      );

      return loadItemsFromJson(Object.fromEntries(allItems));
    })(),
  ]);

  return { categories, quests, items };
}

async function listAllFilesAndDirs(dirHandle: any): Promise<any[]> {
  const files = [];
  for await (const [name, handle] of dirHandle) {
    const { kind } = handle;
    if (handle.kind === 'directory') {
      files.push(...(await listAllFilesAndDirs(handle)));
    } else {
      files.push({ name, handle, kind });
    }
  }
  return files;
}