mikro-orm-markdown 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cli.cjs +326 -197
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +5 -2
- package/dist/cli.d.ts +5 -2
- package/dist/cli.js +329 -200
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +242 -131
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +244 -133
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -76,17 +76,7 @@ function loadJsDoc(filePaths, onWarn) {
|
|
|
76
76
|
if (classDocs.length > 0) {
|
|
77
77
|
entities.set(className, parseEntityJsDoc(classDocs));
|
|
78
78
|
}
|
|
79
|
-
const propMap =
|
|
80
|
-
for (const prop of cls.getProperties()) {
|
|
81
|
-
const propDocs = prop.getJsDocs();
|
|
82
|
-
if (propDocs.length === 0) {
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
const info = parsePropJsDoc(propDocs);
|
|
86
|
-
if (info.description !== void 0 || info.atLeastOne) {
|
|
87
|
-
propMap.set(prop.getName(), info);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
79
|
+
const propMap = collectPropJsDocs(cls);
|
|
90
80
|
if (propMap.size > 0) {
|
|
91
81
|
props.set(className, propMap);
|
|
92
82
|
}
|
|
@@ -103,6 +93,28 @@ function formatUnknownError(err) {
|
|
|
103
93
|
function hasGlobPattern(filePath) {
|
|
104
94
|
return /[*?[\]{}]/.test(filePath);
|
|
105
95
|
}
|
|
96
|
+
function collectPropJsDocs(cls) {
|
|
97
|
+
const propMap = /* @__PURE__ */ new Map();
|
|
98
|
+
for (const prop of [...cls.getProperties(), ...cls.getGetAccessors()]) {
|
|
99
|
+
const info = parsePropJsDoc(prop.getJsDocs());
|
|
100
|
+
addPropInfo(propMap, prop.getName(), info);
|
|
101
|
+
}
|
|
102
|
+
for (const prop of getConstructorParameterProperties(cls)) {
|
|
103
|
+
const info = parseCompilerPropJsDoc(import_ts_morph.ts.getJSDocCommentsAndTags(prop.compilerNode));
|
|
104
|
+
addPropInfo(propMap, prop.getName(), info);
|
|
105
|
+
}
|
|
106
|
+
return propMap;
|
|
107
|
+
}
|
|
108
|
+
function getConstructorParameterProperties(cls) {
|
|
109
|
+
return cls.getConstructors().flatMap(
|
|
110
|
+
(constructorDeclaration) => constructorDeclaration.getParameters().filter((param) => param.isParameterProperty())
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
function addPropInfo(propMap, propName, info) {
|
|
114
|
+
if (info.description !== void 0 || info.atLeastOne) {
|
|
115
|
+
propMap.set(propName, info);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
106
118
|
function parseEntityJsDoc(jsDocs) {
|
|
107
119
|
const namespaces = [];
|
|
108
120
|
const erdNamespaces = [];
|
|
@@ -152,6 +164,35 @@ function parsePropJsDoc(jsDocs) {
|
|
|
152
164
|
}
|
|
153
165
|
return { ...description !== void 0 && { description }, atLeastOne };
|
|
154
166
|
}
|
|
167
|
+
function parseCompilerPropJsDoc(jsDocs) {
|
|
168
|
+
let description;
|
|
169
|
+
let atLeastOne = false;
|
|
170
|
+
for (const doc of jsDocs) {
|
|
171
|
+
if (import_ts_morph.ts.isJSDoc(doc)) {
|
|
172
|
+
const desc = formatCompilerJsDocComment(doc.comment);
|
|
173
|
+
if (desc && description === void 0) {
|
|
174
|
+
description = desc;
|
|
175
|
+
}
|
|
176
|
+
for (const tag of doc.tags ?? []) {
|
|
177
|
+
if (tag.tagName.getText() === "atLeastOne") {
|
|
178
|
+
atLeastOne = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (doc.tagName.getText() === "atLeastOne") {
|
|
184
|
+
atLeastOne = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return { ...description !== void 0 && { description }, atLeastOne };
|
|
188
|
+
}
|
|
189
|
+
function formatCompilerJsDocComment(comment) {
|
|
190
|
+
if (comment === void 0) {
|
|
191
|
+
return void 0;
|
|
192
|
+
}
|
|
193
|
+
const trimmed = import_ts_morph.ts.getTextOfJSDocComment(comment)?.trim();
|
|
194
|
+
return trimmed === void 0 || trimmed === "" ? void 0 : trimmed;
|
|
195
|
+
}
|
|
155
196
|
|
|
156
197
|
// src/metadata/load.ts
|
|
157
198
|
var path = __toESM(require("path"), 1);
|
|
@@ -191,6 +232,44 @@ function assertNoEntitySchemaEntities(options) {
|
|
|
191
232
|
Use decorator-based @Entity() classes instead.`
|
|
192
233
|
);
|
|
193
234
|
}
|
|
235
|
+
function hasDecoratorMarker(target) {
|
|
236
|
+
const pathSymbol = import_core.MetadataStorage.PATH_SYMBOL;
|
|
237
|
+
if (typeof pathSymbol === "symbol" && pathSymbol in target) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
return "__path" in target;
|
|
241
|
+
}
|
|
242
|
+
function isRenderableMeta(meta) {
|
|
243
|
+
return !meta.pivotTable && !meta.embeddable;
|
|
244
|
+
}
|
|
245
|
+
function assertDiscoveredEntitiesAreSupported(metas) {
|
|
246
|
+
const confirmed = [];
|
|
247
|
+
const unconfirmed = [];
|
|
248
|
+
for (const meta of metas) {
|
|
249
|
+
if (!isRenderableMeta(meta)) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (import_core.EntitySchema.REGISTRY.has(meta.class)) {
|
|
253
|
+
confirmed.push(meta.className);
|
|
254
|
+
} else if (!hasDecoratorMarker(meta.class)) {
|
|
255
|
+
unconfirmed.push(meta.className);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (confirmed.length === 0 && unconfirmed.length === 0) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const lines = [];
|
|
262
|
+
if (confirmed.length > 0) {
|
|
263
|
+
lines.push(`EntitySchema-defined entities are not currently supported: ${confirmed.join(", ")}.`);
|
|
264
|
+
}
|
|
265
|
+
if (unconfirmed.length > 0) {
|
|
266
|
+
lines.push(
|
|
267
|
+
`Could not confirm these entities are decorator-based @Entity() classes: ${unconfirmed.join(", ")}. This usually means they are EntitySchema-defined entities (also not currently supported). If you're certain these are valid @Entity() classes, this may be a detection false positive in mikro-orm-markdown \u2014 please open an issue: https://github.com/iamkanguk97/mikro-orm-markdown/issues`
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
lines.push("Use decorator-based @Entity() classes instead.");
|
|
271
|
+
throw new MetadataLoadError(lines.join("\n"));
|
|
272
|
+
}
|
|
194
273
|
async function loadEntityMetadata(options) {
|
|
195
274
|
assertNoEntitySchemaEntities(options);
|
|
196
275
|
let orm;
|
|
@@ -217,6 +296,7 @@ async function loadEntityMetadata(options) {
|
|
|
217
296
|
"No entities were discovered. Check that your config specifies at least one entity path or class."
|
|
218
297
|
);
|
|
219
298
|
}
|
|
299
|
+
assertDiscoveredEntitiesAreSupported(all);
|
|
220
300
|
const baseDir = orm.config.get("baseDir");
|
|
221
301
|
const sourcePaths = [...new Set(all.filter((m) => m.path).map((m) => path.resolve(baseDir, m.path)))];
|
|
222
302
|
return { metas: all, sourcePaths };
|
|
@@ -228,55 +308,8 @@ async function loadEntityMetadata(options) {
|
|
|
228
308
|
// src/model/build.ts
|
|
229
309
|
var import_core3 = require("@mikro-orm/core");
|
|
230
310
|
|
|
231
|
-
// src/
|
|
311
|
+
// src/model/diagram.ts
|
|
232
312
|
var import_core2 = require("@mikro-orm/core");
|
|
233
|
-
|
|
234
|
-
// src/render/escape.ts
|
|
235
|
-
var MARKDOWN_INLINE_SPECIAL_CHARS = /[\\`|*#]/g;
|
|
236
|
-
var MERMAID_IDENTIFIER_INVALID_CHARS = /[^a-zA-Z0-9_]/g;
|
|
237
|
-
function normalizeInlineText(value) {
|
|
238
|
-
return value.replace(/\r\n?/g, "\n").replace(/[\n\t]+/g, " ").replace(/\s{2,}/g, " ").trim();
|
|
239
|
-
}
|
|
240
|
-
function splitNormalizedLines(value) {
|
|
241
|
-
return value.replace(/\r\n?/g, "\n").split("\n");
|
|
242
|
-
}
|
|
243
|
-
function escapeHtmlText(value) {
|
|
244
|
-
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
245
|
-
}
|
|
246
|
-
function escapeMarkdownInline(value) {
|
|
247
|
-
return escapeHtmlText(normalizeInlineText(value)).replace(MARKDOWN_INLINE_SPECIAL_CHARS, "\\$&");
|
|
248
|
-
}
|
|
249
|
-
function escapeMarkdownTableCell(value) {
|
|
250
|
-
return splitNormalizedLines(value).map((line) => escapeMarkdownInline(line)).join("<br>");
|
|
251
|
-
}
|
|
252
|
-
function escapeMarkdownParagraph(value) {
|
|
253
|
-
return splitNormalizedLines(value).map((line) => escapeMarkdownInline(line)).join(" \n");
|
|
254
|
-
}
|
|
255
|
-
function renderMarkdownBlockQuote(value) {
|
|
256
|
-
return splitNormalizedLines(value).map((line) => `> ${escapeMarkdownInline(line)}`).join("\n");
|
|
257
|
-
}
|
|
258
|
-
function renderMarkdownInlineCode(value) {
|
|
259
|
-
const normalized = normalizeInlineText(value);
|
|
260
|
-
const backtickRuns = normalized.match(/`+/g) ?? [];
|
|
261
|
-
const longestRun = Math.max(0, ...backtickRuns.map((run) => run.length));
|
|
262
|
-
const fence = "`".repeat(longestRun + 1);
|
|
263
|
-
const needsPadding = normalized.startsWith("`") || normalized.endsWith("`");
|
|
264
|
-
const content = needsPadding ? ` ${normalized} ` : normalized;
|
|
265
|
-
return `${fence}${content}${fence}`;
|
|
266
|
-
}
|
|
267
|
-
function toMermaidIdentifier(value) {
|
|
268
|
-
const normalized = normalizeInlineText(value).replace(MERMAID_IDENTIFIER_INVALID_CHARS, "_").replace(/_+/g, "_");
|
|
269
|
-
const identifier = normalized === "" ? "_" : normalized;
|
|
270
|
-
return /^[a-zA-Z_]/.test(identifier) ? identifier : `_${identifier}`;
|
|
271
|
-
}
|
|
272
|
-
function escapeMermaidQuotedText(value) {
|
|
273
|
-
return normalizeInlineText(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
274
|
-
}
|
|
275
|
-
function toMarkdownAnchor(value) {
|
|
276
|
-
return normalizeInlineText(value).toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s+/g, "-");
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// src/render/mermaid.ts
|
|
280
313
|
var FORMULA_DUMMY_TABLE = {
|
|
281
314
|
alias: "e0",
|
|
282
315
|
name: "",
|
|
@@ -547,75 +580,6 @@ function buildEdge(fromEntity, prop) {
|
|
|
547
580
|
}
|
|
548
581
|
return null;
|
|
549
582
|
}
|
|
550
|
-
function normalizeType(type) {
|
|
551
|
-
const t = type.toLowerCase().trim();
|
|
552
|
-
if (t === "uuid" || t === "text" || t === "string" || t.startsWith("varchar")) {
|
|
553
|
-
return "string";
|
|
554
|
-
}
|
|
555
|
-
if (t === "timestamptz" || t === "timestamp" || t === "datetime") {
|
|
556
|
-
return "datetime";
|
|
557
|
-
}
|
|
558
|
-
if (t === "integer" || t === "int" || t === "bigint" || t === "smallint") {
|
|
559
|
-
return "integer";
|
|
560
|
-
}
|
|
561
|
-
if (t === "doubletype" || t === "double precision" || t === "double" || t === "float" || t === "decimal") {
|
|
562
|
-
return "float";
|
|
563
|
-
}
|
|
564
|
-
if (t === "boolean" || t === "bool") {
|
|
565
|
-
return "boolean";
|
|
566
|
-
}
|
|
567
|
-
if (t === "jsonb") {
|
|
568
|
-
return "json";
|
|
569
|
-
}
|
|
570
|
-
return type;
|
|
571
|
-
}
|
|
572
|
-
function renderErDiagram(model, mermaid) {
|
|
573
|
-
const lines = [];
|
|
574
|
-
if (mermaid?.layout !== void 0 || mermaid?.theme !== void 0) {
|
|
575
|
-
lines.push("---", "config:");
|
|
576
|
-
if (mermaid.layout !== void 0) {
|
|
577
|
-
lines.push(` layout: ${mermaid.layout}`);
|
|
578
|
-
}
|
|
579
|
-
if (mermaid.theme !== void 0) {
|
|
580
|
-
lines.push(` theme: ${mermaid.theme}`);
|
|
581
|
-
}
|
|
582
|
-
lines.push("---");
|
|
583
|
-
}
|
|
584
|
-
lines.push("erDiagram");
|
|
585
|
-
for (const entity of model.entities) {
|
|
586
|
-
lines.push(` ${toMermaidIdentifier(entity.className)} {`);
|
|
587
|
-
for (const col of entity.columns) {
|
|
588
|
-
lines.push(` ${renderColumnLine(col)}`);
|
|
589
|
-
}
|
|
590
|
-
lines.push(" }");
|
|
591
|
-
}
|
|
592
|
-
for (const rel of model.relations) {
|
|
593
|
-
lines.push(
|
|
594
|
-
` ${toMermaidIdentifier(rel.fromEntity)} ${rel.fromCardinality}--${rel.toCardinality} ${toMermaidIdentifier(rel.toEntity)} : "${escapeMermaidQuotedText(rel.label)}"`
|
|
595
|
-
);
|
|
596
|
-
}
|
|
597
|
-
return lines.join("\n");
|
|
598
|
-
}
|
|
599
|
-
function renderColumnLine(col) {
|
|
600
|
-
let qualifier = "";
|
|
601
|
-
if (col.isPrimary) {
|
|
602
|
-
qualifier = " PK";
|
|
603
|
-
} else if (col.isUnique) {
|
|
604
|
-
qualifier = " UK";
|
|
605
|
-
}
|
|
606
|
-
let comment;
|
|
607
|
-
if (col.formula !== void 0) {
|
|
608
|
-
comment = col.formula ? `formula: ${col.formula}` : "formula";
|
|
609
|
-
} else if (col.isDiscriminator) {
|
|
610
|
-
comment = "discriminator";
|
|
611
|
-
} else if (col.embeddedIn !== void 0) {
|
|
612
|
-
comment = `[${col.embeddedIn}]`;
|
|
613
|
-
} else if (col.isSelfReference) {
|
|
614
|
-
comment = "self-ref";
|
|
615
|
-
}
|
|
616
|
-
const commentStr = comment !== void 0 ? ` "${escapeMermaidQuotedText(comment)}"` : "";
|
|
617
|
-
return `${toMermaidIdentifier(normalizeType(col.type))} ${toMermaidIdentifier(col.fieldName)}${qualifier}${commentStr}`;
|
|
618
|
-
}
|
|
619
583
|
|
|
620
584
|
// src/model/build.ts
|
|
621
585
|
var FROM_ONE_OR_MORE = "}|";
|
|
@@ -638,7 +602,10 @@ function buildDocumentModel(metas, jsDocResult, title, description, onWarn) {
|
|
|
638
602
|
const columns = model.columns.filter(
|
|
639
603
|
(col) => !(col.isForeignKey && col.referencedEntity !== void 0 && hiddenClasses.has(col.referencedEntity))
|
|
640
604
|
);
|
|
641
|
-
const visibleModel =
|
|
605
|
+
const visibleModel = removeHiddenEntityReferences(
|
|
606
|
+
columns.length === model.columns.length ? model : { ...model, columns },
|
|
607
|
+
hiddenClasses
|
|
608
|
+
);
|
|
642
609
|
const ownPropDocs = jsDocResult.props.get(model.className) ?? /* @__PURE__ */ new Map();
|
|
643
610
|
const propDocs = withEmbeddedPropDocs(ownPropDocs, visibleModel.columns, jsDocResult.props);
|
|
644
611
|
enrichedByClass.set(model.className, { model: visibleModel, jsDoc, propDocs });
|
|
@@ -689,6 +656,14 @@ function buildDocumentModel(metas, jsDocResult, title, description, onWarn) {
|
|
|
689
656
|
});
|
|
690
657
|
return { title, groups, ...description !== void 0 && { description } };
|
|
691
658
|
}
|
|
659
|
+
function removeHiddenEntityReferences(model, hiddenClasses) {
|
|
660
|
+
if (model.extendsEntity === void 0 || !hiddenClasses.has(model.extendsEntity)) {
|
|
661
|
+
return model;
|
|
662
|
+
}
|
|
663
|
+
const visibleModel = { ...model };
|
|
664
|
+
delete visibleModel.extendsEntity;
|
|
665
|
+
return visibleModel;
|
|
666
|
+
}
|
|
692
667
|
function withEmbeddedPropDocs(ownPropDocs, columns, allPropDocs) {
|
|
693
668
|
const merged = new Map(ownPropDocs);
|
|
694
669
|
for (const col of columns) {
|
|
@@ -800,6 +775,142 @@ async function withTsMorphMetadataProvider(options, onWarn) {
|
|
|
800
775
|
}
|
|
801
776
|
}
|
|
802
777
|
|
|
778
|
+
// src/render/escape.ts
|
|
779
|
+
var MARKDOWN_INLINE_SPECIAL_CHARS = /[\\`|*#\[\]]/g;
|
|
780
|
+
var MARKDOWN_EMPHASIS_UNDERSCORE = /(?<![a-zA-Z0-9])_|_(?![a-zA-Z0-9])/g;
|
|
781
|
+
var MERMAID_IDENTIFIER_INVALID_CHARS = /[^a-zA-Z0-9_]/g;
|
|
782
|
+
function normalizeInlineText(value) {
|
|
783
|
+
return value.replace(/\r\n?/g, "\n").replace(/[\n\t]+/g, " ").replace(/\s{2,}/g, " ").trim();
|
|
784
|
+
}
|
|
785
|
+
function splitNormalizedLines(value) {
|
|
786
|
+
return value.replace(/\r\n?/g, "\n").split("\n");
|
|
787
|
+
}
|
|
788
|
+
function escapeHtmlText(value) {
|
|
789
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
790
|
+
}
|
|
791
|
+
function escapeMarkdownInline(value) {
|
|
792
|
+
return escapeHtmlText(normalizeInlineText(value)).replace(MARKDOWN_INLINE_SPECIAL_CHARS, "\\$&").replace(MARKDOWN_EMPHASIS_UNDERSCORE, "\\_");
|
|
793
|
+
}
|
|
794
|
+
function escapeMarkdownTableCell(value) {
|
|
795
|
+
return splitNormalizedLines(value).map((line) => escapeMarkdownInline(line)).join("<br>");
|
|
796
|
+
}
|
|
797
|
+
function escapeMarkdownParagraph(value) {
|
|
798
|
+
return splitNormalizedLines(value).map((line) => escapeMarkdownInline(line)).join(" \n");
|
|
799
|
+
}
|
|
800
|
+
function renderMarkdownBlockQuote(value) {
|
|
801
|
+
return splitNormalizedLines(value).map((line) => `> ${escapeMarkdownInline(line)}`).join("\n");
|
|
802
|
+
}
|
|
803
|
+
function renderMarkdownInlineCode(value) {
|
|
804
|
+
const normalized = normalizeInlineText(value);
|
|
805
|
+
const backtickRuns = normalized.match(/`+/g) ?? [];
|
|
806
|
+
const longestRun = Math.max(0, ...backtickRuns.map((run) => run.length));
|
|
807
|
+
const fence = "`".repeat(longestRun + 1);
|
|
808
|
+
const needsPadding = normalized.startsWith("`") || normalized.endsWith("`");
|
|
809
|
+
const content = needsPadding ? ` ${normalized} ` : normalized;
|
|
810
|
+
return `${fence}${content}${fence}`;
|
|
811
|
+
}
|
|
812
|
+
function toMermaidIdentifier(value) {
|
|
813
|
+
const normalized = normalizeInlineText(value).replace(MERMAID_IDENTIFIER_INVALID_CHARS, "_").replace(/_+/g, "_");
|
|
814
|
+
const identifier = normalized === "" ? "_" : normalized;
|
|
815
|
+
return /^[a-zA-Z_]/.test(identifier) ? identifier : `_${identifier}`;
|
|
816
|
+
}
|
|
817
|
+
function escapeMermaidQuotedText(value) {
|
|
818
|
+
return normalizeInlineText(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
819
|
+
}
|
|
820
|
+
function toMarkdownAnchor(value) {
|
|
821
|
+
return normalizeInlineText(value).toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s+/g, "-");
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// src/render/mermaid.ts
|
|
825
|
+
var GENERIC_TYPE_BY_BASE_NAME = /* @__PURE__ */ new Map([
|
|
826
|
+
["uuid", "string"],
|
|
827
|
+
["text", "string"],
|
|
828
|
+
["string", "string"],
|
|
829
|
+
["varchar", "string"],
|
|
830
|
+
["character varying", "string"],
|
|
831
|
+
["character", "string"],
|
|
832
|
+
["char", "string"],
|
|
833
|
+
["tinytext", "string"],
|
|
834
|
+
["mediumtext", "string"],
|
|
835
|
+
["longtext", "string"],
|
|
836
|
+
["timestamptz", "datetime"],
|
|
837
|
+
["timestamp", "datetime"],
|
|
838
|
+
["datetime", "datetime"],
|
|
839
|
+
["integer", "integer"],
|
|
840
|
+
["int", "integer"],
|
|
841
|
+
["bigint", "integer"],
|
|
842
|
+
["smallint", "integer"],
|
|
843
|
+
["tinyint", "integer"],
|
|
844
|
+
["mediumint", "integer"],
|
|
845
|
+
["serial", "integer"],
|
|
846
|
+
["bigserial", "integer"],
|
|
847
|
+
["doubletype", "float"],
|
|
848
|
+
["double precision", "float"],
|
|
849
|
+
["double", "float"],
|
|
850
|
+
["float", "float"],
|
|
851
|
+
["decimal", "float"],
|
|
852
|
+
["numeric", "float"],
|
|
853
|
+
["real", "float"],
|
|
854
|
+
["boolean", "boolean"],
|
|
855
|
+
["bool", "boolean"],
|
|
856
|
+
["jsonb", "json"]
|
|
857
|
+
]);
|
|
858
|
+
function normalizeType(type) {
|
|
859
|
+
const t = type.toLowerCase().replace(/\s+/g, " ").trim();
|
|
860
|
+
if (/^tinyint\s*\(\s*1\s*\)$/.test(t)) {
|
|
861
|
+
return "boolean";
|
|
862
|
+
}
|
|
863
|
+
const baseName = t.replace(/\(.*\)/, "").replace(/\b(un)?signed\b/, "").trim();
|
|
864
|
+
return GENERIC_TYPE_BY_BASE_NAME.get(baseName) ?? type;
|
|
865
|
+
}
|
|
866
|
+
function renderErDiagram(model, mermaid) {
|
|
867
|
+
const lines = [];
|
|
868
|
+
if (mermaid?.layout !== void 0 || mermaid?.theme !== void 0) {
|
|
869
|
+
lines.push("---", "config:");
|
|
870
|
+
if (mermaid.layout !== void 0) {
|
|
871
|
+
lines.push(` layout: ${mermaid.layout}`);
|
|
872
|
+
}
|
|
873
|
+
if (mermaid.theme !== void 0) {
|
|
874
|
+
lines.push(` theme: ${mermaid.theme}`);
|
|
875
|
+
}
|
|
876
|
+
lines.push("---");
|
|
877
|
+
}
|
|
878
|
+
lines.push("erDiagram");
|
|
879
|
+
for (const entity of model.entities) {
|
|
880
|
+
lines.push(` ${toMermaidIdentifier(entity.className)} {`);
|
|
881
|
+
for (const col of entity.columns) {
|
|
882
|
+
lines.push(` ${renderColumnLine(col)}`);
|
|
883
|
+
}
|
|
884
|
+
lines.push(" }");
|
|
885
|
+
}
|
|
886
|
+
for (const rel of model.relations) {
|
|
887
|
+
lines.push(
|
|
888
|
+
` ${toMermaidIdentifier(rel.fromEntity)} ${rel.fromCardinality}--${rel.toCardinality} ${toMermaidIdentifier(rel.toEntity)} : "${escapeMermaidQuotedText(rel.label)}"`
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
return lines.join("\n");
|
|
892
|
+
}
|
|
893
|
+
function renderColumnLine(col) {
|
|
894
|
+
let qualifier = "";
|
|
895
|
+
if (col.isPrimary) {
|
|
896
|
+
qualifier = " PK";
|
|
897
|
+
} else if (col.isUnique) {
|
|
898
|
+
qualifier = " UK";
|
|
899
|
+
}
|
|
900
|
+
let comment;
|
|
901
|
+
if (col.formula !== void 0) {
|
|
902
|
+
comment = col.formula ? `formula: ${col.formula}` : "formula";
|
|
903
|
+
} else if (col.isDiscriminator) {
|
|
904
|
+
comment = "discriminator";
|
|
905
|
+
} else if (col.embeddedIn !== void 0) {
|
|
906
|
+
comment = `[${col.embeddedIn}]`;
|
|
907
|
+
} else if (col.isSelfReference) {
|
|
908
|
+
comment = "self-ref";
|
|
909
|
+
}
|
|
910
|
+
const commentStr = comment !== void 0 ? ` "${escapeMermaidQuotedText(comment)}"` : "";
|
|
911
|
+
return `${toMermaidIdentifier(normalizeType(col.type))} ${toMermaidIdentifier(col.fieldName)}${qualifier}${commentStr}`;
|
|
912
|
+
}
|
|
913
|
+
|
|
803
914
|
// src/render/markdown.ts
|
|
804
915
|
function renderMarkdown(docModel, mermaid) {
|
|
805
916
|
const sections = [`# ${escapeMarkdownInline(docModel.title)}`];
|
|
@@ -823,7 +934,7 @@ function renderBulletSection(header, items, renderItem) {
|
|
|
823
934
|
}
|
|
824
935
|
function renderTableOfContents(groups, anchors) {
|
|
825
936
|
return renderBulletSection("## Contents", groups, (group) => {
|
|
826
|
-
const label = escapeMarkdownInline(group.name)
|
|
937
|
+
const label = escapeMarkdownInline(group.name);
|
|
827
938
|
return `- [${label}](#${anchors.get(group) ?? toMarkdownAnchor(group.name)})`;
|
|
828
939
|
});
|
|
829
940
|
}
|
|
@@ -908,7 +1019,7 @@ function resolveColumnKey(col) {
|
|
|
908
1019
|
return "PK";
|
|
909
1020
|
}
|
|
910
1021
|
if (col.isForeignKey) {
|
|
911
|
-
return fkKey;
|
|
1022
|
+
return col.isUnique ? `${fkKey}, UK` : fkKey;
|
|
912
1023
|
}
|
|
913
1024
|
if (col.isUnique) {
|
|
914
1025
|
return "UK";
|