UNPKG

@knapsack/app

Version:

Build Design Systems with Knapsack

170 lines 6.03 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FileDb = void 0; const file_utils_1 = require("@knapsack/file-utils"); const os_1 = __importDefault(require("os")); const fs_extra_1 = __importDefault(require("fs-extra")); const chokidar_1 = __importDefault(require("chokidar")); const schema_utils_1 = require("@knapsack/schema-utils"); const md5_1 = __importDefault(require("md5")); const utils_1 = require("@knapsack/utils"); const events_1 = require("../events"); class FileDb { /** * Full path to file used for storage */ filePath; type; // config: ConfigType; validationSchema; defaults; orderAlphabetically; fileHashes; #singleQuote; constructor({ filePath, // dbDir, // name, type = 'json', defaults, validationSchema, writeFileIfAbsent = true, orderAlphabetically = false, }) { this.orderAlphabetically = orderAlphabetically; this.type = type; this.validationSchema = validationSchema; this.filePath = filePath; this.fileHashes = new Map(); this.defaults = defaults; this.#singleQuote = true; const exists = fs_extra_1.default.existsSync(this.filePath); if (writeFileIfAbsent && !exists) { const { contents } = this.serialize(defaults); fs_extra_1.default.writeFileSync(this.filePath, contents); } } async init(_opt) { const prettierConfig = await (0, file_utils_1.getPrettierConfig)(this.filePath); this.#singleQuote = prettierConfig?.singleQuote ?? this.#singleQuote; } watchFiles({ handleChange, extraPaths = [], }) { if (!handleChange) return; // Start watching the file in case user manually changes it so we can re-read it into memory const watcher = chokidar_1.default.watch([this.filePath, ...extraPaths], { ignoreInitial: true, }); watcher.on('all', async (eventName, path) => { let hash = ''; try { const dbString = await (0, file_utils_1.readFile)(path); hash = (0, md5_1.default)(dbString); } catch (e) { // oh well } const oldHash = this.fileHashes.get(path); if (hash !== oldHash) { this.fileHashes.set(path, hash); handleChange(path); } }); events_1.knapsackEvents.onShutdown(() => watcher.close()); return watcher; } /** * Ensure the data is good during run-time by using provided JSON Schemas to validate * Requires `validationSchema` to be passed in during initial creation * @throws Error if it's not valid */ validateConfig(config) { if (!this.validationSchema) return; const { ok, message, errors } = (0, schema_utils_1.validateDataAgainstSchema)(this.validationSchema, config); if (ok) return; const msg = [ `Data validation error for ${this.filePath}`, 'The data:', JSON.stringify(config, null, ' '), '', 'The error:', message, JSON.stringify(errors, null, ' '), ].join('\n'); throw new Error(msg); } serialize(config) { this.validateConfig(config); switch (this.type) { case 'json': { return { contents: JSON.stringify(this.orderAlphabetically ? (0, utils_1.sortKeysRecursive)(config) : config, null, ' ') + os_1.default.EOL, encoding: 'utf8', }; } case 'yml': { // no need to run through formatCodeSync, it's already formatted return { contents: (0, file_utils_1.stringifyYaml)(this.orderAlphabetically ? (0, utils_1.sortKeysRecursive)(config) : config, { doubleQuote: !this.#singleQuote }), encoding: 'utf8', }; } default: throw new Error('Un-supported type used'); } } parse(fileString) { let config; switch (this.type) { case 'json': config = JSON.parse(fileString); this.validateConfig(config); return config; case 'yml': config = (0, file_utils_1.parseYaml)(fileString); this.validateConfig(config); return config; default: throw new Error('Un-supported type used'); } } async read() { const dbString = await (0, file_utils_1.readFile)(this.filePath); return this.parse(dbString); } readSync() { const dbString = fs_extra_1.default.readFileSync(this.filePath, 'utf8'); return this.parse(dbString); } async savePrep(config = this.defaults) { this.validateConfig(config); const { contents, encoding } = this.serialize(config); return [ { contents, encoding, path: this.filePath, }, ]; } // async write(config: ConfigType, { sync = false } = {}): Promise<string> { // const { contents, path, encoding } = this.savePrep(config); // if (sync) { // fs.writeFileSync(path, contents, { encoding }); // } else { // await fs.writeFile(path, contents, { encoding }); // } // return path; // } async getData() { const config = await this.read(); this.validateConfig(config); return config; } getDataSync() { const config = this.readSync(); this.validateConfig(config); return config; } } exports.FileDb = FileDb; //# sourceMappingURL=file-db.js.map