All files / src/lib/project loadEngineSchema.ts

41.3% Statements 19/46
10.34% Branches 3/29
50% Functions 1/2
39.53% Lines 17/43

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 101 102 103 104 105 106 107 108 109 110 1112x 2x 2x 2x                       2x                 2x       3x   3x 5x     3x 4x   4x   4x 2x         2x       3x     2x                                                                                                                    
import Path from "path";
import { readJSON, pathExists } from "fs-extra";
import { globSync } from "lib/helpers/glob";
import { defaultEngineMetaPath } from "consts";
import type {
  SceneTypeSchema,
  EngineFieldSchema,
} from "store/features/engine/engineState";
 
export interface EngineSchema {
  fields: EngineFieldSchema[];
  sceneTypes: SceneTypeSchema[];
  consts: Record<string, number>;
}
 
const defaultSceneTypes: SceneTypeSchema[] = [
  { key: "TOPDOWN", label: "GAMETYPE_TOP_DOWN" },
  { key: "PLATFORM", label: "GAMETYPE_PLATFORMER" },
  { key: "ADVENTURE", label: "GAMETYPE_ADVENTURE" },
  { key: "SHMUP", label: "GAMETYPE_SHMUP" },
  { key: "POINTNCLICK", label: "GAMETYPE_POINT_N_CLICK" },
  { key: "LOGO", label: "GAMETYPE_LOGO" },
];
 
export const mergeSceneTypes = (
  sceneTypes: SceneTypeSchema[],
  extraSceneTypes: Partial<SceneTypeSchema>[],
): SceneTypeSchema[] => {
  const baseMap = new Map<string, SceneTypeSchema>();
 
  for (const scene of sceneTypes) {
    baseMap.set(scene.key, scene);
  }
 
  for (const override of extraSceneTypes) {
    Iif (!override.key) continue;
 
    const base = baseMap.get(override.key);
 
    if (base) {
      baseMap.set(override.key, {
        ...base,
        ...override,
      });
    } else {
      baseMap.set(override.key, override as SceneTypeSchema);
    }
  }
 
  return Array.from(baseMap.values());
};
 
export const loadEngineSchema = async (
  projectRoot: string,
): Promise<EngineSchema> => {
  const localEngineJsonPath = Path.join(
    projectRoot,
    "assets",
    "engine",
    "engine.json",
  );
  const pluginsPath = Path.join(projectRoot, "plugins");
 
  let defaultEngine: Partial<EngineSchema> = {};
  let localEngine: Partial<EngineSchema> = {};
 
  try {
    localEngine = await readJSON(localEngineJsonPath);
  } catch {
    defaultEngine = await readJSON(defaultEngineMetaPath);
  }
 
  let fields = localEngine.fields || defaultEngine.fields || [];
  let sceneTypes =
    localEngine.sceneTypes || defaultEngine.sceneTypes || defaultSceneTypes;
  let consts = localEngine.consts || defaultEngine.consts || {};
  let extraSceneTypes: Partial<SceneTypeSchema>[] = [];
 
  const enginePlugins = globSync("**/engine", {
    cwd: pluginsPath,
    absolute: true,
  });
  for (const enginePluginPath of enginePlugins) {
    const enginePluginJsonPath = Path.join(enginePluginPath, "engine.json");
    if (await pathExists(enginePluginJsonPath)) {
      try {
        const pluginEngine: EngineSchema = await readJSON(enginePluginJsonPath);
        if (pluginEngine.fields?.length) {
          fields = fields.concat(pluginEngine.fields);
        }
        if (pluginEngine.sceneTypes?.length) {
          extraSceneTypes = extraSceneTypes.concat(pluginEngine.sceneTypes);
        }
        if (pluginEngine.consts) {
          consts = { ...consts, ...pluginEngine.consts }; // Plugin consts override existing ones
        }
      } catch (e) {
        console.warn(e);
      }
    }
  }
 
  sceneTypes = mergeSceneTypes(sceneTypes, extraSceneTypes);
 
  return {
    fields,
    sceneTypes,
    consts,
  };
};