"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; var __accessCheck = (obj, member, msg) => { if (!member.has(obj)) throw TypeError("Cannot " + msg); }; var __privateGet = (obj, member, getter) => { __accessCheck(obj, member, "read from private field"); return getter ? getter.call(obj) : member.get(obj); }; var __privateAdd = (obj, member, value) => { if (member.has(obj)) throw TypeError("Cannot add the same private member more than once"); member instanceof WeakSet ? member.add(obj) : member.set(obj, value); }; var __privateSet = (obj, member, value, setter) => { __accessCheck(obj, member, "write to private field"); setter ? setter.call(obj, value) : member.set(obj, value); return value; }; // src/index.ts var src_exports = {}; __export(src_exports, { CE_CHANGE_KIND: () => CE_CHANGE_KIND, CE_COLUMN_ATTRIBUTE: () => CE_COLUMN_ATTRIBUTE, CE_COMMAND_LIST: () => CE_COMMAND_LIST, CE_DEFAULT_VALUE: () => CE_DEFAULT_VALUE, CE_ENTITY_VERSION_FROM: () => CE_ENTITY_VERSION_FROM, CE_IMAGE_FORMAT: () => CE_IMAGE_FORMAT, CE_MERMAID_THEME: () => CE_MERMAID_THEME, CE_OUTPUT_COMPONENT: () => CE_OUTPUT_COMPONENT, CE_OUTPUT_FORMAT: () => CE_OUTPUT_FORMAT, CE_PROJECT_NAME_FROM: () => CE_PROJECT_NAME_FROM, CE_RECORD_KIND: () => CE_RECORD_KIND, CE_TEMPLATE_NAME: () => CE_TEMPLATE_NAME, Logger: () => Logger, SymbolDataSource: () => SymbolDataSource, SymbolDefaultTemplate: () => SymbolDefaultTemplate, SymbolLogger: () => SymbolLogger, SymbolTemplate: () => SymbolTemplate, SymbolTemplateRenderer: () => SymbolTemplateRenderer, TemplateRenderer: () => TemplateRenderer, applyPrettier: () => applyPrettier, betterMkdir: () => betterMkdir, buildDocumentCommandHandler: () => buildDocumentCommandHandler, buildOptionBuilder: () => buildOptionBuilder, building: () => building, cleanDocumentCommandHandler: () => cleanDocumentCommandHandler, cleaning: () => cleaning, commonOptionBuilder: () => commonOptionBuilder, compareDatabase: () => compareDatabase, configTemplate: () => configTemplate, container: () => container, createHtml: () => createHtml, createImageHtml: () => createImageHtml, createLogger: () => createLogger, createMarkdown: () => createMarkdown, createPdfHtml: () => createPdfHtml, dedupeManaToManyRelationRecord: () => dedupeManaToManyRelationRecord, defaultExclude: () => defaultExclude, documentOptionBuilder: () => documentOptionBuilder, ejecting: () => ejecting, flushDatabase: () => flushDatabase, getAutoCompleteSource: () => getAutoCompleteSource, getColumnAttributeKey: () => getColumnAttributeKey, getColumnHash: () => getColumnHash, getColumnRecord: () => getColumnRecord, getColumnType: () => getColumnType, getColumnWeight: () => getColumnWeight, getComment: () => getComment, getConfigContent: () => getConfigContent, getConfigFilePath: () => getConfigFilePath, getCwd: () => getCwd, getDataSource: () => getDataSource, getDatabaseName: () => getDatabaseName, getEntityHash: () => getEntityHash, getEntityName: () => getEntityName, getEntityPropertyName: () => getEntityPropertyName, getEntityRecord: () => getEntityRecord, getEntityRecords: () => getEntityRecords, getFileVersion: () => getFileVersion, getFindFile: () => getFindFile, getGlobFiles: () => getGlobFiles, getIndexHash: () => getIndexHash, getIndexRecord: () => getIndexRecord, getIndexRecords: () => getIndexRecords, getInverseRelationMetadata: () => getInverseRelationMetadata, getIsNullable: () => getIsNullable, getJoinColumn: () => getJoinColumn, getManyToManyEntityMetadata: () => getManyToManyEntityMetadata, getManyToManyJoinColumn: () => getManyToManyJoinColumn, getManyToOneJoinColumn: () => getManyToOneJoinColumn, getMetadata: () => getMetadata, getOutputDirPath: () => getOutputDirPath, getPackageName: () => getPackageName, getPlainRelationType: () => getPlainRelationType, getProjectName: () => getProjectName, getPuppeteerConfig: () => getPuppeteerConfig, getRelationHash: () => getRelationHash, getRelationRecord: () => getRelationRecord, getRelationRecords: () => getRelationRecords, getRenderData: () => getRenderData, getSlashEndRoutePath: () => getSlashEndRoutePath, getTemplate: () => getTemplate, getTemplateDirPath: () => getTemplateDirPath, getTemplateModulePath: () => getTemplateModulePath, getTemplatePath: () => getTemplatePath, getTemplates: () => getTemplates, getVersion: () => getVersion, initConfigCommandHandler: () => initConfigCommandHandler, initializing: () => initializing, loadDataSource: () => loadDataSource, loadTemplates: () => loadTemplates, openDatabase: () => openDatabase, outputOptionBuilder: () => outputOptionBuilder, preLoadConfig: () => preLoadConfig, processDatabase: () => processDatabase, templateEjectCommandHandler: () => templateEjectCommandHandler, writeToImage: () => writeToImage, writeToPdf: () => writeToPdf }); module.exports = __toCommonJS(src_exports); // src/common/getColumnHash.ts function getColumnHash(column) { const baseHash = [column.entity, column.dbName].join(":"); const base64 = Buffer.from(baseHash).toString("base64"); return base64; } // src/common/getDatabaseName.ts var import_util = require("util"); function getDatabaseName(options) { const name = options.database; if (typeof name === "string") { return name; } if (name instanceof Uint8Array) { return new import_util.TextDecoder().decode(name); } return "default"; } // src/common/getEntityHash.ts function getEntityHash(entity) { const baseHash = [entity.entity, entity.dbName].join(":"); const base64 = Buffer.from(baseHash).toString("base64"); return base64; } // src/common/getFileVersion.ts var import_jsonc_parser = require("jsonc-parser"); var import_semver = __toESM(require("semver")); function getFileVersion(buf) { const rawJson = buf.toString(); if (import_semver.default.valid(rawJson)) { return rawJson; } const parsed = (0, import_jsonc_parser.parse)(rawJson); const { version } = parsed; if (version == null || version === "") { throw new Error(`invalid version file: ${rawJson}`); } return version; } // src/common/getIndexHash.ts function getIndexHash(column) { const baseHash = [column.entity, column.dbName].join(":"); const base64 = Buffer.from(baseHash).toString("base64"); return base64; } // src/common/getPackageName.ts function getPackageName(json) { const { name } = json; if (typeof name === "string" && name !== "") { return name; } throw new Error("Cannot get project name from package.json"); } // src/configs/const-enum/CE_PROJECT_NAME_FROM.ts var CE_PROJECT_NAME_FROM = { DATABASE: "db", APPLICATION: "app" }; // src/common/getProjectName.ts async function getProjectName(dataSource, json, option) { if (option.projectName === CE_PROJECT_NAME_FROM.DATABASE) { if (dataSource.options.database != null) { const databaseName = getDatabaseName(dataSource.options); return databaseName; } const name2 = getPackageName(json); return name2; } const name = getPackageName(json); return name; } // src/configs/const-enum/CE_DEFAULT_VALUE.ts var CE_DEFAULT_VALUE = { CONFIG_FILE_NAME: ".erdiarc", TSCONFIG_FILE_NAME: "tsconfig.json", HTML_INDEX_FILENAME: "index.html", HTML_MERMAID_FILENAME: "mermaid.html", MARKDOWN_FILENAME: "erdia.md", DATABASE_FILENAME: "erdiadb.json", VERSION_FILENAME: ".erdiaverrc", TEMPLATES_PATH: "templates", DATA_SOURCE_FILE_FUZZY_SCORE_LIMIT: 50, OUTPUT_DIRECTORY_FUZZY_SCORE_LIMIT: 50 }; // src/configs/modules/getCwd.ts function getCwd(env) { if ((env.USE_INIT_CWD ?? "false") === "false") { return process.cwd(); } if (env.INIT_CWD != null) { return env.INIT_CWD; } return process.cwd(); } // src/modules/files/getFindFile.ts var import_find_up = __toESM(require("find-up")); async function getFindFile(filename, option) { const finded = await (0, import_find_up.default)(filename, option); return finded; } // src/modules/files/betterMkdir.ts var import_my_easy_fp = require("my-easy-fp"); var import_my_node_fp = require("my-node-fp"); var import_node_fs = __toESM(require("fs")); var import_pathe = __toESM(require("pathe")); async function betterMkdir(filePath) { const isFilePathExist = await (0, import_my_node_fp.exists)(filePath); if ((0, import_my_easy_fp.isFalse)(isFilePathExist)) { const extname = import_pathe.default.extname(filePath); const hasExtname = extname !== "" && extname.length > 0; if (hasExtname) { const dirPath = await (0, import_my_node_fp.getDirname)(filePath); await import_node_fs.default.promises.mkdir(dirPath, { recursive: true }); } else { await import_node_fs.default.promises.mkdir(filePath, { recursive: true }); } } } // src/modules/files/getOutputDirPath.ts var import_my_easy_fp2 = require("my-easy-fp"); var import_my_node_fp2 = require("my-node-fp"); var import_pathe2 = __toESM(require("pathe")); async function getOutputDirPath(option, cwd) { const outputDirPath = option.output ?? cwd; const resolvedOutputDirPath = import_pathe2.default.resolve(outputDirPath); if ((0, import_my_easy_fp2.isFalse)(await (0, import_my_node_fp2.exists)(resolvedOutputDirPath))) { await betterMkdir(import_pathe2.default.join(resolvedOutputDirPath)); return resolvedOutputDirPath; } if ((0, import_my_easy_fp2.isFalse)(await (0, import_my_node_fp2.isDirectory)(outputDirPath))) { return import_pathe2.default.resolve(await (0, import_my_node_fp2.getDirname)(outputDirPath)); } return import_pathe2.default.resolve(outputDirPath); } // src/common/getVersion.ts var import_dayjs = __toESM(require("dayjs")); var import_fs = __toESM(require("fs")); var import_pathe3 = __toESM(require("pathe")); async function getVersionFilename(option, versionFilename) { if (option.versionPath != null) { const filename2 = await getFindFile( import_pathe3.default.join(await getOutputDirPath({ output: option.versionPath }, getCwd(process.env)), versionFilename), { cwd: getCwd(process.env) } ); return filename2; } const filename = await getFindFile(versionFilename, { cwd: getCwd(process.env) }); return filename; } async function getVersion(json, option) { if (option.versionFrom === "package.json") { const { version } = json; if (!(typeof version === "string") || version == null) { throw new Error(`Cannot found version field in package.json`); } return { version }; } if (option.versionFrom === "file") { const getVersionFile = async () => { const filename = await getVersionFilename(option, CE_DEFAULT_VALUE.VERSION_FILENAME); if (filename != null) { return filename; } const fromConfig = await getVersionFilename(option, CE_DEFAULT_VALUE.CONFIG_FILE_NAME); return fromConfig; }; const versionFilename = await getVersionFile(); if (versionFilename == null) { throw new Error(`Cannot found version file: ${CE_DEFAULT_VALUE.VERSION_FILENAME}`); } const versionBuf = await import_fs.default.promises.readFile(versionFilename); const version = getFileVersion(versionBuf); return { version: version.trim() }; } return { version: `${(0, import_dayjs.default)().valueOf()}` }; } // src/modules/containers/container.ts var import_awilix = require("awilix"); var container = (0, import_awilix.createContainer)(); // src/modules/containers/keys/SymbolDataSource.ts var SymbolDataSource = Symbol("data-source"); // src/common/getMetadata.ts var import_dayjs2 = __toESM(require("dayjs")); var import_filenamify = __toESM(require("filenamify")); var import_read_pkg = __toESM(require("read-pkg")); async function getMetadata(option) { const dataSource = container.resolve(SymbolDataSource); const json = await (0, import_read_pkg.default)({ normalize: false }); const rawName = await getProjectName(dataSource, json, option); const name = (0, import_filenamify.default)(rawName, { replacement: "_" }); const { version } = await getVersion(json, option); return { name, title: option.title, version, createdAt: (0, import_dayjs2.default)().format(), updatedAt: (0, import_dayjs2.default)().format() }; } // src/common/getPlainRelationType.ts function getPlainRelationType(relationType) { if (relationType === "one-to-one") { return "one-to-one"; } if (relationType === "many-to-many") { return "many-to-many"; } return "one-to-many"; } // src/common/getRelationHash.ts function getRelationHash(relation) { const entities = [relation.entity, relation.inverseEntityName].sort((l, r) => l.localeCompare(r)); const plainRelationType = getPlainRelationType(relation.relationType); const baseHash = [...entities, plainRelationType].join(":"); const base64 = Buffer.from(baseHash).toString("base64"); return base64; } // src/creators/applyPretter.ts var import_consola = __toESM(require("consola")); var import_my_easy_fp3 = require("my-easy-fp"); async function applyPrettier(document, format, configPath) { try { const prettier = (await import("prettier")).default; const prettierConfig = await prettier.resolveConfig(configPath ?? "."); const formatted = await prettier.format(document, { ...prettierConfig ?? {}, parser: format === "md" ? "markdown" : format }); return formatted; } catch (caught) { const err = (0, import_my_easy_fp3.isError)(caught, new Error("unknown error raised from prettier appling function")); import_consola.default.error(err.message); import_consola.default.error(err.stack); return document; } } // src/configs/const-enum/CE_OUTPUT_COMPONENT.ts var CE_OUTPUT_COMPONENT = { TABLE: "table", ER: "er" }; // src/modules/containers/keys/SymbolTemplateRenderer.ts var SymbolTemplateRenderer = Symbol("template-renderer"); // src/templates/cosnt-enum/CE_TEMPLATE_NAME.ts var CE_TEMPLATE_NAME = { HTML_DOCUMENT_TOC: "html-document-toc", HTML_DOCUMENT: "html-document", HTML_MERMAID: "html-mermaid", HTML_MERMAID_TOC: "html-mermaid-toc", HTML_MERMAID_DIAGRAM: "html-mermaid-diagram", HTML_STYLE: "html-style", HTML_TABLE: "html-table", IMAGE_DOCUMENT: "image-document", IMAGE_MERMAID_DIAGRAM: "image-mermaid-diagram", IMAGE_STYLE: "image-style", MARKDOWN_DOCUMENT: "markdown-document", MARKDOWN_MERMAID_DIAGRAM: "markdown-mermaid-diagram", MARKDOWN_TABLE: "markdown-table", MARKDOWN_TOC: "markdown-toc", PDF_DOCUMENT_TOC: "pdf-document-toc", PDF_DOCUMENT: "pdf-document", PDF_MERMAID_DIAGRAM: "pdf-mermaid-diagram", PDF_STYLE: "pdf-style", PDF_TABLE: "pdf-table", CONFIG_JSON: "config-json" }; // src/creators/createHtml.ts var import_consola2 = __toESM(require("consola")); var import_pathe4 = __toESM(require("pathe")); async function getTables(option, renderData, outputDir) { if (!option.components.includes(CE_OUTPUT_COMPONENT.TABLE)) { return []; } const renderer = container.resolve(SymbolTemplateRenderer); const rawTables = await renderer.evaluate(CE_TEMPLATE_NAME.HTML_DOCUMENT, renderData); const prettiedTables = await applyPrettier(rawTables, "html", option.prettierConfig); const tablesFileName = import_pathe4.default.join(outputDir, CE_DEFAULT_VALUE.HTML_INDEX_FILENAME); return [ { dirname: import_pathe4.default.resolve(outputDir), filename: import_pathe4.default.resolve(tablesFileName), content: prettiedTables } ]; } async function getDiagram(option, renderData, outputDir) { if (!option.components.includes(CE_OUTPUT_COMPONENT.ER)) { return []; } const renderer = container.resolve(SymbolTemplateRenderer); const rawDiagram = await renderer.evaluate(CE_TEMPLATE_NAME.HTML_MERMAID, renderData); const prettiedDiagram = await applyPrettier(rawDiagram, "html", option.prettierConfig); const diagramFileName = option.components.includes(CE_OUTPUT_COMPONENT.TABLE) ? import_pathe4.default.join(outputDir, CE_DEFAULT_VALUE.HTML_MERMAID_FILENAME) : import_pathe4.default.join(outputDir, CE_DEFAULT_VALUE.HTML_INDEX_FILENAME); return [ { dirname: import_pathe4.default.resolve(outputDir), filename: import_pathe4.default.resolve(diagramFileName), content: prettiedDiagram } ]; } async function createHtml(option, renderData) { const outputDir = await getOutputDirPath(option, getCwd(process.env)); import_consola2.default.info(`export component: ${option.components.join(", ")}`); const documents = (await Promise.all( option.components.map(async (component) => { if (component === CE_OUTPUT_COMPONENT.TABLE) { return getTables(option, renderData, outputDir); } if (component === CE_OUTPUT_COMPONENT.ER) { return getDiagram(option, renderData, outputDir); } return []; }) )).flat(); return documents; } // src/creators/createImageHtml.ts var import_my_node_fp3 = require("my-node-fp"); var import_node_crypto = require("crypto"); var import_pathe5 = __toESM(require("pathe")); async function createImageHtml(option, renderData) { const renderer = container.resolve(SymbolTemplateRenderer); const rawHtml = await renderer.evaluate(CE_TEMPLATE_NAME.IMAGE_DOCUMENT, { ...renderData, option: { ...renderData.option, width: "200vw" } }); const prettiedHtml = await applyPrettier(rawHtml, "html", option.prettierConfig); const outputDirPath = option.output != null ? import_pathe5.default.resolve(option.output) : process.cwd(); await betterMkdir(outputDirPath); const tempFileName = import_pathe5.default.join(outputDirPath, `${(0, import_node_crypto.randomUUID)()}.html`); return { dirname: await (0, import_my_node_fp3.getDirname)(outputDirPath), content: prettiedHtml, filename: import_pathe5.default.resolve(tempFileName) }; } // src/creators/createMarkdown.ts var import_pathe6 = __toESM(require("pathe")); async function createMarkdown(option, renderData) { const renderer = container.resolve(SymbolTemplateRenderer); const rawMarkdown = await renderer.evaluate(CE_TEMPLATE_NAME.MARKDOWN_DOCUMENT, renderData); const prettiedMarkdown = await applyPrettier(rawMarkdown, "md", option.prettierConfig); const markdownFileName = `${renderData.metadata.name}.md`; const outputDir = await getOutputDirPath(option, getCwd(process.env)); return { filename: import_pathe6.default.resolve(import_pathe6.default.join(outputDir, markdownFileName)), dirname: import_pathe6.default.resolve(outputDir), content: prettiedMarkdown }; } // src/creators/createPdfHtml.ts var import_my_node_fp4 = require("my-node-fp"); var import_node_crypto2 = require("crypto"); var import_pathe7 = __toESM(require("pathe")); async function createPdfHtml(option, renderData) { const renderer = container.resolve(SymbolTemplateRenderer); const rawHtml = await renderer.evaluate(CE_TEMPLATE_NAME.PDF_DOCUMENT, renderData); const prettiedHtml = await applyPrettier(rawHtml, "html", option.prettierConfig); const outputDirPath = option.output != null ? import_pathe7.default.resolve(option.output) : process.cwd(); await betterMkdir(outputDirPath); const tempFileName = import_pathe7.default.join(outputDirPath, `${(0, import_node_crypto2.randomUUID)()}.html`); return { dirname: await (0, import_my_node_fp4.getDirname)(outputDirPath), content: prettiedHtml, filename: import_pathe7.default.resolve(tempFileName) }; } // src/configs/const-enum/CE_OUTPUT_FORMAT.ts var CE_OUTPUT_FORMAT = { HTML: "html", MARKDOWN: "md", PDF: "pdf", IMAGE: "image" }; // src/databases/const-enum/CE_RECORD_KIND.ts var CE_RECORD_KIND = { COLUMN: "column", ENTITY: "entity", RELATION: "relation", INDEX: "index" }; // src/modules/getSlashEndRoutePath.ts function getSlashEndRoutePath(basePath) { if (basePath.endsWith("/")) { return basePath; } return `${basePath}/`; } // src/creators/getRenderData.ts var import_alasql = __toESM(require("alasql")); var import_compare_versions = require("compare-versions"); async function getRenderData(records, metadata, option) { const versionRows = await import_alasql.default.promise("SELECT DISTINCT version FROM ?", [records]); const unSortedVersions = versionRows.map((version) => version.version); const versions = option.versionFrom === "timestamp" ? unSortedVersions.sort((l, r) => r.localeCompare(l)) : unSortedVersions.sort((l, r) => (0, import_compare_versions.compareVersions)(r, l)); const renderDatas = await Promise.all( versions.map(async (version) => { const entities = await import_alasql.default.promise(`SELECT * FROM ? WHERE [$kind] = ? AND version = ?`, [ records, "entity", version ]); const renderData = await Promise.all( entities.map(async (entity) => { const [columns, relations, indices] = await Promise.all([ await import_alasql.default.promise("SELECT * FROM ? WHERE [$kind] = ? AND entity = ? AND version = ?", [ records, CE_RECORD_KIND.COLUMN, entity.entity, version ]), await import_alasql.default.promise("SELECT * FROM ? WHERE [$kind] = ? AND entity = ? AND version = ?", [ records, CE_RECORD_KIND.RELATION, entity.entity, version ]), await import_alasql.default.promise("SELECT * FROM ? WHERE [$kind] = ? AND entity = ? AND version = ?", [ records, CE_RECORD_KIND.INDEX, entity.entity, version ]) ]); return { ...entity, columns, relations, indices }; }) ); return { version, entities: renderData, latest: version === metadata.version }; }) ); if (option.format === CE_OUTPUT_FORMAT.HTML) { return { versions: renderDatas, option: { ...option, routeBasePath: option.routeBasePath != null ? getSlashEndRoutePath(option.routeBasePath) : void 0 }, metadata }; } return { versions: renderDatas, option, metadata }; } // src/modules/getPuppeteerConfig.ts var import_fs2 = __toESM(require("fs")); var import_jsonc_parser2 = require("jsonc-parser"); var import_my_node_fp5 = require("my-node-fp"); async function getPuppeteerConfig(confgFilePath) { try { if (confgFilePath == null) { return {}; } if (await (0, import_my_node_fp5.exists)(confgFilePath)) { const buf = await import_fs2.default.promises.readFile(confgFilePath); const option = (0, import_jsonc_parser2.parse)(buf.toString()); return option; } return {}; } catch { return {}; } } // src/creators/writeToImage.ts var import_consola3 = __toESM(require("consola")); var import_del = __toESM(require("del")); var import_my_easy_fp4 = require("my-easy-fp"); var import_node_fs2 = __toESM(require("fs")); var import_pathe8 = __toESM(require("pathe")); var puppeteer = __toESM(require("puppeteer")); async function writeToImage(document, option, renderData) { let localBrowser; let localPage; try { const puppeteerConfig = await getPuppeteerConfig(option.prettierConfig); const browser = await puppeteer.launch({ ...puppeteerConfig, headless: true }); const page = await browser.newPage(); const puppeteerGotoOption = { waitUntil: "domcontentloaded", timeout: 6e4 }; localBrowser = browser; localPage = page; await betterMkdir(document.filename); await import_node_fs2.default.promises.writeFile(document.filename, document.content); await page.setViewport({ width: option.viewportWidth ?? 1280, height: option.viewportHeight ?? 720 * 2 }); await page.goto(`file://${document.filename}`, puppeteerGotoOption); import_consola3.default.debug(`file write start: ${document.filename}`); await page.$eval( "body", (body, backgroundColor) => { body.style.background = backgroundColor; }, option.backgroundColor ?? "white" ); if (option.imageFormat === "svg") { const svg = await page.$eval("#mermaid-diagram-container", (container2) => container2.innerHTML); if (svg == null) { await (0, import_del.default)(document.filename); throw new Error("invalid image html document template"); } await import_node_fs2.default.promises.writeFile(import_pathe8.default.join(document.dirname, `${renderData.metadata.name}.svg`), svg); import_consola3.default.debug("file write end"); await (0, import_del.default)(document.filename); import_consola3.default.info(`Component ER diagram successfully write on ${renderData.metadata.name}.svg`); return [import_pathe8.default.join(document.dirname, `${renderData.metadata.name}.svg`)]; } const clip = await page.$eval("svg", (htmlSvgElement) => { const react = htmlSvgElement.getBoundingClientRect(); return { x: react.left, y: react.top, width: react.width, height: react.height }; }); await page.screenshot({ path: import_pathe8.default.join(document.dirname, `${renderData.metadata.name}.png`), clip, omitBackground: false }); import_consola3.default.debug("file write end"); await (0, import_del.default)(document.filename); import_consola3.default.info(`Component ER diagram successfully write on ${renderData.metadata.name}.png`); return [import_pathe8.default.join(document.dirname, `${renderData.metadata.name}.png`)]; } catch (caught) { const err = (0, import_my_easy_fp4.isError)(caught, new Error("unknown error raised from writeToImage")); import_consola3.default.error(err.message); import_consola3.default.error(err.stack); return false; } finally { import_consola3.default.debug("Start page, brower close"); if (localPage !== void 0 && localPage !== null) { await localPage.close(); } if (localBrowser !== void 0 && localBrowser !== null) { await localBrowser.close(); } } } // src/creators/writeToPdf.ts var import_consola4 = __toESM(require("consola")); var import_del2 = __toESM(require("del")); var import_fs3 = __toESM(require("fs")); var import_my_easy_fp5 = require("my-easy-fp"); var import_pathe9 = __toESM(require("pathe")); var puppeteer2 = __toESM(require("puppeteer")); async function writeToPdf(document, option, renderData) { let localBrowser; let localPage; try { const puppeteerConfig = await getPuppeteerConfig(option.puppeteerConfig); const browser = await puppeteer2.launch({ ...puppeteerConfig, headless: true }); const page = await browser.newPage(); const puppeteerGotoOption = { waitUntil: "domcontentloaded", timeout: 6e4 }; localBrowser = browser; localPage = page; import_consola4.default.info("filename: ", document.filename); await page.setViewport({ width: option.viewportWidth ?? 1280, height: option.viewportHeight ?? 720 * 2 }); await import_fs3.default.promises.writeFile(document.filename, document.content); await page.goto(`file://${document.filename}`, puppeteerGotoOption); await page.pdf({ path: import_pathe9.default.join(document.dirname, `${renderData.metadata.name}.pdf`), printBackground: option.backgroundColor !== "transparent" }); await (0, import_del2.default)(document.filename); return [import_pathe9.default.join(document.dirname, `${renderData.metadata.name}.pdf`)]; } catch (caught) { const err = (0, import_my_easy_fp5.isError)(caught, new Error("unknown error raised from writeToPdf")); import_consola4.default.error(err.message); import_consola4.default.error(err.stack); return []; } finally { if (localPage !== void 0 && localPage !== null) { import_consola4.default.debug("Session Closed"); await localPage.close(); } if (localBrowser !== void 0 && localBrowser !== null) { await localBrowser.close(); } } } // src/databases/const-enum/CE_CHANGE_KIND.ts var CE_CHANGE_KIND = { CHANGE: "change", ADD: "add", DELETE: "delete", NONE: "none" }; // src/databases/compareDatabase.ts var import_deep_object_diff = require("deep-object-diff"); var import_my_easy_fp6 = require("my-easy-fp"); function compareDatabase(metadata, next, prev) { if (prev.length <= 0) { return next.map((record) => ({ ...record, change: CE_CHANGE_KIND.NONE })); } const nextMap = next.reduce((aggregation, record) => { switch (record.$kind) { case CE_RECORD_KIND.ENTITY: return { ...aggregation, [getEntityHash(record)]: record }; case CE_RECORD_KIND.COLUMN: return { ...aggregation, [getColumnHash(record)]: record }; case CE_RECORD_KIND.RELATION: return { ...aggregation, [getRelationHash(record)]: record }; case CE_RECORD_KIND.INDEX: return { ...aggregation, [getIndexHash(record)]: record }; default: return aggregation; } }, {}); const prevMap = prev.reduce((aggregation, record) => { switch (record.$kind) { case CE_RECORD_KIND.ENTITY: return { ...aggregation, [getEntityHash(record)]: record }; case CE_RECORD_KIND.COLUMN: return { ...aggregation, [getColumnHash(record)]: record }; case CE_RECORD_KIND.RELATION: return { ...aggregation, [getRelationHash(record)]: record }; case CE_RECORD_KIND.INDEX: return { ...aggregation, [getIndexHash(record)]: record }; default: return aggregation; } }, {}); const compared = (0, import_my_easy_fp6.settify)([...Object.keys(nextMap), ...Object.keys(prevMap)]).map((key) => { const fromNext = nextMap[key]; const fromPrev = prevMap[key]; if (fromNext != null && fromPrev == null) { return { ...fromNext, change: CE_CHANGE_KIND.ADD }; } if (fromNext == null && fromPrev != null) { return { ...fromPrev, change: CE_CHANGE_KIND.DELETE, version: metadata.version }; } const forCompareNext = { ...fromNext, title: fromNext.title ?? "", change: CE_CHANGE_KIND.NONE, createdAt: "", updatedAt: "", version: "" }; const forComparePrev = { ...fromPrev, title: fromPrev.title ?? "", change: CE_CHANGE_KIND.NONE, createdAt: "", updatedAt: "", version: "" }; const diffed = (0, import_deep_object_diff.detailedDiff)(forCompareNext, forComparePrev); if (Object.keys(diffed.added).length <= 0 && Object.keys(diffed.updated).length <= 0 && Object.keys(diffed.deleted).length <= 0) { return { ...fromNext, change: CE_CHANGE_KIND.NONE }; } return { ...fromNext, change: CE_CHANGE_KIND.CHANGE, prev: fromPrev }; }); return compared; } // src/databases/flushDatabase.ts var import_node_fs3 = __toESM(require("fs")); var import_pathe10 = __toESM(require("pathe")); async function flushDatabase(option, records) { const dirname = await getOutputDirPath({ output: option.databasePath }, process.cwd()); const filename = import_pathe10.default.join(dirname, CE_DEFAULT_VALUE.DATABASE_FILENAME); if (filename == null) { throw new Error(`invalid database name: undefined`); } await import_node_fs3.default.promises.writeFile( import_pathe10.default.join(dirname, CE_DEFAULT_VALUE.DATABASE_FILENAME), JSON.stringify(records, void 0, 2) ); return records; } // src/databases/openDatabase.ts var import_jsonc_parser3 = require("jsonc-parser"); var import_my_easy_fp7 = require("my-easy-fp"); var import_my_node_fp6 = require("my-node-fp"); var import_node_fs4 = __toESM(require("fs")); var import_pathe11 = __toESM(require("pathe")); async function openDatabase(option) { const dirname = await getOutputDirPath({ output: option.databasePath }, process.cwd()); const filename = import_pathe11.default.join(dirname, CE_DEFAULT_VALUE.DATABASE_FILENAME); if (filename == null) { return []; } if ((0, import_my_easy_fp7.isFalse)(await (0, import_my_node_fp6.exists)(filename))) { return []; } const db = (0, import_jsonc_parser3.parse)((await import_node_fs4.default.promises.readFile(filename)).toString()); return db; } // src/databases/processDatabase.ts var import_alasql2 = __toESM(require("alasql")); var import_compare_versions2 = require("compare-versions"); var import_my_easy_fp8 = require("my-easy-fp"); async function processDatabase(metadata, db, option) { if (db.length <= 0) { return { next: [], deleted: [], prev: [] }; } const currentVersion = metadata.version; const versions = await import_alasql2.default.promise("SELECT DISTINCT version FROM ?", [db]); const sortedVersions = option.versionFrom === "timestamp" ? versions.sort((l, r) => r.version.localeCompare(l.version)) : versions.sort((l, r) => (0, import_compare_versions2.compareVersions)(r.version, l.version)); const firstVersionFromDb = (0, import_my_easy_fp8.atOrThrow)(sortedVersions, 0).version; if (currentVersion !== firstVersionFromDb) { const latestRecords2 = await import_alasql2.default.promise("SELECT * FROM ? WHERE version = ?", [ db, firstVersionFromDb ]); return { next: db, deleted: [], prev: latestRecords2 }; } if (sortedVersions.length <= 1) { return { next: [], deleted: [], prev: [] }; } const secondVersionFromDb = (0, import_my_easy_fp8.atOrThrow)(sortedVersions, 1).version; const partialRecords = await import_alasql2.default.promise("SELECT * FROM ? WHERE version != ?", [ db, currentVersion ]); const oldRecords = await import_alasql2.default.promise("SELECT * FROM ? WHERE version = ?", [ db, currentVersion ]); const latestRecords = await import_alasql2.default.promise("SELECT * FROM ? WHERE version = ?", [ db, secondVersionFromDb ]); return { next: partialRecords, deleted: oldRecords, prev: latestRecords }; } // src/templates/TemplateRenderer.ts var import_consola5 = __toESM(require("consola")); var import_eta = require("eta"); var import_my_easy_fp9 = require("my-easy-fp"); var _eta, _templates, _defaultTemplates; var TemplateRenderer = class { constructor(templates, defaultTemplates) { __privateAdd(this, _eta, void 0); __privateAdd(this, _templates, void 0); __privateAdd(this, _defaultTemplates, void 0); __privateSet(this, _templates, templates); __privateSet(this, _defaultTemplates, defaultTemplates); __privateSet(this, _eta, new import_eta.Eta({ views: "erdia", autoEscape: false })); __privateGet(this, _eta).resolvePath = (templatePath) => templatePath; __privateGet(this, _eta).readFile = (templatePath) => { const template = __privateGet(this, _templates).get(templatePath) ?? __privateGet(this, _defaultTemplates).get(templatePath); return (0, import_my_easy_fp9.orThrow)(template, new Error(`cannot found template: ${templatePath}`)); }; } async evaluate(name, data) { try { const rendered = __privateGet(this, _eta).render(name, data); return rendered; } catch (caught) { const err = (0, import_my_easy_fp9.isError)(caught, new Error(`raise error from evaluateTemplate: ${name}`)); import_consola5.default.error(`template: ${name}`, data); import_consola5.default.error(err); throw err; } } }; _eta = new WeakMap(); _templates = new WeakMap(); _defaultTemplates = new WeakMap(); // src/typeorm/loadDataSource.ts var import_my_easy_fp10 = require("my-easy-fp"); var import_typeorm = require("typeorm"); var import_ImportUtils = require("typeorm/util/ImportUtils"); async function loadDataSource(dataSourceFilePath) { let dataSourceFileExports; try { [dataSourceFileExports] = await (0, import_ImportUtils.importOrRequireFile)(dataSourceFilePath); } catch (caught) { const err = (0, import_my_easy_fp10.isError)(caught, new Error(`Unable to open file: "${dataSourceFilePath}".`)); throw new Error(`Unable to open file: "${dataSourceFilePath}". ${err.message}`); } if (!dataSourceFileExports || typeof dataSourceFileExports !== "object") { throw new Error(`Given data source file must contain export of a DataSource instance`); } if (import_typeorm.InstanceChecker.isDataSource(dataSourceFileExports)) { return dataSourceFileExports; } const dataSourceExports = []; for (const fileExportKey in dataSourceFileExports) { const fileExport = dataSourceFileExports[fileExportKey]; const awaitedFileExport = await fileExport; if (import_typeorm.InstanceChecker.isDataSource(awaitedFileExport)) { dataSourceExports.push(awaitedFileExport); } } if (dataSourceExports.length === 0) { throw new Error(`Given data source file must contain export of a DataSource instance`); } if (dataSourceExports.length > 1) { throw new Error(`Given data source file must contain only one export of DataSource instance`); } return dataSourceExports[0]; } // src/typeorm/getDataSource.ts var import_my_easy_fp11 = require("my-easy-fp"); var import_my_node_fp7 = require("my-node-fp"); var import_pathe12 = __toESM(require("pathe")); async function getDataSource(options) { const dataSourcePath = import_pathe12.default.resolve(options.dataSourcePath); if ((0, import_my_easy_fp11.isFalse)(await (0, import_my_node_fp7.exists)(dataSourcePath))) { throw new Error(`Cannot found dataSource: ${dataSourcePath}`); } const dataSource = await loadDataSource(dataSourcePath); if (dataSource == null) { throw new Error(`Cannot found dataSource in ${options.dataSourcePath}`); } return dataSource; } // src/cli/builders/buildOptionBuilder.ts function buildOptionBuilder(args) { args.option("route-base-path", { describe: "define the route base path. The route base path is used as the base path for navbar anchor when generating HTML documents", type: "string", default: void 0 }).option("title", { describe: "define what will be written in the HTML document title tag", type: "string", default: void 0 }).option("prettier-config", { describe: "define the path to the prettier configuration file", type: "string", default: void 0 }).option("puppeteer-config", { describe: "define the path to the puppeteer configuration file", type: "string" }).option("width", { describe: "define the ER diagram width. The width is defined by the HTML document css attribute width", type: "string", default: "100%" }).option("viewport-width", { describe: "define the viewport width to puppeteer. The width is defined by the HTML document css attribute width", type: "number", default: 1280 }).option("viewport-height", { describe: "define the viewport height to puppeteer. The width is defined by the HTML document css attribute height", type: "number", default: 720 * 2 }).option("image-format", { describe: "define the format to image file", type: "string", choices: ["svg", "png"], default: "svg" }).option("background-color", { describe: "define the background color to html documents. eg. transparent, red, '#F0F0F0'", type: "string", default: "white" }); return args; } // src/cli/builders/outputOptionBuilder.ts function outputOptionBuilder(args) { args.option("output", { alias: "o", describe: "define the directory to output file", type: "string" }); return args; } // src/cli/builders/commonOptionBuilder.ts function commonOptionBuilder(args) { outputOptionBuilder(args).option("config", { alias: "c", describe: "define the path to to configuration file: .erdiarc", type: "string" }).option("data-source-path", { alias: "d", describe: "define the path to TypeORM data source file", type: "string" }).option("show-logo", { describe: "define the logo display on cli interface", type: "boolean", default: false }).demandOption("data-source-path"); return args; } // src/configs/const-enum/CE_ENTITY_VERSION_FROM.ts var CE_ENTITY_VERSION_FROM = { TIMESTAMP: "timestamp", PACKAGE_JSON: "package.json", FILE: "file" }; // src/configs/const-enum/CE_MERMAID_THEME.ts var CE_MERMAID_THEME = { DEFAULT: "default", FOREST: "forest", DARK: "dark", NEUTRAL: "neutral", NULL: "null" }; // src/cli/builders/documentOptionBuilder.ts function documentOptionBuilder(args) { args.option("components", { alias: "t", describe: "define the output component to builded documents", choices: [CE_OUTPUT_COMPONENT.TABLE, CE_OUTPUT_COMPONENT.ER], type: "array", default: [CE_OUTPUT_COMPONENT.TABLE, CE_OUTPUT_COMPONENT.ER] }).option("project-name", { describe: "define whether project name will come from the `package.json` name field or database name", type: "string", choices: [CE_PROJECT_NAME_FROM.APPLICATION, CE_PROJECT_NAME_FROM.DATABASE], default: CE_PROJECT_NAME_FROM.APPLICATION }).option("database-path", { describe: "define the directory to store `erdiadb.json`", type: "string", default: void 0 }).option("template-path", { describe: "define the directory to ETA templates", type: "string" }).option("skip-image-in-html", { describe: "enabling the this option will skip attaching the ER diagram image file to the html document", type: "boolean", default: false }).option("format", { describe: "define the output format to builded documents", choices: [CE_OUTPUT_FORMAT.HTML, CE_OUTPUT_FORMAT.MARKDOWN, CE_OUTPUT_FORMAT.PDF, CE_OUTPUT_FORMAT.IMAGE], type: "string", default: CE_OUTPUT_FORMAT.HTML }).option("version-from", { describe: "define whether document version will come from the `package.json` version field or specific file, timestamp", choices: [CE_ENTITY_VERSION_FROM.PACKAGE_JSON, CE_ENTITY_VERSION_FROM.FILE, CE_ENTITY_VERSION_FROM.TIMESTAMP], type: "string", default: CE_ENTITY_VERSION_FROM.PACKAGE_JSON }).option("version-path", { describe: "If the versionFrom option set `file`, read the file from this path", type: "string", default: void 0 }).option("theme", { describe: "define the mermaid.js plugin theme. see https://mermaid-js.github.io/mermaid/#/Setup?id=theme", choices: [ CE_MERMAID_THEME.DEFAULT, CE_MERMAID_THEME.DARK, CE_MERMAID_THEME.FOREST, CE_MERMAID_THEME.DARK, CE_MERMAID_THEME.NEUTRAL, CE_MERMAID_THEME.NULL ], default: CE_MERMAID_THEME.DARK, type: "string" }); return args; } // src/modules/containers/keys/SymbolDefaultTemplate.ts var SymbolDefaultTemplate = Symbol("default-template"); // src/modules/containers/keys/SymbolLogger.ts var SymbolLogger = Symbol("symbol-logger"); // src/modules/containers/keys/SymbolTemplate.ts var SymbolTemplate = Symbol("template"); // src/modules/loggers/Logger.ts var import_consola6 = __toESM(require("consola")); var _enable; var Logger = class { constructor(enable) { __privateAdd(this, _enable, void 0); __publicField(this, "info", this.logging.bind(this, "info")); __publicField(this, "warn", this.logging.bind(this, "warn")); __publicField(this, "silent", this.logging.bind(this, "silent")); __publicField(this, "error", this.logging.bind(this, "error")); __publicField(this, "success", this.logging.bind(this, "success")); __publicField(this, "fail", this.logging.bind(this, "fail")); __publicField(this, "fatal", this.logging.bind(this, "fatal")); __publicField(this, "debug", this.logging.bind(this, "debug")); __publicField(this, "trace", this.logging.bind(this, "trace")); __publicField(this, "verbose", this.logging.bind(this, "verbose")); __publicField(this, "ready", this.logging.bind(this, "ready")); __publicField(this, "box", this.logging.bind(this, "box")); __publicField(this, "log", this.logging.bind(this, "log")); __privateSet(this, _enable, enable ?? false); } get enable() { return __privateGet(this, _enable); } set enable(value) { __privateSet(this, _enable, value); } get level() { return import_consola6.default.level; } set level(level) { import_consola6.default.level = level; } logging(level, message, ...args) { if (__privateGet(this, _enable)) { import_consola6.default[level](message, ...args); } } }; _enable = new WeakMap(); // src/modules/loggers/createLogger.ts var import_awilix2 = require("awilix"); function createLogger(enable) { if (!container.hasRegistration(SymbolLogger)) { const logger = new Logger(enable ?? false); container.register(SymbolLogger, (0, import_awilix2.asValue)(logger)); } } // src/templates/modules/configTemplate.ts var configTemplate = ` { // directory for output files "output": "<%= it.config.output %>", // typeorm dataSourcePath "data-source-path": "<%= it.config.dataSourceFile %>", // type of generated document "components": <%~ JSON.stringify(it.config.components) %>, // kind of document name // - db: database name from TypeORM // - app: application name from package.json "project-name": "<%= it.config.projectName %>", // custom template file path. erdia are using [ETA](https://eta.js.org/) template engine <% if (it.config.templatePath != null) { %> "template-path": "<%= it.config.templatePath %>", <% } else { %> // "template-path": "", <% } %> // erdia entity database file path <% if (it.config.databasePath != null) { %> "database-path": "<%= it.config.databasePath %>", <% } else { %> // "database-path": "", <% } %> // erdia entity database file path <% if (it.config.routeBasePath != null) { %> "route-base-path": "<%= it.config.routeBasePath %>", <% } else { %> // "route-base-path": "", <% } %> // document version using package.json version or timestamp "version-from": "<%= it.config.versionFrom %>", // If the versionFrom option set file, read the file from this path <% if (it.config.versionPath != null) { %> "version-path": "<%= it.config.versionPath %>", <% } else { %> // "version-path": "", <% } %> // output format of generated documents // - html // - md // - pdf // - image "format": "<%= it.config.format %>", // skip image file attachment in html document "skipImageInHtml": false, // mermaid.js plugin theme configuration // @url https://mermaid-js.github.io/mermaid/#/Setup?id=theme "theme": "<%= it.config.theme %>", // prettier config path // "prettier-config": "set your .prettierrc file path", // title tag content that inside of html document // "title": "set title tag content in html document", // ER diagram width, it will be set width css attribute // @format pdf, image <% if (it.config.format === 'pdf' || it.config.format === 'image') { -%> "width": "100%", <% } else { -%> // "width": "100%", <% } -%> // puppeteer viewport width // @format pdf, image <% if (it.config.format === 'pdf' || it.config.format === 'image') { -%> "viewport-width": 1280, <% } else { -%> // "viewport-width": 1280, <% } -%> // puppeteer viewport height // @format pdf, image <% if (it.config.format === 'pdf' || it.config.format === 'image') { -%> "viewport-height": 1440, <% } else { -%> // "viewport-height": 1440, <% } -%> // puppeteer config file path // @format pdf, image // "puppeteer-config-path": "set your puppeteer configuration file path", // Background color. Example: transparent, red, '#F0F0F0'. Optional. Default: white // @format pdf, image // "background-color": "#FFFFFF", // ER diagram export image file format // @format image <% if (it.config.format === 'image') { %> "image-format": "<%= it.config.imageFormat %>", <% } else { %> // "image-format": "svg", <% } %> } `; // src/templates/modules/getTemplateModulePath.ts var import_my_node_fp8 = require("my-node-fp"); var import_pathe13 = __toESM(require("pathe")); async function getTemplateModulePath(templatePathParam) { const currentFilePath = import_pathe13.default.resolve(__dirname); if (templatePathParam != null) { const currentWithTemplatePath = import_pathe13.default.resolve(import_pathe13.default.join(currentFilePath, templatePathParam)); if (await (0, import_my_node_fp8.exists)(currentWithTemplatePath)) { return currentWithTemplatePath; } } const packageRootTemplatePath = import_pathe13.default.resolve( import_pathe13.default.join(currentFilePath, "..", "..", "..", CE_DEFAULT_VALUE.TEMPLATES_PATH) ); if (await (0, import_my_node_fp8.exists)(packageRootTemplatePath)) { return packageRootTemplatePath; } const distTemplatePath = import_pathe13.default.resolve(import_pathe13.default.join(currentFilePath, "..", "..", CE_DEFAULT_VALUE.TEMPLATES_PATH)); if (await (0, import_my_node_fp8.exists)(distTemplatePath)) { return distTemplatePath; } throw new Error("cannot found template directory!"); } // src/templates/modules/getTemplatePath.ts var import_my_node_fp9 = require("my-node-fp"); var import_pathe14 = __toESM(require("pathe")); async function getTemplatePath(templatePathParam) { if (templatePathParam != null && await (0, import_my_node_fp9.exists)(import_pathe14.default.resolve(templatePathParam))) { return import_pathe14.default.resolve(templatePathParam); } return getTemplateModulePath(templatePathParam); } // src/modules/files/getGlobFiles.ts var import_pathe15 = __toESM(require("pathe")); function getGlobFiles(glob) { const filePathSet = /* @__PURE__ */ new Set(); for (const filePath of glob) { filePathSet.add(typeof filePath === "string" ? filePath : import_pathe15.default.join(filePath.path, filePath.name)); } return Array.from(filePathSet); } // src/modules/scopes/defaultExclude.ts var defaultExclude = ["node_modules/**", "flow-typed/**", "coverage/**", ".git/**"]; // src/templates/modules/getTemplate.ts var import_my_easy_fp12 = require("my-easy-fp"); var import_my_node_fp10 = require("my-node-fp"); var import_node_fs5 = __toESM(require("fs")); var import_pathe16 = __toESM(require("pathe")); async function getTemplate(dirPath, filePath) { if ((0, import_my_easy_fp12.isTrue)(await (0, import_my_node_fp10.exists)(filePath))) { const buf = await import_node_fs5.default.promises.readFile(filePath); const relative = import_pathe16.default.relative(dirPath, filePath).replace(`.${import_pathe16.default.sep}`, ""); const dirname = await (0, import_my_node_fp10.getDirname)(relative); const basename = (0, import_my_node_fp10.basenames)(relative, [".eta", ".ejs"]); return { key: import_pathe16.default.join(dirname, basename), content: buf.toString() }; } return void 0; } // src/templates/modules/getTemplates.ts var import_glob = require("glob"); var import_pathe17 = __toESM(require("pathe")); async function getTemplates(templatePath, globOptions) { const resolvedTemplatePath = import_pathe17.default.resolve(templatePath); const globs = new import_glob.Glob(import_pathe17.default.join(resolvedTemplatePath, `**`, "*.eta"), { ...globOptions, absolute: true, ignore: defaultExclude, cwd: resolvedTemplatePath, windowsPathsNoEscape: true }); const templateFilePaths = getGlobFiles(globs).map((filePath) => [filePath, true]).map(([filePath, _flag]) => filePath); const loadedTemplateFiles = (await Promise.all(templateFilePaths.map((templateFilePath) => getTemplate(resolvedTemplatePath, templateFilePath)))).filter((template) => template != null); return loadedTemplateFiles; } // src/templates/modules/loadTemplates.ts var import_pathe18 = __toESM(require("pathe")); async function loadTemplates(option) { const defaultTemplatePath = await getTemplatePath(CE_DEFAULT_VALUE.TEMPLATES_PATH); const [defaultHtml, defaultMarkdown, defaultImage, defaultPdf] = await Promise.all([ getTemplates(import_pathe18.default.join(defaultTemplatePath, "html"), {}), getTemplates(import_pathe18.default.join(defaultTemplatePath, "markdown"), {}), getTemplates(import_pathe18.default.join(defaultTemplatePath, "image"), {}), getTemplates(import_pathe18.default.join(defaultTemplatePath, "pdf"), {}) ]); const defaultTemplateMap = new Map([ ["config-json", configTemplate.trim()], ...defaultHtml.map((template) => [`html-${template.key}`, template.content]), ...defaultMarkdown.map((template) => [`markdown-${template.key}`, template.content]), ...defaultImage.map((template) => [`image-${template.key}`, template.content]), ...defaultPdf.map((template) => [`pdf-${template.key}`, template.content]) ]); if (option?.templatePath == null) { return { default: defaultTemplateMap, template: defaultTemplateMap }; } const templatePath = await getTemplatePath(option.templatePath); const [templateHtml, templateMarkdown, templateImage, templatePdf] = await Promise.all([ getTemplates(import_pathe18.default.join(templatePath, "html"), {}), getTemplates(import_pathe18.default.join(templatePath, "markdown"), {}), getTemplates(import_pathe18.default.join(templatePath, "image"), {}), getTemplates(import_pathe18.default.join(templatePath, "pdf"), {}) ]); const templateMap = new Map([ ["config-json", configTemplate.trim()], ...templateHtml.map((template) => [`html-${template.key}`, template.content]), ...templateMarkdown.map((template) => [`markdown-${template.key}`, template.content]), ...templateImage.map((template) => [`image-${template.key}`, template.content]), ...templatePdf.map((template) => [`pdf-${template.key}`, template.content]) ]); return { default: defaultTemplateMap, template: templateMap }; } // src/configs/const-enum/CE_COLUMN_ATTRIBUTE.ts var CE_COLUMN_ATTRIBUTE = { PK: "PK", FK: "FK", UK: "UK" }; // src/creators/columns/getColumnWeight.ts var import_mathjs = require("mathjs"); var import_my_easy_fp13 = require("my-easy-fp"); function getColumnWeight(column) { const weight = (0, import_mathjs.bignumber)(0); const type = (0, import_mathjs.bignumber)( (0, import_my_easy_fp13.populate)(column.columnType.length).reduce((sum, index) => sum + column.columnType.charCodeAt(index), 0) ).mul(1e3); return weight.add(column.attributeKey.indexOf(CE_COLUMN_ATTRIBUTE.PK) >= 0 ? 2e7 : 0).add(column.attributeKey.indexOf(CE_COLUMN_ATTRIBUTE.FK) >= 0 ? 1e7 : 0).add(type).add((0, import_mathjs.bignumber)(122).sub((0, import_mathjs.bignumber)(column.name.toLowerCase().charCodeAt(0)))).add( (0, import_mathjs.bignumber)(122).sub((0, import_mathjs.bignumber)(column.name.toLowerCase().charCodeAt(1))).div(100) ); } // src/typeorm/columns/getColumnAttributeKey.ts var import_alasql3 = __toESM(require("alasql")); var import_my_easy_fp14 = require("my-easy-fp"); function getColumnAttributeKey(columnMetadata, dbName, tableDBName, indexRecords) { const indices = (0, import_alasql3.default)("SELECT * FROM ? WHERE ? = ANY (columnNames) and tableDBName = ?", [ indexRecords, dbName, tableDBName ]); const index = (0, import_my_easy_fp14.atOrUndefined)(indices, 0); return [ columnMetadata.relationMetadata != null ? CE_COLUMN_ATTRIBUTE.FK : void 0, columnMetadata.isPrimary ? CE_COLUMN_ATTRIBUTE.PK : void 0, index?.isUnique ? CE_COLUMN_ATTRIBUTE.UK : void 0 ].filter((attribute) => attribute != null); } // src/typeorm/columns/getIsNullable.ts function getIsNullable(metadata) { if (metadata.isPrimary) { return ""; } if (metadata.isNullable === false) { return ""; } return "nullable"; } // src/typeorm/columns/getColumnType.ts var import_my_easy_fp15 = require("my-easy-fp"); function getColumnType(columnMetadata, includeLength) { const nullable = getIsNullable(columnMetadata); if (typeof columnMetadata.type === "function") { if ((0, import_my_easy_fp15.isTrue)(includeLength ?? false) && columnMetadata.length !== "") { const name3 = columnMetadata.type.name.toString().toLowerCase().replace(/\s/g, "-"); const withNullable3 = nullable === "nullable" ? name3 : `*${name3}`; return `${withNullable3}(${columnMetadata.length})`; } const name2 = columnMetadata.type.name.toString().toLowerCase().replace(/\s/g, "-"); const withNullable2 = nullable === "nullable" ? name2 : `*${name2}`; return withNullable2; } if ((0, import_my_easy_fp15.isTrue)(includeLength ?? false) && columnMetadata.length !== "") { const name2 = columnMetadata.type.toString().replace(/\s/g, "-"); const withNullable2 = nullable === "nullable" ? name2 : `*${name2}`; return `${withNullable2}(${columnMetadata.length})`; } const name = columnMetadata.type.toString().replace(/\s/g, "-"); const withNullable = nullable === "nullable" ? name : `*${name}`; return withNullable; } // src/typeorm/columns/getComment.ts function getComment(option, comment) { if (comment == null) { return ""; } if (option.format === CE_OUTPUT_FORMAT.MARKDOWN) { return comment.replace(/\r\n/g, "\\\\r\\\\n").replace(/\n\r/g, "\\\\n\\\\r").replace(/\n/g, "\\\\n"); } if (option.format === CE_OUTPUT_FORMAT.HTML) { return comment.replace(/\r\n/g, "
").replace(/\n\r/g, "
").replace(/\n/g, "
"); } return comment.replace(/\r\n/g, "
").replace(/\n\r/g, "
").replace(/\n/g, "
"); } // src/typeorm/entities/getEntityName.ts function getEntityName(entityMeta) { if ("$kind" in entityMeta) { if (entityMeta.dbName == null || entityMeta.dbName === "") { return entityMeta.name; } return entityMeta.dbName; } const { tableName, name } = entityMeta; if (tableName == null || tableName === "") { return name; } return tableName; } // src/typeorm/columns/getColumnRecord.ts function getColumnRecord(columnMetadata, option, metadata, indices) { const entityName = getEntityName(columnMetadata.entityMetadata); const { propertyName } = columnMetadata; const columnName = columnMetadata.databaseName; const attributeKey = getColumnAttributeKey(columnMetadata, columnName, entityName, indices); const columnType = getColumnType(columnMetadata); const columnTypeWithLength = getColumnType(columnMetadata, true); const comment = getComment(option, columnMetadata.comment); const isNullable = getIsNullable(columnMetadata); const charset = columnMetadata.charset ?? ""; const columnData = { $kind: "column", ...metadata, change: CE_CHANGE_KIND.ADD, entity: entityName, name: propertyName, dbName: columnName, attributeKey, isNullable, columnType, charset, columnTypeWithLength, comment }; const weight = getColumnWeight(columnData); return { ...columnData, weight: weight.toNumber() }; } // src/typeorm/entities/getEntityRecord.ts function getEntityRecord(entityMetadata, metadata) { const record = { $kind: "entity", ...metadata, change: CE_CHANGE_KIND.ADD, entity: getEntityName(entityMetadata), name: entityMetadata.name, dbName: entityMetadata.tableName, hasRelation: entityMetadata.relations.length > 0 }; return record; } // src/typeorm/entities/getEntityRecords.ts function getEntityRecords(dataSource, metadata) { const entityRecords = dataSource.entityMetadatas.map((entityMetadata) => getEntityRecord(entityMetadata, metadata)); const entityMap = entityRecords.reduce((map, record) => { return { ...map, [record.name]: record }; }, {}); const deduped = Object.values(entityMap); return deduped; } // src/typeorm/indices/getIndexRecord.ts function getIndexRecord(entityMetadata, metadata) { const indices = entityMetadata.indices.map((entityIndex) => { const record = { $kind: CE_RECORD_KIND.INDEX, ...metadata, change: CE_CHANGE_KIND.NONE, entity: getEntityName(entityMetadata), name: entityIndex.givenName ?? entityIndex.name, dbName: entityIndex.name, tableName: entityMetadata.name, tableDBName: entityMetadata.tableName, isUnique: entityIndex.isUnique, isFulltext: entityIndex.isFulltext, isSpatial: entityIndex.isSpatial ?? false, columnNames: entityIndex.columns.map((column) => column.databaseName) }; return record; }); const uniques = entityMetadata.uniques.map((entityUnique) => { const record = { $kind: CE_RECORD_KIND.INDEX, ...metadata, change: CE_CHANGE_KIND.NONE, entity: getEntityName(entityMetadata), name: entityUnique.givenName ?? entityUnique.name, dbName: entityUnique.name, tableName: entityMetadata.name, tableDBName: entityMetadata.tableName, isUnique: true, isFulltext: false, isSpatial: false, columnNames: entityUnique.columns.map((column) => column.databaseName) }; return record; }); return [...indices, ...uniques]; } // src/typeorm/indices/getIndexRecords.ts function getIndexRecords(dataSource, metadata) { const indexRecords = dataSource.entityMetadatas.map((entityMetadata) => getIndexRecord(entityMetadata, metadata)).flat(); const dedupedMap = indexRecords.reduce((aggregation, indexRecord) => { return { ...aggregation, [getIndexHash(indexRecord)]: indexRecord }; }, {}); const deduped = Object.values(dedupedMap); return deduped; } // src/typeorm/relations/dedupeManaToManyRelationRecord.ts var import_my_easy_fp16 = require("my-easy-fp"); function dedupeManaToManyRelationRecord(relations) { const otherRelations = relations.filter((relation) => relation.relationType !== "many-to-many"); const manyToManyRelations = relations.filter((relation) => relation.relationType === "many-to-many"); const relationMap = manyToManyRelations.reduce((aggregation, relation) => { if (aggregation[relation.relationHash] == null) { return { ...aggregation, [relation.relationHash]: [relation] }; } return { ...aggregation, [relation.relationHash]: [...aggregation[relation.relationHash], relation] }; }, {}); const nextRelations = Object.values(relationMap).map((chunkedRelations) => { const sortedRelations = chunkedRelations.sort((l, r) => l.dbName.localeCompare(r.dbName)); const firstRelation = (0, import_my_easy_fp16.atOrThrow)( sortedRelations, 0, new Error(`Cannot found relation: ${sortedRelations.at(0)?.entity} - ${sortedRelations.at(1)?.entity}`) ); const secondRelation = (0, import_my_easy_fp16.atOrThrow)( sortedRelations, 1, new Error(`Cannot found relation: ${sortedRelations.at(0)?.entity} - ${sortedRelations.at(1)?.entity}`) ); const firstNext = { ...firstRelation, inverseJoinColumnName: secondRelation.joinColumnName }; const secondNext = { ...secondRelation, inverseJoinColumnName: firstRelation.joinColumnName, isDuplicate: true }; return [firstNext, secondNext]; }); return [...otherRelations, ...nextRelations.flat()]; } // src/typeorm/entities/getEntityPropertyName.ts function getEntityPropertyName(entityMeta) { if ("$kind" in entityMeta) { if (entityMeta.name == null || entityMeta.name === "") { return entityMeta.dbName; } return entityMeta.name; } const { tableName, name } = entityMeta; if (name == null || name === "") { return tableName; } return name; } // src/typeorm/relations/getInverseRelationMetadata.ts var import_my_easy_fp17 = require("my-easy-fp"); function getInverseRelationMetadata(relationMetadata) { const entityName = getEntityName(relationMetadata.entityMetadata); const raceInverseRelationMetadata = () => { const fromInverseMetadata = relationMetadata.inverseEntityMetadata.relations.find( (relation) => getEntityName(relation.inverseEntityMetadata) === entityName ); const fromInverseJoinColumns = (0, import_my_easy_fp17.atOrUndefined)(relationMetadata.inverseJoinColumns, 0); if (fromInverseMetadata != null) { return fromInverseMetadata; } if (fromInverseJoinColumns?.relationMetadata != null) { return fromInverseJoinColumns.relationMetadata; } return void 0; }; const inverseRelationMetadata = raceInverseRelationMetadata(); if (inverseRelationMetadata == null) { throw new Error( `Cannot found relation from inverse entity metadata: ${relationMetadata.inverseEntityMetadata.name}` ); } return inverseRelationMetadata; } // src/typeorm/relations/getManyToManyJoinColumn.ts var import_consola7 = __toESM(require("consola")); function getManyToManyJoinColumn(relationMetadata) { const joinTable = relationMetadata.joinTableName; const joinColumn = relationMetadata.joinColumns.find((column) => getEntityName(column.entityMetadata) === joinTable); const inverseRelationMetadata = getInverseRelationMetadata(relationMetadata); if (joinColumn != null) { import_consola7.default.debug(`M:N entity: ${joinColumn.propertyName}-${relationMetadata.joinTableName}`); return { inverseJoinColumnOne: false, inverseJoinColumnNullable: inverseRelationMetadata.isNullable, joinPropertyName: joinColumn.propertyName, joinColumnName: joinColumn.databaseName, isDuplicate: false }; } const entityName = getEntityName(relationMetadata.entityMetadata); const manyToManyRelation = relationMetadata.inverseEntityMetadata.manyToManyRelations.find( (manyToOneRelationMetadata) => { const inverseEntityName = getEntityName(manyToOneRelationMetadata.inverseEntityMetadata); return inverseEntityName === entityName; } ); if (manyToManyRelation == null) { throw new Error(`Cannot found relation on many-to-many side: ${relationMetadata.entityMetadata.name}`); } const inverseJoinTable = manyToManyRelation.joinTableName; const inverseJoinColumn = manyToManyRelation.joinColumns.find( (column) => getEntityName(column.entityMetadata) === inverseJoinTable ); if (inverseJoinColumn == null) { throw new Error(`Cannot found join-column on many-to-many side: ${manyToManyRelation.entityMetadata.name}`); } return { inverseJoinColumnOne: false, inverseJoinColumnNullable: inverseRelationMetadata.isNullable, joinPropertyName: inverseJoinColumn.propertyName, joinColumnName: inverseJoinColumn.databaseName, isDuplicate: false }; } // src/typeorm/relations/getManyToOneJoinColumn.ts function getManyToOneJoinColumn(relationMetadata) { const joinColumn = relationMetadata.joinColumns.find( (column) => getEntityName(column.entityMetadata) === getEntityName(relationMetadata.entityMetadata) ); if (joinColumn == null) { throw new Error( `Invalid joinColumn detected: [${relationMetadata.joinColumns.length}] ${relationMetadata.propertyName}` ); } return { inverseJoinColumnNullable: joinColumn.isNullable, joinPropertyName: joinColumn.propertyName, joinColumnName: joinColumn.databaseName }; } // src/typeorm/relations/getJoinColumn.ts function getJoinColumn(relationMetadata) { if (relationMetadata.relationType === "one-to-one") { const joinColumn = relationMetadata.joinColumns.find( (column) => getEntityName(column.entityMetadata) === getEntityName(relationMetadata.entityMetadata) ); if (joinColumn != null) { return { inverseJoinColumnOne: true, inverseJoinColumnNullable: joinColumn.isNullable, joinPropertyName: joinColumn.propertyName, joinColumnName: joinColumn.databaseName, isDuplicate: false }; } const entityName = getEntityName(relationMetadata.entityMetadata); const inverseRelationMetadata = relationMetadata.inverseEntityMetadata.oneToOneRelations.find( (oneToOneRelation) => { return getEntityName(oneToOneRelation.inverseEntityMetadata) === entityName; } ); if (inverseRelationMetadata == null) { throw new Error(`Invalid joinColumn detected: ${relationMetadata.propertyName}`); } const inverseJoinColumn = inverseRelationMetadata.joinColumns.find( (column) => getEntityName(column.entityMetadata) === getEntityName(inverseRelationMetadata.entityMetadata) ); if (inverseJoinColumn == null) { throw new Error(`Invalid joinColumn detected: ${relationMetadata.propertyName}`); } return { inverseJoinColumnOne: true, inverseJoinColumnNullable: inverseRelationMetadata.isNullable, joinPropertyName: inverseJoinColumn.propertyName, joinColumnName: inverseJoinColumn.databaseName, isDuplicate: true }; } if (relationMetadata.relationType === "many-to-one") { return { ...getManyToOneJoinColumn(relationMetadata), inverseJoinColumnOne: true, isDuplicate: false }; } if (relationMetadata.relationType === "one-to-many") { const oneEntityName = getEntityName(relationMetadata.entityMetadata); const manyToOneRelation = relationMetadata.inverseEntityMetadata.manyToOneRelations.find( (manyToOneRelationMetadata) => { const entityName = getEntityName(manyToOneRelationMetadata.inverseEntityMetadata); return entityName === oneEntityName; } ); if (manyToOneRelation == null) { throw new Error(`Cannot found relation on many-to-one side: ${relationMetadata.entityMetadata.name}`); } return { ...getManyToOneJoinColumn(manyToOneRelation), inverseJoinColumnOne: false, isDuplicate: true }; } return getManyToManyJoinColumn(relationMetadata); } // src/typeorm/relations/getManyToManyEntityMetadata.ts function getManyToManyEntityMetadata(entityMetadatas, relationMetadata) { const entityName = getEntityName(relationMetadata.entityMetadata); const { joinTableName } = relationMetadata; const joinEntityMetadata = entityMetadatas.find((entityMetadata) => entityMetadata.name === joinTableName); if (joinEntityMetadata != null) { return joinEntityMetadata; } const manyToManyRelation = relationMetadata.inverseEntityMetadata.manyToManyRelations.find( (manyToOneRelationMetadata) => { const inverseEntityName = getEntityName(manyToOneRelationMetadata.inverseEntityMetadata); return inverseEntityName === entityName; } ); if (manyToManyRelation == null) { throw new Error("many-to-many relations need JoinTable more than one!"); } const inverseJoinTableName = manyToManyRelation.joinTableName; const inverseJoinEntityMetadata = entityMetadatas.find( (entityMetadata) => entityMetadata.name === inverseJoinTableName ); if (inverseJoinEntityMetadata == null) { throw new Error(`[many-to-many] cannot found entity: ${inverseJoinTableName}`); } return inverseJoinEntityMetadata; } // src/typeorm/relations/getRelationRecord.ts var import_consola8 = __toESM(require("consola")); var import_my_easy_fp18 = require("my-easy-fp"); var import_my_only_either = require("my-only-either"); function getRelationRecord(entityMetadatas, relationMetadata, metadata) { try { const entityDBName = getEntityName(relationMetadata.entityMetadata); const entityPropertyName = getEntityPropertyName(relationMetadata.entityMetadata); const inverseEntityDBName = getEntityName(relationMetadata.inverseEntityMetadata); const inverseEntityPropertyName = getEntityPropertyName(relationMetadata.inverseEntityMetadata); const { relationType } = relationMetadata; const { joinColumnName, joinPropertyName, inverseJoinColumnOne, inverseJoinColumnNullable, isDuplicate } = getJoinColumn(relationMetadata); const joinColumnOne = relationType === "one-to-many" || relationType === "one-to-one"; const relationHash = getRelationHash({ entity: entityDBName, inverseEntityName: inverseEntityDBName, relationType: relationMetadata.relationType }); const joinColumnNullable = relationMetadata.isNullable; import_consola8.default.debug(`relation: [${relationMetadata.relationType}] ${entityDBName} -> ${inverseEntityDBName}`); if (relationType === "many-to-many") { const joinEntityMetadata = getManyToManyEntityMetadata(entityMetadatas, relationMetadata); const joinEntityName = getEntityName(joinEntityMetadata); const joinEntityPropertyName = getEntityPropertyName(joinEntityMetadata); const order = [entityDBName, inverseEntityDBName].sort().indexOf(entityDBName) + 1; const relationRecord = { ...metadata, $kind: "relation", entity: entityDBName, name: entityPropertyName, dbName: entityDBName, change: CE_CHANGE_KIND.ADD, inverseEntityName: inverseEntityPropertyName, inverseEntityDBName, joinColumnName, joinPropertyName, relationHash, joinColumnOne, joinColumnNullable, inverseJoinColumnNullable, inverseJoinColumnOne, relationType, order, isDuplicate }; const manyToManyRelationEntityRecord = { ...metadata, $kind: "relation", entity: joinEntityName, name: joinEntityPropertyName, dbName: joinEntityName, change: CE_CHANGE_KIND.ADD, inverseEntityName: entityPropertyName, inverseEntityDBName: entityDBName, joinPropertyName, joinColumnName, joinColumnOne: false, joinColumnNullable: false, inverseJoinColumnOne: true, inverseJoinColumnNullable: false, relationType: "many-to-one", relationHash: getRelationHash({ entity: joinEntityName, inverseEntityName: joinEntityName, relationType: "many-to-one" }), isDuplicate: false, order: [joinEntityName, entityDBName].sort().indexOf(joinEntityName) + 1 }; return (0, import_my_only_either.pass)([relationRecord, manyToManyRelationEntityRecord]); } return (0, import_my_only_either.pass)([ { ...metadata, $kind: "relation", entity: entityDBName, name: entityPropertyName, dbName: entityDBName, change: CE_CHANGE_KIND.ADD, inverseEntityName: inverseEntityPropertyName, inverseEntityDBName, joinColumnName, joinPropertyName, relationHash, joinColumnOne, joinColumnNullable, inverseJoinColumnNullable, inverseJoinColumnOne, relationType, isDuplicate, order: [entityDBName, inverseEntityDBName].sort().indexOf(entityDBName) + 1 } ]); } catch (caught) { const err = (0, import_my_easy_fp18.isError)(caught, new Error("unknown error raised from getRelationData")); const reason = { columnName: "N/A", entityName: getEntityName(relationMetadata.entityMetadata), message: `${getEntityName(relationMetadata.entityMetadata)}: ${err.message}` }; return (0, import_my_only_either.fail)(reason); } } // src/typeorm/relations/getRelationRecords.ts var import_consola9 = __toESM(require("consola")); function getRelationRecords(dataSource, metadata) { const relationRecords = dataSource.entityMetadatas.map((entityMetadata) => { import_consola9.default.debug(`Entity: ${getEntityName(entityMetadata)}, Length: ${entityMetadata.relations.length}`); return entityMetadata.relations.map( (relation) => getRelationRecord(dataSource.entityMetadatas, relation, metadata) ); }).flat(); return relationRecords; } // src/modules/commands/building.ts var import_awilix3 = require("awilix"); var import_chalk = __toESM(require("chalk")); var import_fast_safe_stringify = __toESM(require("fast-safe-stringify")); var import_my_easy_fp19 = require("my-easy-fp"); var import_my_only_either2 = require("my-only-either"); var import_node_fs6 = __toESM(require("fs")); async function building(option, logging) { createLogger(logging); const logger = container.resolve(SymbolLogger); try { logger.info(`connection initialize: "${import_chalk.default.yellowBright(`${option.dataSourcePath}`)}"`); const dataSource = await getDataSource(option); const [templates] = await Promise.all([await loadTemplates(option), await dataSource.initialize()]); const renderer = new TemplateRenderer(templates.template, templates.default); if ((0, import_my_easy_fp19.isFalse)(dataSource.isInitialized)) { throw new Error(`Cannot initialize in ${(0, import_fast_safe_stringify.default)(dataSource.options, void 0, 2)}`); } container.register(SymbolDefaultTemplate, (0, import_awilix3.asValue)(templates.default)); container.register(SymbolTemplate, (0, import_awilix3.asValue)(templates.template)); container.register(SymbolDataSource, (0, import_awilix3.asValue)(dataSource)); container.register(SymbolTemplateRenderer, (0, import_awilix3.asValue)(renderer)); const metadata = await getMetadata(option); logger.success("connection initialized"); logger.info(`version: ${metadata.version}`); logger.info(`extract entities in ${getDatabaseName(dataSource.options)}`); const entities = getEntityRecords(dataSource, metadata); const indicesRecords = getIndexRecords(dataSource, metadata); const columns = dataSource.entityMetadatas.map((entity) => entity.columns.map((column) => getColumnRecord(column, option, metadata, indicesRecords))).flat(); const relationRecords = getRelationRecords(dataSource, metadata); const failRelations = relationRecords.filter((relationRecord) => (0, import_my_only_either2.isFail)(relationRecord)).map((relationRecord) => relationRecord.fail).flat(); failRelations.forEach((relation) => logger.warn(relation.message)); const passRelations = relationRecords.filter((relation) => (0, import_my_only_either2.isPass)(relation)).map((relationRecord) => relationRecord.pass).flat(); const dedupedRelations = dedupeManaToManyRelationRecord(passRelations); const records = [...entities, ...columns, ...dedupedRelations, ...indicesRecords]; logger.success("complete extraction"); logger.info("Database open and processing"); const db = await openDatabase(option); const processedDb = await processDatabase(metadata, db, option); const compared = compareDatabase(metadata, records, processedDb.prev); const nextDb = [...compared, ...processedDb.next]; const renderData = await getRenderData(nextDb, metadata, option); await flushDatabase(option, nextDb); logger.success("Database open and processing completed"); logger.info(`output format: ${option.format}`); if (option.format === CE_OUTPUT_FORMAT.HTML) { const imageOption = { ...option, format: CE_OUTPUT_FORMAT.IMAGE, imageFormat: "svg", width: "200%", theme: CE_MERMAID_THEME.DARK }; const documents = await createHtml(option, renderData); await Promise.all( documents.map(async (document) => { await betterMkdir(document.dirname); await import_node_fs6.default.promises.writeFile(document.filename, document.content); }) ); if (!option.skipImageInHtml) { const imageDocument = await createImageHtml(imageOption, renderData); await writeToImage(imageDocument, imageOption, renderData); } return documents.map((document) => document.filename); } if (option.format === CE_OUTPUT_FORMAT.MARKDOWN) { const document = await createMarkdown(option, renderData); await betterMkdir(document.dirname); await import_node_fs6.default.promises.writeFile(document.filename, document.content); return [document.filename]; } if (option.format === CE_OUTPUT_FORMAT.PDF) { const document = await createPdfHtml(option, renderData); const filenames = await writeToPdf(document, option, renderData); return filenames; } if (option.format === CE_OUTPUT_FORMAT.IMAGE) { const document = await createImageHtml(option, renderData); await betterMkdir(document.dirname); const filenames = await writeToImage(document, option, renderData); return filenames; } return []; } catch (caught) { const err = (0, import_my_easy_fp19.isError)(caught, new Error("unknown error raised from createHtmlDocCommand")); logger.error(err); return []; } finally { if (container.hasRegistration(SymbolDataSource)) { const dataSource = container.resolve(SymbolDataSource); await dataSource.destroy(); } } } // src/cli/commands/buildDocumentCommandHandler.ts var import_cli_logo = require("@maeum/cli-logo"); var import_consola10 = require("consola"); async function buildDocumentCommandHandler(option) { const logger = container.resolve(SymbolLogger); logger.level = import_consola10.LogLevels.info; logger.enable = true; if (option.showLogo != null) { await (0, import_cli_logo.showLogo)({ message: "erdia", figlet: { font: "ANSI Shadow", width: 80 }, color: "cyan" }); } else { logger.info("erdia build start"); } await building(option); } // src/modules/commands/cleaning.ts var import_cli_logo2 = require("@maeum/cli-logo"); var import_awilix4 = require("awilix"); var import_consola11 = __toESM(require("consola")); var import_del3 = __toESM(require("del")); var import_fast_safe_stringify2 = __toESM(require("fast-safe-stringify")); var import_my_easy_fp20 = require("my-easy-fp"); var import_pathe19 = __toESM(require("pathe")); async function cleaning(option) { try { if (option.showLogo != null) { await (0, import_cli_logo2.showLogo)({ message: "erdia", figlet: { font: "ANSI Shadow", width: 80 }, color: "cyan" }); } else { import_consola11.default.info("erdia build start"); } const dataSource = await getDataSource(option); await dataSource.initialize(); if ((0, import_my_easy_fp20.isFalse)(dataSource.isInitialized)) { throw new Error(`Cannot initialize in ${(0, import_fast_safe_stringify2.default)(dataSource.options, void 0, 2)}`); } container.register(SymbolDataSource, (0, import_awilix4.asValue)(dataSource)); const metadata = await getMetadata({ ...option, versionFrom: "package.json", projectName: "app" }); const outputDirPath = await getOutputDirPath(option, getCwd(process.env)); const filenames = [ import_pathe19.default.join(outputDirPath, CE_DEFAULT_VALUE.HTML_MERMAID_FILENAME), import_pathe19.default.join(outputDirPath, CE_DEFAULT_VALUE.HTML_INDEX_FILENAME), import_pathe19.default.join(outputDirPath, `${metadata.name}.md`), import_pathe19.default.join(outputDirPath, `${metadata.name}.png`), import_pathe19.default.join(outputDirPath, `${metadata.name}.svg`) ]; await (0, import_del3.default)(filenames); return filenames; } catch (caught) { const err = (0, import_my_easy_fp20.isError)(caught, new Error("unknown error raised from createHtmlDocCommand")); import_consola11.default.error(err); return []; } finally { if (container.hasRegistration(SymbolDataSource)) { const dataSource = container.resolve(SymbolDataSource); await dataSource.destroy(); } } } // src/cli/commands/cleanDocumentCommandHandler.ts var import_cli_logo3 = require("@maeum/cli-logo"); var import_consola12 = __toESM(require("consola")); async function cleanDocumentCommandHandler(option) { const logger = container.resolve(SymbolLogger); logger.level = import_consola12.LogLevels.info; logger.enable = true; if (option.showLogo != null) { await (0, import_cli_logo3.showLogo)({ message: "erdia", figlet: { font: "ANSI Shadow", width: 80 }, color: "cyan" }); } else { import_consola12.default.info("erdia build start"); } await cleaning(option); } // src/configs/const-enum/CE_IMAGE_FORMAT.ts var CE_IMAGE_FORMAT = { SVG: "svg", PNG: "png" }; // src/configs/modules/getAutoCompleteSource.ts var import_mathjs2 = require("mathjs"); function getAutoCompleteSource(fuse, limit) { return (_answersSoFar, input) => { const safeInput = input === void 0 || input === null ? "" : input; return fuse.search(safeInput).map((matched) => { return { ...matched, oneBased: (0, import_mathjs2.bignumber)(1).sub((0, import_mathjs2.bignumber)(matched.score ?? 0)).mul(100).floor().div(100).toNumber(), percent: (0, import_mathjs2.bignumber)(1).sub((0, import_mathjs2.bignumber)(matched.score ?? 0)).mul(1e4).floor().div(100).toNumber() }; }).filter((matched) => matched.percent > limit).sort((l, r) => r.percent - l.percent).map((matched) => matched.item); }; } // src/modules/files/getTemplateDirPath.ts var import_my_easy_fp21 = require("my-easy-fp"); var import_my_node_fp11 = require("my-node-fp"); var import_pathe20 = __toESM(require("pathe")); async function getTemplateDirPath(option, cwd) { const templateDirPath = import_pathe20.default.join(option.templatePath ?? import_pathe20.default.join(cwd, CE_DEFAULT_VALUE.TEMPLATES_PATH)); const resolvedTemplateDirPath = import_pathe20.default.resolve(templateDirPath); if ((0, import_my_easy_fp21.isFalse)(await (0, import_my_node_fp11.exists)(resolvedTemplateDirPath))) { await betterMkdir(import_pathe20.default.join(resolvedTemplateDirPath)); return resolvedTemplateDirPath; } if ((0, import_my_easy_fp21.isFalse)(await (0, import_my_node_fp11.isDirectory)(templateDirPath))) { return import_pathe20.default.resolve(await (0, import_my_node_fp11.getDirname)(templateDirPath)); } return import_pathe20.default.resolve(templateDirPath); } // src/modules/commands/ejecting.ts var import_glob2 = require("glob"); var import_my_easy_fp22 = require("my-easy-fp"); var import_my_node_fp12 = require("my-node-fp"); var import_node_fs7 = __toESM(require("fs")); var import_pathe21 = __toESM(require("pathe")); async function ejecting(option, logging) { createLogger(logging); const logger = container.resolve(SymbolLogger); try { const templateDirPath = await getTemplateDirPath(option, getCwd(process.env)); const originTemplateDirPath = await getTemplateModulePath(CE_DEFAULT_VALUE.TEMPLATES_PATH); const targetTemplateDirPath = option.templatePath == null ? import_pathe21.default.join(templateDirPath, CE_DEFAULT_VALUE.TEMPLATES_PATH) : templateDirPath; logger.info("Template directory: ", targetTemplateDirPath); const originTemplateGlobPaths = new import_glob2.Glob(import_pathe21.default.join(originTemplateDirPath, `**`, "*.eta"), { absolute: true, ignore: [...defaultExclude, "config/**"], cwd: originTemplateDirPath, windowsPathsNoEscape: true }); const originTemplateFilePaths = getGlobFiles(originTemplateGlobPaths); await Promise.all( originTemplateFilePaths.map(async (originTemplateFilePath) => { const subDirPath = await (0, import_my_node_fp12.getDirname)(originTemplateFilePath); const subFilePath = (0, import_my_node_fp12.startSepRemove)(originTemplateFilePath.replace(subDirPath, "")); const targetTemplateSubDirPath = import_pathe21.default.join( targetTemplateDirPath, (0, import_my_node_fp12.startSepRemove)(subDirPath.replace(originTemplateDirPath, "")) ); await betterMkdir(targetTemplateSubDirPath); const templateFileBuf = await import_node_fs7.default.promises.readFile(originTemplateFilePath); await import_node_fs7.default.promises.writeFile(import_pathe21.default.join(targetTemplateSubDirPath, subFilePath), templateFileBuf); }) ); logger.success("eject success: ", targetTemplateDirPath); return targetTemplateDirPath; } catch (caught) { const err = (0, import_my_easy_fp22.isError)(caught, new Error("unknown error raised from createHtmlDocCommand")); logger.error(err); return void 0; } } // src/configs/modules/getConfigContent.ts var import_fuse = __toESM(require("fuse.js")); var import_glob3 = require("glob"); var import_inquirer = __toESM(require("inquirer")); var import_inquirer_autocomplete_prompt = __toESM(require("inquirer-autocomplete-prompt")); var import_pathe22 = __toESM(require("pathe")); async function getConfigContent() { const sourceGlobFiles = new import_glob3.Glob(["**/*.js", "**/*.cjs", "**/*.mjs", "**/*.ts", "**/*.cts", "**/*.mts"], { // absolute: true, ignore: defaultExclude, cwd: process.cwd(), onlyFiles: true }); const sourceFiles = getGlobFiles(sourceGlobFiles); const everyGlobFiles = new import_glob3.Glob(["**/*"], { // absolute: true, ignore: defaultExclude, cwd: process.cwd(), dot: true, onlyFiles: true }); const everyFiles = getGlobFiles(everyGlobFiles); const directoryGlobDirPaths = new import_glob3.Glob(["**/*"], { // absolute: true, ignore: defaultExclude, cwd: process.cwd(), dot: true, onlyDirectories: true }); const directories = getGlobFiles(directoryGlobDirPaths); const sourceFilesFuse = new import_fuse.default(sourceFiles, { includeScore: true }); const everyFilesFuse = new import_fuse.default(everyFiles, { includeScore: true }); const directoriesFuse = new import_fuse.default(directories, { includeScore: true }); import_inquirer.default.registerPrompt("autocomplete", import_inquirer_autocomplete_prompt.default); const answer = await import_inquirer.default.prompt([ { type: "autocomplete", name: "dataSourceFile", message: "Select a dataSource file: ", source: getAutoCompleteSource(sourceFilesFuse, CE_DEFAULT_VALUE.DATA_SOURCE_FILE_FUZZY_SCORE_LIMIT) }, { type: "autocomplete", name: "output", message: "Select directory for output files: ", source: getAutoCompleteSource(directoriesFuse, CE_DEFAULT_VALUE.OUTPUT_DIRECTORY_FUZZY_SCORE_LIMIT) }, { type: "list", name: "projectName", message: "Select output type: ", choices: [ { name: "database: document name came from database name", value: "db" }, { name: "application: document name came from name in package.json", value: "app" } ] }, { type: "list", name: "isEjectTemplate", message: "Want to eject template? ", choices: [ { name: "use custom template: eject template", value: true }, { name: "use default template: not eject template", value: false } ] }, { type: "list", name: "format", message: "Select output type: ", default: CE_OUTPUT_FORMAT.HTML, choices: [ { name: "html", value: CE_OUTPUT_FORMAT.HTML }, { name: "markdown", value: CE_OUTPUT_FORMAT.MARKDOWN }, { name: "pdf", value: CE_OUTPUT_FORMAT.PDF }, { name: "image", value: CE_OUTPUT_FORMAT.IMAGE } ] }, { type: "list", name: "isSelectDatabasePath", message: "Want to select the entity database file path?", default: false, choices: [ { name: "yes", value: true }, { name: "no", value: false } ] }, { type: "autocomplete", name: "databasePath", message: "Select the entity database file path: ", source: getAutoCompleteSource(directoriesFuse, CE_DEFAULT_VALUE.OUTPUT_DIRECTORY_FUZZY_SCORE_LIMIT), when: (answerForWhen) => { return answerForWhen.isSelectDatabasePath; } }, { type: "list", name: "isEnterRouteBasePath", message: "Want to enter route base path for html document? ", default: false, choices: [ { name: "enter rotue base path", value: true }, { name: "skip", value: false } ], when: (answerForWhen) => { return answerForWhen.format === CE_OUTPUT_FORMAT.HTML; } }, { type: "input", name: "routeBasePath", message: "Enter your route base path: ", when: (answerForWhen) => { return answerForWhen.format === CE_OUTPUT_FORMAT.HTML && answerForWhen.isEnterRouteBasePath; } }, { type: "list", name: "versionFrom", message: "Select version extract style: ", choices: [ { name: "extract from package.json", value: CE_ENTITY_VERSION_FROM.PACKAGE_JSON }, { name: "extract from file(need version file selection)", value: CE_ENTITY_VERSION_FROM.FILE }, { name: "use timestamp(all stored different version)", value: CE_ENTITY_VERSION_FROM.TIMESTAMP } ], when: (answerForWhen) => { return answerForWhen.format !== CE_OUTPUT_FORMAT.IMAGE; } }, { type: "autocomplete", name: "versionPath", message: "Select the version file path: ", source: getAutoCompleteSource(everyFilesFuse, CE_DEFAULT_VALUE.OUTPUT_DIRECTORY_FUZZY_SCORE_LIMIT), when: (answerForWhen) => { return answerForWhen.versionFrom === CE_ENTITY_VERSION_FROM.FILE; } }, { type: "list", name: "theme", message: "Select mermaid theme: ", choices: [ { name: "default", value: CE_MERMAID_THEME.DEFAULT }, { name: "forest", value: CE_MERMAID_THEME.FOREST }, { name: "dark", value: CE_MERMAID_THEME.DARK }, { name: "neutral", value: CE_MERMAID_THEME.NEUTRAL }, { name: "null", value: CE_MERMAID_THEME.NULL } ] }, { type: "checkbox", name: "components", message: "Check component in document: ", choices: [ ...[CE_OUTPUT_COMPONENT.TABLE, CE_OUTPUT_COMPONENT.ER].map( (component) => component === CE_OUTPUT_COMPONENT.ER ? { name: "ER diagram", value: "er", checked: true } : { name: "Entity specification table", value: "table", checked: true } ) ], when: (answerForWhen) => { return answerForWhen.format !== "image"; } }, { type: "list", name: "imageFormat", message: "Select image format: ", choices: [ { name: "svg", checked: CE_IMAGE_FORMAT.SVG }, { name: "png", checked: CE_IMAGE_FORMAT.PNG } ], when: (answerForWhen) => { return answerForWhen.format === "image"; } } ]); const templateDir = await (answer.isEjectTemplate ? ejecting({ templatePath: import_pathe22.default.join(getCwd(process.env), CE_DEFAULT_VALUE.TEMPLATES_PATH), showLogo: false }) : Promise.resolve(void 0)); const renderer = container.resolve(SymbolTemplateRenderer); const file = await renderer.evaluate(CE_TEMPLATE_NAME.CONFIG_JSON, { config: { ...answer, templatePath: templateDir != null ? import_pathe22.default.relative(getCwd(process.env), templateDir) : templateDir, versionFrom: answer.versionFrom != null ? answer.versionFrom : CE_ENTITY_VERSION_FROM.TIMESTAMP, config: CE_DEFAULT_VALUE.CONFIG_FILE_NAME } }); return file; } // src/modules/commands/initializing.ts var import_awilix5 = require("awilix"); var import_fs4 = __toESM(require("fs")); var import_my_easy_fp23 = require("my-easy-fp"); async function initializing(logging) { createLogger(logging); const logger = container.resolve(SymbolLogger); try { const templates = await loadTemplates(); const renderer = new TemplateRenderer(templates.template, templates.default); container.register(SymbolTemplateRenderer, (0, import_awilix5.asValue)(renderer)); const rawConfig = await getConfigContent(); const prettiered = await applyPrettier(rawConfig, "json"); await import_fs4.default.promises.writeFile(CE_DEFAULT_VALUE.CONFIG_FILE_NAME, prettiered); logger.info(`${CE_DEFAULT_VALUE.CONFIG_FILE_NAME} file created`); return rawConfig; } catch (caught) { const err = (0, import_my_easy_fp23.isError)(caught, new Error("unknown error raised from createHtmlDocCommand")); logger.error(err); return void 0; } } // src/cli/commands/initConfigCommandHandler.ts var import_consola13 = require("consola"); async function initConfigCommandHandler() { const logger = container.resolve(SymbolLogger); logger.level = import_consola13.LogLevels.info; logger.enable = true; const configFilePath = await initializing(); return configFilePath; } // src/cli/commands/templateEjectCommandHandler.ts var import_cli_logo4 = require("@maeum/cli-logo"); var import_consola14 = __toESM(require("consola")); async function templateEjectCommandHandler(option) { const logger = container.resolve(SymbolLogger); logger.level = import_consola14.LogLevels.info; logger.enable = true; if (option.showLogo != null) { await (0, import_cli_logo4.showLogo)({ message: "erdia", figlet: { font: "ANSI Shadow", width: 80 }, color: "cyan" }); } else { import_consola14.default.info("erdia build start"); } const targetTemplateDirPath = await ejecting(option); return targetTemplateDirPath; } // src/configs/const-enum/CE_COMMAND_LIST.ts var CE_COMMAND_LIST = { BUILD: "build", INIT: "init", CLEAN: "clean", EJECT: "eject", BUILD_ALIAS: "b", INIT_ALIAS: "i", CLEAN_ALIAS: "c", EJECT_ALIAS: "e" }; // src/configs/modules/getConfigFilePath.ts var findUp2 = __toESM(require("find-up")); function getConfigFilePath(argv) { const configFilePathSearchResultOnCwd = findUp2.sync(CE_DEFAULT_VALUE.CONFIG_FILE_NAME, { cwd: getCwd(process.env) }); const getConfigValue = () => { if (typeof argv.c === "string" && argv.c !== "") { return argv.c; } if (typeof argv.config === "string" && argv.config !== "") { return argv.config; } return void 0; }; return getConfigValue() ?? configFilePathSearchResultOnCwd; } // src/configs/modules/preLoadConfig.ts var import_consola15 = __toESM(require("consola")); var import_jsonc_parser4 = require("jsonc-parser"); var import_minimist = __toESM(require("minimist")); var fs12 = __toESM(require("fs")); function preLoadConfig() { try { const argv = (0, import_minimist.default)(process.argv.slice(2)); const configFilePath = getConfigFilePath(argv); const readConfigFile = () => { if (configFilePath != null) { const buf = fs12.readFileSync(configFilePath); const parsed = (0, import_jsonc_parser4.parse)(buf.toString()); return parsed; } return { "data-source-path": void 0 }; }; const config = readConfigFile(); return { ...config, c: configFilePath, config: configFilePath }; } catch (caught) { const err = caught instanceof Error ? caught : new Error("unknown error raised"); import_consola15.default.error(err); import_consola15.default.error(err.stack); return {}; } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { CE_CHANGE_KIND, CE_COLUMN_ATTRIBUTE, CE_COMMAND_LIST, CE_DEFAULT_VALUE, CE_ENTITY_VERSION_FROM, CE_IMAGE_FORMAT, CE_MERMAID_THEME, CE_OUTPUT_COMPONENT, CE_OUTPUT_FORMAT, CE_PROJECT_NAME_FROM, CE_RECORD_KIND, CE_TEMPLATE_NAME, Logger, SymbolDataSource, SymbolDefaultTemplate, SymbolLogger, SymbolTemplate, SymbolTemplateRenderer, TemplateRenderer, applyPrettier, betterMkdir, buildDocumentCommandHandler, buildOptionBuilder, building, cleanDocumentCommandHandler, cleaning, commonOptionBuilder, compareDatabase, configTemplate, container, createHtml, createImageHtml, createLogger, createMarkdown, createPdfHtml, dedupeManaToManyRelationRecord, defaultExclude, documentOptionBuilder, ejecting, flushDatabase, getAutoCompleteSource, getColumnAttributeKey, getColumnHash, getColumnRecord, getColumnType, getColumnWeight, getComment, getConfigContent, getConfigFilePath, getCwd, getDataSource, getDatabaseName, getEntityHash, getEntityName, getEntityPropertyName, getEntityRecord, getEntityRecords, getFileVersion, getFindFile, getGlobFiles, getIndexHash, getIndexRecord, getIndexRecords, getInverseRelationMetadata, getIsNullable, getJoinColumn, getManyToManyEntityMetadata, getManyToManyJoinColumn, getManyToOneJoinColumn, getMetadata, getOutputDirPath, getPackageName, getPlainRelationType, getProjectName, getPuppeteerConfig, getRelationHash, getRelationRecord, getRelationRecords, getRenderData, getSlashEndRoutePath, getTemplate, getTemplateDirPath, getTemplateModulePath, getTemplatePath, getTemplates, getVersion, initConfigCommandHandler, initializing, loadDataSource, loadTemplates, openDatabase, outputOptionBuilder, preLoadConfig, processDatabase, templateEjectCommandHandler, writeToImage, writeToPdf }); //# sourceMappingURL=index.cjs.map