UNPKG

haystack-codegen

Version:

Project Haystack Core code generation tools

183 lines (182 loc) 6.36 kB
"use strict"; /* * Copyright (c) 2021, J2 Innovations. All Rights Reserved */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolvePodsNamespace = exports.resolveDefaultNamespace = void 0; const haystack_core_1 = require("haystack-core"); const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); const util_1 = require("util"); const safe_1 = __importDefault(require("colors/safe")); const adm_zip_1 = __importDefault(require("adm-zip")); const yaml_1 = __importDefault(require("yaml")); const readFileAsync = (0, util_1.promisify)(fs_1.readFile); const readdirAsync = (0, util_1.promisify)(fs_1.readdir); /** * Resolve the default namespace from defs distributed with the project. * * @returns The default namespace. */ async function resolveDefaultNamespace() { const defsBuf = await readFileAsync(path_1.default.join(__dirname, '../rc/defs.zinc')); const grid = haystack_core_1.ZincReader.readValue(defsBuf.toString('utf-8')); return new haystack_core_1.HNamespace(grid); } exports.resolveDefaultNamespace = resolveDefaultNamespace; const DEF_FILE_EXTS = ['.trio', '.hayson.yaml', '.hayson.yml', '.hayson.json']; /** * Resolve the namespace from some POD files. * * @param podDir The directory to read the pod files from. * @param podFilter If non-empty, used to filter certain POD files. * @returns The generated namespace. */ async function resolvePodsNamespace(podDir, podFilter = '') { const podsToLibDefs = await getPodToLibDefs(podDir, podFilter); const pods = [...podsToLibDefs.keys()]; const logger = { warning(message) { console.log(' ' + safe_1.default.green(message)); }, error(message) { console.warn(' ' + safe_1.default.yellow(message)); }, fatal(message) { console.error(' ' + safe_1.default.red(message)); }, }; if (!pods.length) { logger.warning('No pods found.'); return new haystack_core_1.HNamespace(haystack_core_1.HGrid.make({})); } const loadLib = async (pod) => { const lib = podsToLibDefs.get(pod); return { name: pod.name, lib, dicts: readDictsFromPodLibFolder(pod), }; }; const scanner = () => pods.map(loadLib); return await new haystack_core_1.HNormalizer(scanner, logger).normalize(); } exports.resolvePodsNamespace = resolvePodsNamespace; /** * Asynchronously load POD to lib defs. * * This will filter out any POD files that don't have any defs. * * @param podDir The POD file directory. * @param podFilter If not empty, used to filter the POD files used. * @returns A map of pods to lib defs dicts. */ async function getPodToLibDefs(podDir, podFilter) { const pods = await getPods(podDir, podFilter); const map = new Map(); for (const pod of pods) { for (const ext of DEF_FILE_EXTS) { const dicts = readDicts(pod, `lib/lib${ext}`); if (dicts?.length) { map.set(pod, dicts[0]); break; } } } return map; } /** * Return an array of PODs. * * @param podDir The POD file directory. * @param podFilter If non-empty, used to filter the POD files used. * @returns An array of PODs. */ async function getPods(podDir, podFilter) { let files = await readdirAsync(podDir); files = files.filter((file) => file.toLowerCase().endsWith('.pod')); const fileNames = files.map((file) => file.substring(0, file.length - 4)); const zips = files.map((file) => new adm_zip_1.default(path_1.default.join(podDir, file))); return (fileNames .map((fileName, i) => ({ name: fileName, getAsset: (path) => { try { return zips[i].readAsText(path); } catch (err) { return undefined; } }, listFiles: (path) => zips[i] .getEntries() .map((entry) => entry.entryName) .filter((entryName) => entryName.startsWith(path)), })) // If specified, filter the POD files scanned. We have to do this for // SkySpark since some of the def library creation is dynamic. .filter((pod) => podFilter ? pod.name.startsWith(podFilter) : true)); } /** * Load the dicts from the POD lib folder. * * @param pod To load all the dicts from. * @returns An array of def/defx dicts. */ function readDictsFromPodLibFolder(pod) { const files = pod.listFiles('lib'); return files .filter((path) => { const lowerPath = path.toLowerCase(); return DEF_FILE_EXTS.some((ext) => lowerPath.endsWith(ext)); }) .map((path) => readDicts(pod, path) ?? []) .reduce((dicts, prev) => dicts.concat(prev), []); } function readDicts(pod, path) { const text = pod.getAsset(path); let dicts; if (text) { const lowerPath = path.toLowerCase(); try { if (lowerPath.endsWith('.trio')) { dicts = new haystack_core_1.TrioReader(text).readAllDicts(); } else if (lowerPath.endsWith('.hayson.json')) { dicts = convertHaysonToDicts(JSON.parse(text)); } else if (lowerPath.endsWith('.hayson.yaml') || lowerPath.endsWith('.hayson.yml')) { dicts = []; for (const decoded of yaml_1.default.parseAllDocuments(text).map((doc) => doc.toJSON())) { dicts = dicts.concat(convertHaysonToDicts(decoded)); } } } catch (error) { throw new Error(`Error parsing '${pod.name}.pod:/${path}' - ${error}`); } } return dicts; } function convertHaysonToDicts(hayson) { const dicts = []; function read(value) { if (value) { const hval = (0, haystack_core_1.makeValue)(value); if ((0, haystack_core_1.valueIsKind)(hval, haystack_core_1.Kind.Dict)) { dicts.push(hval); } } } if (Array.isArray(hayson)) { hayson.forEach(read); } else { read(hayson); } return dicts; }