mikro-orm-markdown 0.1.0-alpha.2 → 0.1.0-alpha.3
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 +53 -0
- package/CODE_OF_CONDUCT.md +25 -0
- package/LICENSE +1 -1
- package/README.ko.md +248 -41
- package/README.md +248 -41
- package/SECURITY.md +28 -0
- package/dist/cli.cjs +670 -134
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +51 -0
- package/dist/cli.d.ts +51 -0
- package/dist/cli.js +650 -136
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +500 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -17
- package/dist/index.d.ts +21 -17
- package/dist/index.js +489 -119
- package/dist/index.js.map +1 -1
- package/package.json +30 -6
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// src/docs/jsdoc.ts
|
|
2
2
|
import { Project } from "ts-morph";
|
|
3
|
-
function loadJsDoc(
|
|
3
|
+
function loadJsDoc(filePaths) {
|
|
4
4
|
const entities = /* @__PURE__ */ new Map();
|
|
5
5
|
const props = /* @__PURE__ */ new Map();
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const classNames = /* @__PURE__ */ new Set();
|
|
7
|
+
if (filePaths.length === 0) {
|
|
8
|
+
return { entities, props, sourceFileCount: 0, classNames };
|
|
8
9
|
}
|
|
9
10
|
const project = new Project({
|
|
10
11
|
skipAddingFilesFromTsConfig: true,
|
|
@@ -14,34 +15,44 @@ function loadJsDoc(srcGlobs) {
|
|
|
14
15
|
skipLibCheck: true
|
|
15
16
|
}
|
|
16
17
|
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
for (const prop of cls.getProperties()) {
|
|
30
|
-
const propDocs = prop.getJsDocs();
|
|
31
|
-
if (propDocs.length === 0) {
|
|
18
|
+
for (const filePath of filePaths) {
|
|
19
|
+
try {
|
|
20
|
+
project.addSourceFilesAtPaths(filePath);
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const sourceFiles = project.getSourceFiles();
|
|
25
|
+
for (const sourceFile of sourceFiles) {
|
|
26
|
+
try {
|
|
27
|
+
for (const cls of sourceFile.getClasses()) {
|
|
28
|
+
const className = cls.getName();
|
|
29
|
+
if (!className) {
|
|
32
30
|
continue;
|
|
33
31
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
classNames.add(className);
|
|
33
|
+
const classDocs = cls.getJsDocs();
|
|
34
|
+
if (classDocs.length > 0) {
|
|
35
|
+
entities.set(className, parseEntityJsDoc(classDocs));
|
|
36
|
+
}
|
|
37
|
+
const propMap = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const prop of cls.getProperties()) {
|
|
39
|
+
const propDocs = prop.getJsDocs();
|
|
40
|
+
if (propDocs.length === 0) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const info = parsePropJsDoc(propDocs);
|
|
44
|
+
if (info.description !== void 0 || info.atLeastOne) {
|
|
45
|
+
propMap.set(prop.getName(), info);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (propMap.size > 0) {
|
|
49
|
+
props.set(className, propMap);
|
|
37
50
|
}
|
|
38
51
|
}
|
|
39
|
-
|
|
40
|
-
props.set(className, propMap);
|
|
41
|
-
}
|
|
52
|
+
} catch {
|
|
42
53
|
}
|
|
43
54
|
}
|
|
44
|
-
return { entities, props };
|
|
55
|
+
return { entities, props, sourceFileCount: sourceFiles.length, classNames };
|
|
45
56
|
}
|
|
46
57
|
function parseEntityJsDoc(jsDocs) {
|
|
47
58
|
const namespaces = [];
|
|
@@ -76,18 +87,26 @@ function parseEntityJsDoc(jsDocs) {
|
|
|
76
87
|
hidden
|
|
77
88
|
};
|
|
78
89
|
}
|
|
79
|
-
function
|
|
90
|
+
function parsePropJsDoc(jsDocs) {
|
|
91
|
+
let description;
|
|
92
|
+
let atLeastOne = false;
|
|
80
93
|
for (const doc of jsDocs) {
|
|
81
94
|
const desc = doc.getDescription().trim();
|
|
82
|
-
if (desc) {
|
|
83
|
-
|
|
95
|
+
if (desc && description === void 0) {
|
|
96
|
+
description = desc;
|
|
97
|
+
}
|
|
98
|
+
for (const tag of doc.getTags()) {
|
|
99
|
+
if (tag.getTagName() === "atLeastOne") {
|
|
100
|
+
atLeastOne = true;
|
|
101
|
+
}
|
|
84
102
|
}
|
|
85
103
|
}
|
|
86
|
-
return void 0;
|
|
104
|
+
return { ...description !== void 0 && { description }, atLeastOne };
|
|
87
105
|
}
|
|
88
106
|
|
|
89
107
|
// src/metadata/load.ts
|
|
90
|
-
import
|
|
108
|
+
import * as path from "path";
|
|
109
|
+
import { EntitySchema, MikroORM } from "@mikro-orm/core";
|
|
91
110
|
var MetadataLoadError = class extends Error {
|
|
92
111
|
constructor(message, cause) {
|
|
93
112
|
super(message);
|
|
@@ -95,13 +114,46 @@ var MetadataLoadError = class extends Error {
|
|
|
95
114
|
this.name = "MetadataLoadError";
|
|
96
115
|
}
|
|
97
116
|
};
|
|
117
|
+
async function closeDiscoveryResources(orm) {
|
|
118
|
+
await orm.config.getMetadataCacheAdapter()?.close?.();
|
|
119
|
+
await orm.config.getResultCacheAdapter()?.close?.();
|
|
120
|
+
}
|
|
121
|
+
function collectEntitySchemaNames(options) {
|
|
122
|
+
const configuredEntities = [...options.entities ?? [], ...options.entitiesTs ?? []];
|
|
123
|
+
const names = [];
|
|
124
|
+
for (const entity of configuredEntities) {
|
|
125
|
+
if (entity instanceof EntitySchema) {
|
|
126
|
+
names.push(entity.meta.className);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (entity !== null && typeof entity === "object" && "schema" in entity && entity.schema instanceof EntitySchema) {
|
|
130
|
+
names.push(entity.schema.meta.className);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return names;
|
|
134
|
+
}
|
|
135
|
+
function assertNoEntitySchemaEntities(options) {
|
|
136
|
+
const schemaNames = collectEntitySchemaNames(options);
|
|
137
|
+
if (schemaNames.length === 0) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
throw new MetadataLoadError(
|
|
141
|
+
`EntitySchema-defined entities are not currently supported: ${schemaNames.join(", ")}.
|
|
142
|
+
Use decorator-based @Entity() classes instead.`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
98
145
|
async function loadEntityMetadata(options) {
|
|
146
|
+
assertNoEntitySchemaEntities(options);
|
|
99
147
|
let orm;
|
|
100
148
|
try {
|
|
101
149
|
orm = await MikroORM.init({
|
|
102
150
|
...options,
|
|
103
151
|
debug: false,
|
|
104
|
-
connect: false
|
|
152
|
+
connect: false,
|
|
153
|
+
// Always disable the metadata cache for one-shot doc runs so the project
|
|
154
|
+
// is never littered with a temp/ folder, regardless of how metadataProvider
|
|
155
|
+
// was configured.
|
|
156
|
+
metadataCache: { ...options.metadataCache, enabled: false }
|
|
105
157
|
});
|
|
106
158
|
} catch (cause) {
|
|
107
159
|
throw new MetadataLoadError(
|
|
@@ -109,23 +161,80 @@ async function loadEntityMetadata(options) {
|
|
|
109
161
|
cause
|
|
110
162
|
);
|
|
111
163
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
164
|
+
try {
|
|
165
|
+
const all = Object.values(orm.getMetadata().getAll());
|
|
166
|
+
if (all.length === 0) {
|
|
167
|
+
throw new MetadataLoadError(
|
|
168
|
+
"No entities were discovered. Check that your config specifies at least one entity path or class."
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
const baseDir = orm.config.get("baseDir");
|
|
172
|
+
const sourcePaths = [...new Set(all.filter((m) => m.path).map((m) => path.resolve(baseDir, m.path)))];
|
|
173
|
+
return { metas: all, sourcePaths };
|
|
174
|
+
} finally {
|
|
175
|
+
await closeDiscoveryResources(orm);
|
|
117
176
|
}
|
|
118
|
-
return all;
|
|
119
177
|
}
|
|
120
178
|
|
|
179
|
+
// src/model/build.ts
|
|
180
|
+
import { ReferenceKind as ReferenceKind2 } from "@mikro-orm/core";
|
|
181
|
+
|
|
121
182
|
// src/render/mermaid.ts
|
|
122
183
|
import { ReferenceKind } from "@mikro-orm/core";
|
|
184
|
+
|
|
185
|
+
// src/render/escape.ts
|
|
186
|
+
var MARKDOWN_INLINE_SPECIAL_CHARS = /[\\`|*#]/g;
|
|
187
|
+
var MERMAID_IDENTIFIER_INVALID_CHARS = /[^a-zA-Z0-9_]/g;
|
|
188
|
+
function normalizeInlineText(value) {
|
|
189
|
+
return value.replace(/\r\n?/g, "\n").replace(/[\n\t]+/g, " ").replace(/\s{2,}/g, " ").trim();
|
|
190
|
+
}
|
|
191
|
+
function splitNormalizedLines(value) {
|
|
192
|
+
return value.replace(/\r\n?/g, "\n").split("\n");
|
|
193
|
+
}
|
|
194
|
+
function escapeHtmlText(value) {
|
|
195
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
196
|
+
}
|
|
197
|
+
function escapeMarkdownInline(value) {
|
|
198
|
+
return escapeHtmlText(normalizeInlineText(value)).replace(MARKDOWN_INLINE_SPECIAL_CHARS, "\\$&");
|
|
199
|
+
}
|
|
200
|
+
function escapeMarkdownTableCell(value) {
|
|
201
|
+
return splitNormalizedLines(value).map((line) => escapeMarkdownInline(line)).join("<br>");
|
|
202
|
+
}
|
|
203
|
+
function escapeMarkdownParagraph(value) {
|
|
204
|
+
return splitNormalizedLines(value).map((line) => escapeMarkdownInline(line)).join(" \n");
|
|
205
|
+
}
|
|
206
|
+
function renderMarkdownBlockQuote(value) {
|
|
207
|
+
return splitNormalizedLines(value).map((line) => `> ${escapeMarkdownInline(line)}`).join("\n");
|
|
208
|
+
}
|
|
209
|
+
function renderMarkdownInlineCode(value) {
|
|
210
|
+
const normalized = normalizeInlineText(value);
|
|
211
|
+
const backtickRuns = normalized.match(/`+/g) ?? [];
|
|
212
|
+
const longestRun = Math.max(0, ...backtickRuns.map((run) => run.length));
|
|
213
|
+
const fence = "`".repeat(longestRun + 1);
|
|
214
|
+
const needsPadding = normalized.startsWith("`") || normalized.endsWith("`");
|
|
215
|
+
const content = needsPadding ? ` ${normalized} ` : normalized;
|
|
216
|
+
return `${fence}${content}${fence}`;
|
|
217
|
+
}
|
|
218
|
+
function toMermaidIdentifier(value) {
|
|
219
|
+
const normalized = normalizeInlineText(value).replace(MERMAID_IDENTIFIER_INVALID_CHARS, "_").replace(/_+/g, "_");
|
|
220
|
+
const identifier = normalized === "" ? "_" : normalized;
|
|
221
|
+
return /^[a-zA-Z_]/.test(identifier) ? identifier : `_${identifier}`;
|
|
222
|
+
}
|
|
223
|
+
function escapeMermaidQuotedText(value) {
|
|
224
|
+
return normalizeInlineText(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
225
|
+
}
|
|
226
|
+
function toMarkdownAnchor(value) {
|
|
227
|
+
return normalizeInlineText(value).toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s+/g, "-");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/render/mermaid.ts
|
|
123
231
|
var FORMULA_DUMMY_TABLE = {
|
|
124
232
|
alias: "e0",
|
|
125
233
|
name: "",
|
|
126
234
|
qualifiedName: "",
|
|
127
235
|
toString: () => "e0"
|
|
128
236
|
};
|
|
237
|
+
var UNRESOLVED_FORMULA = "<unresolved>";
|
|
129
238
|
function buildDiagramModel(metas) {
|
|
130
239
|
const metaByClass = new Map(metas.map((m) => [m.className, m]));
|
|
131
240
|
const entities = metas.filter((meta) => !meta.pivotTable && !meta.embeddable).map((meta) => buildEntityModel(meta, metaByClass));
|
|
@@ -133,17 +242,14 @@ function buildDiagramModel(metas) {
|
|
|
133
242
|
return { entities, relations };
|
|
134
243
|
}
|
|
135
244
|
function buildEntityModel(meta, metaByClass) {
|
|
136
|
-
const isStiRoot = meta.discriminatorColumn !== void 0 && !meta.
|
|
245
|
+
const isStiRoot = meta.discriminatorColumn !== void 0 && !meta.extends;
|
|
137
246
|
const isStiChild = Boolean(meta.extends) && meta.discriminatorValue !== void 0;
|
|
138
247
|
const columns = [];
|
|
139
248
|
for (const prop of Object.values(meta.properties)) {
|
|
140
249
|
if (isStiRoot && prop.inherited === true) {
|
|
141
250
|
continue;
|
|
142
251
|
}
|
|
143
|
-
|
|
144
|
-
if (col !== null) {
|
|
145
|
-
columns.push(col);
|
|
146
|
-
}
|
|
252
|
+
columns.push(...buildColumns(prop, metaByClass, meta));
|
|
147
253
|
}
|
|
148
254
|
return {
|
|
149
255
|
className: meta.className,
|
|
@@ -153,47 +259,73 @@ function buildEntityModel(meta, metaByClass) {
|
|
|
153
259
|
isEmbeddable: meta.embeddable === true,
|
|
154
260
|
...isStiRoot && { discriminatorColumn: meta.discriminatorColumn },
|
|
155
261
|
...isStiChild && { extendsEntity: meta.extends },
|
|
262
|
+
...isStiChild && meta.discriminatorValue !== void 0 && { discriminatorValue: String(meta.discriminatorValue) },
|
|
156
263
|
constraints: buildConstraints(meta)
|
|
157
264
|
};
|
|
158
265
|
}
|
|
159
|
-
function
|
|
266
|
+
function buildColumns(prop, metaByClass, owningMeta) {
|
|
160
267
|
if (prop.kind === ReferenceKind.EMBEDDED) {
|
|
161
|
-
|
|
268
|
+
if (prop.object === true || prop.array === true) {
|
|
269
|
+
return [
|
|
270
|
+
{
|
|
271
|
+
propName: prop.name,
|
|
272
|
+
fieldName: prop.fieldNames?.[0] ?? prop.name,
|
|
273
|
+
type: "json",
|
|
274
|
+
isPrimary: false,
|
|
275
|
+
isForeignKey: false,
|
|
276
|
+
isUnique: prop.unique === true,
|
|
277
|
+
isNullable: prop.nullable === true,
|
|
278
|
+
...prop.comment !== void 0 && { comment: prop.comment },
|
|
279
|
+
embeddedIn: prop.array === true ? `${prop.type}[]` : prop.type
|
|
280
|
+
}
|
|
281
|
+
];
|
|
282
|
+
}
|
|
283
|
+
return [];
|
|
162
284
|
}
|
|
163
285
|
if (prop.kind === ReferenceKind.SCALAR) {
|
|
286
|
+
if (prop.object === true && prop.embedded !== void 0) {
|
|
287
|
+
return [];
|
|
288
|
+
}
|
|
164
289
|
const formulaExpr = prop.formula !== void 0 ? resolveFormulaExpr(prop.formula) : void 0;
|
|
165
290
|
let embeddedIn;
|
|
291
|
+
let embeddedPropName;
|
|
166
292
|
if (prop.embedded !== void 0) {
|
|
167
293
|
const parentPropName = prop.embedded[0];
|
|
168
294
|
embeddedIn = owningMeta.properties[parentPropName]?.type;
|
|
295
|
+
embeddedPropName = prop.embedded[1];
|
|
169
296
|
}
|
|
170
297
|
const isDiscriminator = owningMeta.discriminatorColumn !== void 0 && prop.name === owningMeta.discriminatorColumn;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
298
|
+
const enumItems = prop.enum === true && Array.isArray(prop.items) && prop.items.length > 0 ? prop.items.map((item) => String(item)) : void 0;
|
|
299
|
+
return [
|
|
300
|
+
{
|
|
301
|
+
propName: prop.name,
|
|
302
|
+
fieldName: prop.fieldNames?.[0] ?? prop.name,
|
|
303
|
+
// Store the original type (e.g. `varchar(255)`); the Mermaid renderer
|
|
304
|
+
// sanitizes it for diagram identifiers, while the markdown table shows
|
|
305
|
+
// it verbatim. Guard against a missing type so downstream string
|
|
306
|
+
// handling never sees undefined (matches the FK path's defaulting).
|
|
307
|
+
type: prop.type ?? "unknown",
|
|
308
|
+
isPrimary: prop.primary === true,
|
|
309
|
+
isForeignKey: false,
|
|
310
|
+
isUnique: prop.unique === true,
|
|
311
|
+
isNullable: prop.nullable === true,
|
|
312
|
+
...prop.comment !== void 0 && { comment: prop.comment },
|
|
313
|
+
...formulaExpr !== void 0 && { formula: formulaExpr },
|
|
314
|
+
...embeddedIn !== void 0 && { embeddedIn },
|
|
315
|
+
...embeddedPropName !== void 0 && { embeddedPropName },
|
|
316
|
+
...isDiscriminator && { isDiscriminator: true },
|
|
317
|
+
...enumItems !== void 0 && { enumItems }
|
|
318
|
+
}
|
|
319
|
+
];
|
|
183
320
|
}
|
|
184
321
|
if (prop.kind === ReferenceKind.MANY_TO_ONE || prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner === true) {
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
isPrimary: false,
|
|
191
|
-
isForeignKey: true,
|
|
192
|
-
isUnique: prop.unique === true,
|
|
193
|
-
isNullable: prop.nullable === true
|
|
194
|
-
};
|
|
322
|
+
const cols = buildForeignKeyColumns(prop, metaByClass);
|
|
323
|
+
if (prop.type === owningMeta.className) {
|
|
324
|
+
return cols.map((col) => ({ ...col, isSelfReference: true }));
|
|
325
|
+
}
|
|
326
|
+
return cols;
|
|
195
327
|
}
|
|
196
|
-
return
|
|
328
|
+
return [];
|
|
197
329
|
}
|
|
198
330
|
function resolveFormulaExpr(cb) {
|
|
199
331
|
try {
|
|
@@ -203,18 +335,47 @@ function resolveFormulaExpr(cb) {
|
|
|
203
335
|
get: (_target, key) => typeof key === "string" ? key : ""
|
|
204
336
|
}
|
|
205
337
|
);
|
|
206
|
-
|
|
338
|
+
const result = cb(FORMULA_DUMMY_TABLE, cols);
|
|
339
|
+
return typeof result === "string" ? result : String(result);
|
|
207
340
|
} catch {
|
|
208
|
-
return
|
|
341
|
+
return UNRESOLVED_FORMULA;
|
|
209
342
|
}
|
|
210
343
|
}
|
|
211
|
-
function
|
|
212
|
-
const
|
|
344
|
+
function buildForeignKeyColumns(prop, metaByClass) {
|
|
345
|
+
const fieldNames = prop.fieldNames && prop.fieldNames.length > 0 ? prop.fieldNames : [`${prop.name}_id`];
|
|
346
|
+
const fkTypes = resolveFkTypes(prop, metaByClass, fieldNames.length);
|
|
347
|
+
return fieldNames.map((fieldName, index) => ({
|
|
348
|
+
propName: prop.name,
|
|
349
|
+
fieldName,
|
|
350
|
+
type: fkTypes[index] ?? fkTypes[0] ?? "integer",
|
|
351
|
+
isPrimary: prop.primary === true,
|
|
352
|
+
isForeignKey: true,
|
|
353
|
+
isUnique: prop.unique === true,
|
|
354
|
+
isNullable: prop.nullable === true,
|
|
355
|
+
...prop.comment !== void 0 && { comment: prop.comment },
|
|
356
|
+
referencedEntity: prop.type
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
function resolveFkTypes(prop, metaByClass, fieldNameCount) {
|
|
360
|
+
const refMeta = metaByClass.get(prop.type);
|
|
213
361
|
if (!refMeta) {
|
|
214
|
-
return "integer";
|
|
362
|
+
return Array.from({ length: fieldNameCount }, () => "integer");
|
|
363
|
+
}
|
|
364
|
+
const primaryProps = getPrimaryProps(refMeta);
|
|
365
|
+
const referencedColumnNames = prop.referencedColumnNames ?? [];
|
|
366
|
+
return Array.from({ length: fieldNameCount }, (_value, index) => {
|
|
367
|
+
const referencedColumnName = referencedColumnNames[index];
|
|
368
|
+
const pkProp = referencedColumnName !== void 0 ? primaryProps.find((candidate) => candidate.fieldNames.includes(referencedColumnName)) : void 0;
|
|
369
|
+
return (pkProp ?? primaryProps[index] ?? primaryProps[0])?.type ?? "integer";
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
function getPrimaryProps(meta) {
|
|
373
|
+
const primaryKeys = meta.primaryKeys ?? [];
|
|
374
|
+
const orderedPrimaryProps = primaryKeys.map((key) => meta.properties[String(key)]).filter((prop) => prop !== void 0);
|
|
375
|
+
if (orderedPrimaryProps.length > 0) {
|
|
376
|
+
return orderedPrimaryProps;
|
|
215
377
|
}
|
|
216
|
-
|
|
217
|
-
return pkProp ? normalizeType(pkProp.type) : "integer";
|
|
378
|
+
return Object.values(meta.properties).filter((prop) => prop.primary === true);
|
|
218
379
|
}
|
|
219
380
|
function buildConstraints(meta) {
|
|
220
381
|
const result = [];
|
|
@@ -222,7 +383,7 @@ function buildConstraints(meta) {
|
|
|
222
383
|
const props = idx.properties;
|
|
223
384
|
result.push({
|
|
224
385
|
type: "index",
|
|
225
|
-
properties:
|
|
386
|
+
properties: resolveConstraintProperties(meta, props),
|
|
226
387
|
...idx.name !== void 0 && { name: idx.name }
|
|
227
388
|
});
|
|
228
389
|
}
|
|
@@ -230,7 +391,7 @@ function buildConstraints(meta) {
|
|
|
230
391
|
const props = uniq.properties;
|
|
231
392
|
result.push({
|
|
232
393
|
type: "unique",
|
|
233
|
-
properties:
|
|
394
|
+
properties: resolveConstraintProperties(meta, props),
|
|
234
395
|
...uniq.name !== void 0 && { name: uniq.name }
|
|
235
396
|
});
|
|
236
397
|
}
|
|
@@ -247,6 +408,19 @@ function buildConstraints(meta) {
|
|
|
247
408
|
}
|
|
248
409
|
return result;
|
|
249
410
|
}
|
|
411
|
+
function resolveConstraintProperties(meta, props) {
|
|
412
|
+
const propNames = Array.isArray(props) ? props : props !== void 0 ? [props] : [];
|
|
413
|
+
return propNames.flatMap((propName) => {
|
|
414
|
+
const prop = meta.properties[String(propName)];
|
|
415
|
+
if (prop === void 0) {
|
|
416
|
+
return [String(propName)];
|
|
417
|
+
}
|
|
418
|
+
if (prop.fieldNames !== void 0 && prop.fieldNames.length > 0) {
|
|
419
|
+
return prop.fieldNames;
|
|
420
|
+
}
|
|
421
|
+
return [prop.name];
|
|
422
|
+
});
|
|
423
|
+
}
|
|
250
424
|
function buildRelationEdges(metas) {
|
|
251
425
|
const edges = [];
|
|
252
426
|
for (const meta of metas) {
|
|
@@ -265,6 +439,9 @@ function buildRelationEdges(metas) {
|
|
|
265
439
|
function buildEdge(fromEntity, prop) {
|
|
266
440
|
const isNullable = prop.nullable === true;
|
|
267
441
|
if (prop.kind === ReferenceKind.MANY_TO_ONE) {
|
|
442
|
+
if (prop.type === fromEntity) {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
268
445
|
return {
|
|
269
446
|
fromEntity,
|
|
270
447
|
toEntity: prop.type,
|
|
@@ -296,14 +473,16 @@ function buildEdge(fromEntity, prop) {
|
|
|
296
473
|
function renderErDiagram(model) {
|
|
297
474
|
const lines = ["erDiagram"];
|
|
298
475
|
for (const entity of model.entities) {
|
|
299
|
-
lines.push(` ${entity.className} {`);
|
|
476
|
+
lines.push(` ${toMermaidIdentifier(entity.className)} {`);
|
|
300
477
|
for (const col of entity.columns) {
|
|
301
478
|
lines.push(` ${renderColumnLine(col)}`);
|
|
302
479
|
}
|
|
303
480
|
lines.push(" }");
|
|
304
481
|
}
|
|
305
482
|
for (const rel of model.relations) {
|
|
306
|
-
lines.push(
|
|
483
|
+
lines.push(
|
|
484
|
+
` ${toMermaidIdentifier(rel.fromEntity)} ${rel.fromCardinality}--${rel.toCardinality} ${toMermaidIdentifier(rel.toEntity)} : "${escapeMermaidQuotedText(rel.label)}"`
|
|
485
|
+
);
|
|
307
486
|
}
|
|
308
487
|
return lines.join("\n");
|
|
309
488
|
}
|
|
@@ -311,8 +490,6 @@ function renderColumnLine(col) {
|
|
|
311
490
|
let qualifier = "";
|
|
312
491
|
if (col.isPrimary) {
|
|
313
492
|
qualifier = " PK";
|
|
314
|
-
} else if (col.isForeignKey) {
|
|
315
|
-
qualifier = " FK";
|
|
316
493
|
} else if (col.isUnique) {
|
|
317
494
|
qualifier = " UK";
|
|
318
495
|
}
|
|
@@ -323,27 +500,38 @@ function renderColumnLine(col) {
|
|
|
323
500
|
comment = "discriminator";
|
|
324
501
|
} else if (col.embeddedIn !== void 0) {
|
|
325
502
|
comment = `[${col.embeddedIn}]`;
|
|
326
|
-
} else if (col.
|
|
327
|
-
comment =
|
|
503
|
+
} else if (col.isSelfReference) {
|
|
504
|
+
comment = "self-ref";
|
|
328
505
|
}
|
|
329
|
-
const commentStr = comment !== void 0 ? ` "${comment}"` : "";
|
|
330
|
-
return `${col.type} ${col.fieldName}${qualifier}${commentStr}`;
|
|
331
|
-
}
|
|
332
|
-
function normalizeType(type) {
|
|
333
|
-
return type.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
506
|
+
const commentStr = comment !== void 0 ? ` "${escapeMermaidQuotedText(comment)}"` : "";
|
|
507
|
+
return `${toMermaidIdentifier(col.type)} ${toMermaidIdentifier(col.fieldName)}${qualifier}${commentStr}`;
|
|
334
508
|
}
|
|
335
509
|
|
|
336
510
|
// src/model/build.ts
|
|
337
|
-
|
|
338
|
-
|
|
511
|
+
var FROM_ONE_OR_MORE = "}|";
|
|
512
|
+
var TO_ONE_OR_MORE = "|{";
|
|
513
|
+
function buildDocumentModel(metas, jsDocResult, title, description, onWarn) {
|
|
514
|
+
const { entities: diagramEntities, relations } = buildDiagramModel(metas);
|
|
515
|
+
const allRelations = applyAtLeastOne(relations, metas, jsDocResult.props, onWarn);
|
|
516
|
+
const hiddenClasses = /* @__PURE__ */ new Set();
|
|
517
|
+
for (const model of diagramEntities) {
|
|
518
|
+
if (jsDocResult.entities.get(model.className)?.hidden) {
|
|
519
|
+
hiddenClasses.add(model.className);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
339
522
|
const enrichedByClass = /* @__PURE__ */ new Map();
|
|
340
523
|
for (const model of diagramEntities) {
|
|
341
524
|
const jsDoc = jsDocResult.entities.get(model.className);
|
|
342
525
|
if (jsDoc?.hidden) {
|
|
343
526
|
continue;
|
|
344
527
|
}
|
|
345
|
-
const
|
|
346
|
-
|
|
528
|
+
const columns = model.columns.filter(
|
|
529
|
+
(col) => !(col.isForeignKey && col.referencedEntity !== void 0 && hiddenClasses.has(col.referencedEntity))
|
|
530
|
+
);
|
|
531
|
+
const visibleModel = columns.length === model.columns.length ? model : { ...model, columns };
|
|
532
|
+
const ownPropDocs = jsDocResult.props.get(model.className) ?? /* @__PURE__ */ new Map();
|
|
533
|
+
const propDocs = withEmbeddedPropDocs(ownPropDocs, visibleModel.columns, jsDocResult.props);
|
|
534
|
+
enrichedByClass.set(model.className, { model: visibleModel, jsDoc, propDocs });
|
|
347
535
|
}
|
|
348
536
|
const groupNames = /* @__PURE__ */ new Set();
|
|
349
537
|
let anyUntagged = false;
|
|
@@ -384,6 +572,65 @@ function buildDocumentModel(metas, jsDocResult, title, description) {
|
|
|
384
572
|
});
|
|
385
573
|
return { title, groups, ...description !== void 0 && { description } };
|
|
386
574
|
}
|
|
575
|
+
function withEmbeddedPropDocs(ownPropDocs, columns, allPropDocs) {
|
|
576
|
+
const merged = new Map(ownPropDocs);
|
|
577
|
+
for (const col of columns) {
|
|
578
|
+
if (merged.has(col.propName) || col.embeddedIn === void 0 || col.embeddedPropName === void 0) {
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
const info = allPropDocs.get(col.embeddedIn)?.get(col.embeddedPropName);
|
|
582
|
+
if (info) {
|
|
583
|
+
merged.set(col.propName, info);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return merged;
|
|
587
|
+
}
|
|
588
|
+
function applyAtLeastOne(relations, metas, props, onWarn) {
|
|
589
|
+
const adjusted = relations.map((edge) => ({ ...edge }));
|
|
590
|
+
const metaByClass = new Map(metas.map((m) => [m.className, m]));
|
|
591
|
+
for (const [className, propMap] of props) {
|
|
592
|
+
const meta = metaByClass.get(className);
|
|
593
|
+
if (!meta) {
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
for (const [propName, info] of propMap) {
|
|
597
|
+
if (!info.atLeastOne) {
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
const prop = meta.properties[propName];
|
|
601
|
+
if (!prop) {
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
let edge;
|
|
605
|
+
if (prop.kind === ReferenceKind2.ONE_TO_MANY && prop.mappedBy) {
|
|
606
|
+
edge = adjusted.find(
|
|
607
|
+
(e) => e.fromEntity === prop.type && e.toEntity === className && e.label === prop.mappedBy
|
|
608
|
+
);
|
|
609
|
+
if (edge) {
|
|
610
|
+
edge.fromCardinality = FROM_ONE_OR_MORE;
|
|
611
|
+
}
|
|
612
|
+
} else if (prop.kind === ReferenceKind2.MANY_TO_MANY && prop.owner === true) {
|
|
613
|
+
edge = adjusted.find((e) => e.fromEntity === className && e.toEntity === prop.type && e.label === propName);
|
|
614
|
+
if (edge) {
|
|
615
|
+
edge.toCardinality = TO_ONE_OR_MORE;
|
|
616
|
+
}
|
|
617
|
+
} else if (prop.kind === ReferenceKind2.MANY_TO_MANY && prop.mappedBy) {
|
|
618
|
+
edge = adjusted.find(
|
|
619
|
+
(e) => e.fromEntity === prop.type && e.toEntity === className && e.label === prop.mappedBy
|
|
620
|
+
);
|
|
621
|
+
if (edge) {
|
|
622
|
+
edge.fromCardinality = FROM_ONE_OR_MORE;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
if (!edge) {
|
|
626
|
+
onWarn?.(
|
|
627
|
+
`@atLeastOne on ${className}.${propName} had no effect: no matching relation edge was found. It applies only to collection relations that can be matched to a rendered edge: @OneToMany with mappedBy, or @ManyToMany on either the owning side or an inverse mappedBy side.`
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return adjusted;
|
|
633
|
+
}
|
|
387
634
|
function hasNoNamespaceTags(jsDoc) {
|
|
388
635
|
if (!jsDoc) {
|
|
389
636
|
return true;
|
|
@@ -409,19 +656,55 @@ function belongsToGroupForText(jsDoc, groupName, isDefault) {
|
|
|
409
656
|
return jsDoc.namespaces.includes(groupName) || jsDoc.describeNamespaces.includes(groupName);
|
|
410
657
|
}
|
|
411
658
|
|
|
659
|
+
// src/provider.ts
|
|
660
|
+
async function withTsMorphMetadataProvider(options, onWarn) {
|
|
661
|
+
if (options.metadataProvider !== void 0) {
|
|
662
|
+
return options;
|
|
663
|
+
}
|
|
664
|
+
try {
|
|
665
|
+
const { TsMorphMetadataProvider } = await import("@mikro-orm/reflection");
|
|
666
|
+
return { ...options, metadataProvider: TsMorphMetadataProvider };
|
|
667
|
+
} catch (err) {
|
|
668
|
+
const code = err !== null && typeof err === "object" && "code" in err ? err.code : void 0;
|
|
669
|
+
const isNotInstalled = code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND";
|
|
670
|
+
if (!isNotInstalled && onWarn) {
|
|
671
|
+
onWarn(
|
|
672
|
+
`@mikro-orm/reflection is installed but failed to load: ${err instanceof Error ? err.message : String(err)}. Ensure all @mikro-orm/* packages are installed at the same version.`
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
return options;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
412
679
|
// src/render/markdown.ts
|
|
413
680
|
function renderMarkdown(docModel) {
|
|
414
|
-
const sections = [`# ${docModel.title}`];
|
|
681
|
+
const sections = [`# ${escapeMarkdownInline(docModel.title)}`];
|
|
415
682
|
if (docModel.description) {
|
|
416
|
-
sections.push(docModel.description);
|
|
683
|
+
sections.push(escapeMarkdownParagraph(docModel.description));
|
|
684
|
+
}
|
|
685
|
+
if (docModel.groups.length > 1) {
|
|
686
|
+
sections.push(renderTableOfContents(docModel.groups));
|
|
417
687
|
}
|
|
418
688
|
for (const group of docModel.groups) {
|
|
419
689
|
sections.push(renderGroupSection(group));
|
|
420
690
|
}
|
|
421
691
|
return sections.join("\n\n");
|
|
422
692
|
}
|
|
693
|
+
function renderBulletSection(header, items, renderItem) {
|
|
694
|
+
const lines = [header, ""];
|
|
695
|
+
for (const item of items) {
|
|
696
|
+
lines.push(renderItem(item));
|
|
697
|
+
}
|
|
698
|
+
return lines.join("\n");
|
|
699
|
+
}
|
|
700
|
+
function renderTableOfContents(groups) {
|
|
701
|
+
return renderBulletSection("## Contents", groups, (group) => {
|
|
702
|
+
const label = escapeMarkdownInline(group.name).replace(/[[\]]/g, "\\$&");
|
|
703
|
+
return `- [${label}](#${toMarkdownAnchor(group.name)})`;
|
|
704
|
+
});
|
|
705
|
+
}
|
|
423
706
|
function renderGroupSection(group) {
|
|
424
|
-
const parts = [`## ${group.name}`];
|
|
707
|
+
const parts = [`## ${escapeMarkdownInline(group.name)}`];
|
|
425
708
|
if (group.erdEntities.length > 0) {
|
|
426
709
|
const diagramModel = {
|
|
427
710
|
entities: group.erdEntities.map((e) => e.model),
|
|
@@ -435,14 +718,18 @@ function renderGroupSection(group) {
|
|
|
435
718
|
return parts.join("\n\n");
|
|
436
719
|
}
|
|
437
720
|
function renderEntitySection(entity) {
|
|
438
|
-
const parts = [`### ${entity.model.className}`];
|
|
721
|
+
const parts = [`### ${escapeMarkdownInline(entity.model.className)}`];
|
|
722
|
+
parts.push(`*Table: ${renderMarkdownInlineCode(entity.model.tableName)}*`);
|
|
439
723
|
if (entity.jsDoc?.description) {
|
|
440
|
-
parts.push(
|
|
724
|
+
parts.push(renderMarkdownBlockQuote(entity.jsDoc.description));
|
|
441
725
|
}
|
|
442
726
|
if (entity.model.discriminatorColumn) {
|
|
443
|
-
parts.push(`*STI root \u2014 discriminator column:
|
|
727
|
+
parts.push(`*STI root \u2014 discriminator column: ${renderMarkdownInlineCode(entity.model.discriminatorColumn)}*`);
|
|
444
728
|
} else if (entity.model.extendsEntity) {
|
|
445
|
-
|
|
729
|
+
const discValue = entity.model.discriminatorValue !== void 0 ? `, discriminator value: ${renderMarkdownInlineCode(entity.model.discriminatorValue)}` : "";
|
|
730
|
+
parts.push(
|
|
731
|
+
`*Extends ${renderMarkdownInlineCode(entity.model.extendsEntity)} (Single Table Inheritance${discValue})*`
|
|
732
|
+
);
|
|
446
733
|
}
|
|
447
734
|
if (entity.model.columns.length > 0) {
|
|
448
735
|
parts.push(renderColumnTable(entity));
|
|
@@ -450,6 +737,10 @@ function renderEntitySection(entity) {
|
|
|
450
737
|
if (entity.model.constraints.length > 0) {
|
|
451
738
|
parts.push(renderConstraints(entity.model.constraints));
|
|
452
739
|
}
|
|
740
|
+
const computedColumns = entity.model.columns.filter((col) => col.formula !== void 0);
|
|
741
|
+
if (computedColumns.length > 0) {
|
|
742
|
+
parts.push(renderComputedColumns(computedColumns));
|
|
743
|
+
}
|
|
453
744
|
return parts.join("\n\n");
|
|
454
745
|
}
|
|
455
746
|
function renderColumnTable(entity) {
|
|
@@ -458,24 +749,27 @@ function renderColumnTable(entity) {
|
|
|
458
749
|
const rows = entity.model.columns.map((col) => {
|
|
459
750
|
const key = resolveColumnKey(col);
|
|
460
751
|
const nullable = col.isNullable && !col.isPrimary ? "Y" : "";
|
|
461
|
-
const
|
|
462
|
-
|
|
752
|
+
const docDesc = entity.propDocs.get(col.propName)?.description ?? col.comment ?? "";
|
|
753
|
+
const enumDesc = col.enumItems !== void 0 ? `One of: ${col.enumItems.join(", ")}` : "";
|
|
754
|
+
const desc = [docDesc, enumDesc].filter((part) => part !== "").join("\n");
|
|
755
|
+
return `| ${escapeMarkdownTableCell(col.fieldName)} | ${escapeMarkdownTableCell(col.type)} | ${escapeMarkdownTableCell(key)} | ${nullable} | ${escapeMarkdownTableCell(desc)} |`;
|
|
463
756
|
});
|
|
464
757
|
return [header, sep, ...rows].join("\n");
|
|
465
758
|
}
|
|
466
759
|
function resolveColumnKey(col) {
|
|
760
|
+
const fkKey = col.fieldName !== col.propName ? `FK (${col.propName})` : "FK";
|
|
761
|
+
if (col.isPrimary && col.isForeignKey) {
|
|
762
|
+
return `PK, ${fkKey}`;
|
|
763
|
+
}
|
|
467
764
|
if (col.isPrimary) {
|
|
468
765
|
return "PK";
|
|
469
766
|
}
|
|
470
767
|
if (col.isForeignKey) {
|
|
471
|
-
return
|
|
768
|
+
return fkKey;
|
|
472
769
|
}
|
|
473
770
|
if (col.isUnique) {
|
|
474
771
|
return "UK";
|
|
475
772
|
}
|
|
476
|
-
if (col.formula !== void 0) {
|
|
477
|
-
return `formula: ${col.formula}`;
|
|
478
|
-
}
|
|
479
773
|
if (col.isDiscriminator) {
|
|
480
774
|
return "discriminator";
|
|
481
775
|
}
|
|
@@ -484,31 +778,107 @@ function resolveColumnKey(col) {
|
|
|
484
778
|
}
|
|
485
779
|
return "";
|
|
486
780
|
}
|
|
781
|
+
function renderComputedColumns(columns) {
|
|
782
|
+
return renderBulletSection("**Computed columns:**", columns, (col) => {
|
|
783
|
+
const expr = col.formula ? `: ${renderMarkdownInlineCode(col.formula)}` : "";
|
|
784
|
+
return `- ${renderMarkdownInlineCode(col.fieldName)}${expr}`;
|
|
785
|
+
});
|
|
786
|
+
}
|
|
487
787
|
function renderConstraints(constraints) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const
|
|
788
|
+
return renderBulletSection("**Constraints:**", constraints, (c) => {
|
|
789
|
+
const name = c.name ? ` ${renderMarkdownInlineCode(c.name)}` : "";
|
|
790
|
+
const properties = c.properties.map(escapeMarkdownInline).join(", ");
|
|
491
791
|
if (c.type === "index") {
|
|
492
|
-
|
|
493
|
-
} else if (c.type === "unique") {
|
|
494
|
-
lines.push(`- Unique${name}: (${c.properties.join(", ")})`);
|
|
495
|
-
} else if (c.type === "check") {
|
|
496
|
-
lines.push(`- Check${name}: \`${c.expression ?? ""}\``);
|
|
792
|
+
return `- Index${name}: (${properties})`;
|
|
497
793
|
}
|
|
498
|
-
|
|
499
|
-
|
|
794
|
+
if (c.type === "unique") {
|
|
795
|
+
return `- Unique${name}: (${properties})`;
|
|
796
|
+
}
|
|
797
|
+
return `- Check${name}: ${renderMarkdownInlineCode(c.expression ?? "")}`;
|
|
798
|
+
});
|
|
500
799
|
}
|
|
501
800
|
|
|
502
801
|
// src/index.ts
|
|
802
|
+
var COMPILED_JS = /\.(c|m)?js$/i;
|
|
803
|
+
function resolveJsDocSources(sourcePaths, src, onWarn) {
|
|
804
|
+
if (src !== void 0 && src.length > 0) {
|
|
805
|
+
return src;
|
|
806
|
+
}
|
|
807
|
+
if (sourcePaths.some((p) => COMPILED_JS.test(p)) && onWarn) {
|
|
808
|
+
onWarn(
|
|
809
|
+
'Entities were discovered from compiled JavaScript, so JSDoc descriptions and @namespace/@hidden tags cannot be read (build tools strip comments). Hidden entities may be exposed. Pass --src "<glob to your .ts sources>" (or the `src` option) to read JSDoc from the original TypeScript files.'
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
return sourcePaths;
|
|
813
|
+
}
|
|
814
|
+
function assertExplicitJsDocSourceCoverage(metas, jsDocResult, src, onWarn) {
|
|
815
|
+
if (jsDocResult.sourceFileCount === 0) {
|
|
816
|
+
throw new Error(
|
|
817
|
+
`No source files matched the explicit src paths: ${src.join(", ")}
|
|
818
|
+
Check the --src glob/path (or the \`src\` option). Without matching TypeScript sources, JSDoc tags such as @namespace and @hidden cannot be read.`
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
const isRenderable = (meta) => !meta.pivotTable && !meta.embeddable;
|
|
822
|
+
const missingConcrete = metas.filter((meta) => isRenderable(meta) && !meta.abstract).map((meta) => meta.className).filter((className) => !jsDocResult.classNames.has(className));
|
|
823
|
+
if (missingConcrete.length > 0) {
|
|
824
|
+
throw new Error(
|
|
825
|
+
`Explicit src paths did not include source declarations for discovered entities: ${missingConcrete.join(", ")}
|
|
826
|
+
Check that --src (or the \`src\` option) points at all TypeScript entity files. JSDoc tags such as @namespace and @hidden for missing entities cannot be read.`
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
if (onWarn) {
|
|
830
|
+
const missingAbstract = metas.filter((meta) => isRenderable(meta) && meta.abstract).map((meta) => meta.className).filter((className) => !jsDocResult.classNames.has(className));
|
|
831
|
+
if (missingAbstract.length > 0) {
|
|
832
|
+
onWarn(
|
|
833
|
+
`Abstract STI parent entities were not found in the explicit src paths: ${missingAbstract.join(", ")}
|
|
834
|
+
@hidden and @namespace tags for these entities will not be applied. Include their source files in --src to enable JSDoc tags for them.`
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
function errorMessages(err) {
|
|
840
|
+
const messages = [];
|
|
841
|
+
const seen = /* @__PURE__ */ new Set();
|
|
842
|
+
let current = err;
|
|
843
|
+
while (current instanceof Error && !seen.has(current)) {
|
|
844
|
+
seen.add(current);
|
|
845
|
+
messages.push(current.message);
|
|
846
|
+
current = current.cause;
|
|
847
|
+
}
|
|
848
|
+
return messages;
|
|
849
|
+
}
|
|
850
|
+
function isMissingTsMorphSourceFile(err) {
|
|
851
|
+
return errorMessages(err).some((message) => message.includes("Source file") && message.includes("not found"));
|
|
852
|
+
}
|
|
853
|
+
async function loadEntityMetadataWithTsMorphFallback(originalOrm, effectiveOrm) {
|
|
854
|
+
try {
|
|
855
|
+
return await loadEntityMetadata(effectiveOrm);
|
|
856
|
+
} catch (err) {
|
|
857
|
+
const wasAutoInjected = originalOrm.metadataProvider === void 0 && effectiveOrm.metadataProvider !== void 0;
|
|
858
|
+
if (!wasAutoInjected || !isMissingTsMorphSourceFile(err)) {
|
|
859
|
+
throw err;
|
|
860
|
+
}
|
|
861
|
+
try {
|
|
862
|
+
return await loadEntityMetadata(originalOrm);
|
|
863
|
+
} catch {
|
|
864
|
+
throw err;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
503
868
|
async function generateMarkdown(options) {
|
|
504
|
-
const { orm, title = "Database Schema", description, src
|
|
505
|
-
const
|
|
506
|
-
const
|
|
507
|
-
const
|
|
869
|
+
const { orm, title = "Database Schema", description, src, onWarn } = options;
|
|
870
|
+
const effectiveOrm = await withTsMorphMetadataProvider(orm, onWarn);
|
|
871
|
+
const { metas, sourcePaths } = await loadEntityMetadataWithTsMorphFallback(orm, effectiveOrm);
|
|
872
|
+
const jsDocResult = loadJsDoc(resolveJsDocSources(sourcePaths, src, onWarn));
|
|
873
|
+
if (src !== void 0 && src.length > 0) {
|
|
874
|
+
assertExplicitJsDocSourceCoverage(metas, jsDocResult, src, onWarn);
|
|
875
|
+
}
|
|
876
|
+
const docModel = buildDocumentModel(metas, jsDocResult, title, description, onWarn);
|
|
508
877
|
return renderMarkdown(docModel);
|
|
509
878
|
}
|
|
510
879
|
export {
|
|
511
880
|
MetadataLoadError,
|
|
512
|
-
generateMarkdown
|
|
881
|
+
generateMarkdown,
|
|
882
|
+
resolveJsDocSources
|
|
513
883
|
};
|
|
514
884
|
//# sourceMappingURL=index.js.map
|