mikro-orm-markdown 0.1.0-alpha.1 → 0.1.0-alpha.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/README.ko.md CHANGED
@@ -15,15 +15,19 @@ MikroORM에서도 동일한 ERD + Markdown 경험을 제공하며, Prisma로는
15
15
  - **Embeddable** — 별도 테이블 없이 소유 엔티티의 테이블 안에 컬럼을 펼쳐서 저장하는 값 객체입니다. 예를 들어 `Address` 값 객체는 `address_street`, `address_city` 등의 컬럼으로 저장됩니다. DDD의 Value Object와 같은 개념입니다.
16
16
  - **Single Table Inheritance (STI)** — `Dog`, `Cat` 같은 자식 클래스가 `animals` 테이블 하나를 공유합니다. `type` 같은 discriminator 컬럼으로 어떤 자식 클래스인지 구분합니다.
17
17
  - **@Formula** — 실제 DB 컬럼 없이 SELECT 시 SQL 식으로 값을 계산하는 가상 컬럼입니다. 예를 들어 `LENGTH(name)`은 DB에 컬럼이 없지만 조회 시 이름의 길이를 반환합니다.
18
+
19
+ > 이 기능들은 MikroORM에서 완전히 지원하지만 실무에서는 자주 쓰이지 않을 수 있습니다. 특히 Embeddable은 MikroORM Entity를 Domain Entity로 함께 사용하는 구조에서 주로 활용되며, ORM 레이어와 도메인 모델을 분리해서 관리한다면 사용할 일이 거의 없습니다.
20
+
18
21
  - NamingStrategy가 적용된 **실제 DB 컬럼명**
19
22
  - **인덱스 및 제약 조건**
20
23
 
21
- DB에 연결하지 않으므로 MikroORM 지원하는 모든 DB(PostgreSQL, MySQL, SQLite, MSSQL 등)에서 동작합니다.
24
+ PostgreSQL, MySQL/MariaDB, SQLite, MSSQL 같은 MikroORM SQL 드라이버에서 동작합니다. 기존 DB 스키마를 직접 introspection하지 않고 MikroORM 설정에서 엔티티 메타데이터를 읽기 때문에 실행 중인 DB 연결이 필요하지 않습니다.
22
25
 
23
26
  ## 요구사항
24
27
 
25
28
  - Node.js >= 18
26
29
  - `@mikro-orm/core` >= 6 (peer dependency)
30
+ - 사용할 DB에 맞는 MikroORM 드라이버 패키지가 설치된 MikroORM 설정 파일
27
31
  - TypeScript 설정 파일 사용 시 `tsx` 또는 `ts-node` 필요
28
32
 
29
33
  ## 설치
@@ -64,12 +68,12 @@ npm run erd
64
68
 
65
69
  ## CLI 옵션
66
70
 
67
- | 옵션 | 기본값 | 설명 |
68
- |------|--------|------|
69
- | `-c, --config <path>` | *(필수)* | MikroORM 설정 파일 경로 |
70
- | `-o, --out <path>` | `./ERD.md` | 출력 Markdown 파일 경로 |
71
- | `-t, --title <string>` | `Database Schema` | 문서 H1 제목 |
72
- | `-s, --src <glob>` | — | 엔티티 소스 파일 glob 패턴 (반복 가능). JSDoc 태그 추출에 사용됩니다. |
71
+ | 옵션 | 기본값 | 설명 |
72
+ | ---------------------- | ----------------- | --------------------------------------------------------------------- |
73
+ | `-c, --config <path>` | _(필수)_ | MikroORM 설정 파일 경로 |
74
+ | `-o, --out <path>` | `./ERD.md` | 출력 Markdown 파일 경로 |
75
+ | `-t, --title <string>` | `Database Schema` | 문서 H1 제목 |
76
+ | `-s, --src <glob>` | — | 엔티티 소스 파일 glob 패턴 (반복 가능). JSDoc 태그 추출에 사용됩니다. |
73
77
 
74
78
  ## JSDoc 태그
75
79
 
@@ -88,12 +92,12 @@ export class Post {
88
92
  }
89
93
  ```
90
94
 
91
- | 태그 | 설명 |
92
- |------|------|
93
- | `@namespace <Name>` | `Name` 섹션에 포함 (ERD + 본문 표) |
94
- | `@erd <Name>` | `Name` 섹션의 ERD 다이어그램에만 포함 |
95
- | `@describe <Name>` | `Name` 섹션의 본문 표에만 포함 |
96
- | `@hidden` | 문서 전체에서 제외 |
95
+ | 태그 | 설명 |
96
+ | ------------------- | ------------------------------------- |
97
+ | `@namespace <Name>` | `Name` 섹션에 포함 (ERD + 본문 표) |
98
+ | `@erd <Name>` | `Name` 섹션의 ERD 다이어그램에만 포함 |
99
+ | `@describe <Name>` | `Name` 섹션의 본문 표에만 포함 |
100
+ | `@hidden` | 문서 전체에서 제외 |
97
101
 
98
102
  태그가 없는 엔티티는 `default` 섹션에 들어갑니다.
99
103
  하나의 엔티티에 여러 태그를 지정할 수 있습니다.
@@ -127,21 +131,21 @@ erDiagram
127
131
 
128
132
  > 등록된 사용자가 작성한 블로그 게시글입니다.
129
133
 
130
- | Column | Type | Key | Nullable | Description |
131
- |--------|------|-----|----------|-------------|
132
- | id | integer | PK | | |
133
- | title | string | | | 게시글 제목 |
134
- | body | text | | Y | |
135
- | author_id | integer | FK (author) | | |
134
+ | Column | Type | Key | Nullable | Description |
135
+ | --------- | ------- | ----------- | -------- | ----------- |
136
+ | id | integer | PK | | |
137
+ | title | string | | | 게시글 제목 |
138
+ | body | text | | Y | |
139
+ | author_id | integer | FK (author) | | |
136
140
  ````
137
141
 
138
142
  **Key 컬럼 주석 의미:**
139
143
 
140
- | 표기 | 의미 |
141
- |------|------|
142
- | `formula: <expr>` | `@Formula` 계산 컬럼 — 실제 DB 컬럼 없음 |
144
+ | 표기 | 의미 |
145
+ | ------------------ | -------------------------------------------- |
146
+ | `formula: <expr>` | `@Formula` 계산 컬럼 — 실제 DB 컬럼 없음 |
143
147
  | `[EmbeddableType]` | `@Embedded` 값 객체에서 flat으로 저장된 컬럼 |
144
- | `discriminator` | STI 구분자 컬럼 |
148
+ | `discriminator` | STI 구분자 컬럼 |
145
149
 
146
150
  ## 참고 사항
147
151
 
package/README.md CHANGED
@@ -15,15 +15,19 @@ This tool brings the same ERD + Markdown experience to MikroORM, with additional
15
15
  - **Embeddable** — a value object whose fields are stored as flat columns inside the owning entity's table (e.g. `address_street`, `address_city`). No separate table is created.
16
16
  - **Single Table Inheritance (STI)** — subclasses like `Dog` and `Cat` share one `animals` table. A discriminator column (e.g. `type`) distinguishes which subclass each row belongs to.
17
17
  - **@Formula** — a virtual column with no physical DB column. Its value is computed by a SQL expression at SELECT time (e.g. `LENGTH(name)`).
18
+
19
+ > These features are fully supported by MikroORM but are less commonly used in practice. In particular, Embeddable is most relevant when MikroORM entities double as domain objects — if you separate your ORM layer from your domain model, you likely won't need it.
20
+
18
21
  - **Actual DB column names** derived from your NamingStrategy
19
22
  - **Indexes and constraints**
20
23
 
21
- Works with all databases supported by MikroORM (PostgreSQL, MySQL, SQLite, MSSQL, and more) no database connection required.
24
+ Works with MikroORM SQL drivers such as PostgreSQL, MySQL/MariaDB, SQLite, and MSSQL. It reads entity metadata from your MikroORM config, so no live database connection is required.
22
25
 
23
26
  ## Requirements
24
27
 
25
28
  - Node.js >= 18
26
29
  - `@mikro-orm/core` >= 6 (peer dependency)
30
+ - A MikroORM config with the matching database driver package installed
27
31
  - TypeScript config files require `tsx` or `ts-node`
28
32
 
29
33
  ## Installation
@@ -64,12 +68,12 @@ npm run erd
64
68
 
65
69
  ## CLI Options
66
70
 
67
- | Option | Default | Description |
68
- |--------|---------|-------------|
69
- | `-c, --config <path>` | *(required)* | Path to MikroORM config file |
70
- | `-o, --out <path>` | `./ERD.md` | Output Markdown file path |
71
- | `-t, --title <string>` | `Database Schema` | H1 heading of the generated document |
72
- | `-s, --src <glob>` | — | Glob pattern for entity source files (repeatable). Enables JSDoc tag extraction. |
71
+ | Option | Default | Description |
72
+ | ---------------------- | ----------------- | -------------------------------------------------------------------------------- |
73
+ | `-c, --config <path>` | _(required)_ | Path to MikroORM config file |
74
+ | `-o, --out <path>` | `./ERD.md` | Output Markdown file path |
75
+ | `-t, --title <string>` | `Database Schema` | H1 heading of the generated document |
76
+ | `-s, --src <glob>` | — | Glob pattern for entity source files (repeatable). Enables JSDoc tag extraction. |
73
77
 
74
78
  ## JSDoc Tags
75
79
 
@@ -88,12 +92,12 @@ export class Post {
88
92
  }
89
93
  ```
90
94
 
91
- | Tag | Description |
92
- |-----|-------------|
95
+ | Tag | Description |
96
+ | ------------------- | --------------------------------------------------- |
93
97
  | `@namespace <Name>` | Include entity in section `Name` (ERD + text table) |
94
- | `@erd <Name>` | Include in section `Name`'s ERD diagram only |
95
- | `@describe <Name>` | Include in section `Name`'s text table only |
96
- | `@hidden` | Exclude entity from the entire document |
98
+ | `@erd <Name>` | Include in section `Name`'s ERD diagram only |
99
+ | `@describe <Name>` | Include in section `Name`'s text table only |
100
+ | `@hidden` | Exclude entity from the entire document |
97
101
 
98
102
  Entities with no tag are placed in the `default` section.
99
103
  An entity can carry multiple tags to appear in more than one section.
@@ -127,21 +131,21 @@ erDiagram
127
131
 
128
132
  > Blog post authored by a registered user.
129
133
 
130
- | Column | Type | Key | Nullable | Description |
131
- |--------|------|-----|----------|-------------|
132
- | id | integer | PK | | |
133
- | title | string | | | Post title |
134
- | body | text | | Y | |
135
- | author_id | integer | FK (author) | | |
134
+ | Column | Type | Key | Nullable | Description |
135
+ | --------- | ------- | ----------- | -------- | ----------- |
136
+ | id | integer | PK | | |
137
+ | title | string | | | Post title |
138
+ | body | text | | Y | |
139
+ | author_id | integer | FK (author) | | |
136
140
  ````
137
141
 
138
142
  MikroORM-specific annotations in the **Key** column:
139
143
 
140
- | Annotation | Meaning |
141
- |------------|---------|
142
- | `formula: <expr>` | `@Formula` computed column — no physical DB column |
144
+ | Annotation | Meaning |
145
+ | ------------------ | ---------------------------------------------------- |
146
+ | `formula: <expr>` | `@Formula` computed column — no physical DB column |
143
147
  | `[EmbeddableType]` | Flat column inlined from an `@Embedded` value object |
144
- | `discriminator` | STI discriminator column |
148
+ | `discriminator` | STI discriminator column |
145
149
 
146
150
  ## Notes
147
151
 
package/dist/cli.cjs CHANGED
@@ -33,7 +33,9 @@ var import_ts_morph = require("ts-morph");
33
33
  function loadJsDoc(srcGlobs) {
34
34
  const entities = /* @__PURE__ */ new Map();
35
35
  const props = /* @__PURE__ */ new Map();
36
- if (srcGlobs.length === 0) return { entities, props };
36
+ if (srcGlobs.length === 0) {
37
+ return { entities, props };
38
+ }
37
39
  const project = new import_ts_morph.Project({
38
40
  skipAddingFilesFromTsConfig: true,
39
41
  skipLoadingLibFiles: true,
@@ -46,7 +48,9 @@ function loadJsDoc(srcGlobs) {
46
48
  for (const sourceFile of project.getSourceFiles()) {
47
49
  for (const cls of sourceFile.getClasses()) {
48
50
  const className = cls.getName();
49
- if (!className) continue;
51
+ if (!className) {
52
+ continue;
53
+ }
50
54
  const classDocs = cls.getJsDocs();
51
55
  if (classDocs.length > 0) {
52
56
  entities.set(className, parseEntityJsDoc(classDocs));
@@ -54,7 +58,9 @@ function loadJsDoc(srcGlobs) {
54
58
  const propMap = /* @__PURE__ */ new Map();
55
59
  for (const prop of cls.getProperties()) {
56
60
  const propDocs = prop.getJsDocs();
57
- if (propDocs.length === 0) continue;
61
+ if (propDocs.length === 0) {
62
+ continue;
63
+ }
58
64
  const desc = extractDescription(propDocs);
59
65
  if (desc !== void 0) {
60
66
  propMap.set(prop.getName(), { description: desc });
@@ -75,14 +81,21 @@ function parseEntityJsDoc(jsDocs) {
75
81
  let description;
76
82
  for (const doc of jsDocs) {
77
83
  const desc = doc.getDescription().trim();
78
- if (desc && description === void 0) description = desc;
84
+ if (desc && description === void 0) {
85
+ description = desc;
86
+ }
79
87
  for (const tag of doc.getTags()) {
80
88
  const tagName = tag.getTagName();
81
89
  const comment = tag.getCommentText()?.trim();
82
- if (tagName === "namespace" && comment) namespaces.push(comment);
83
- else if (tagName === "erd" && comment) erdNamespaces.push(comment);
84
- else if (tagName === "describe" && comment) describeNamespaces.push(comment);
85
- else if (tagName === "hidden") hidden = true;
90
+ if (tagName === "namespace" && comment) {
91
+ namespaces.push(comment);
92
+ } else if (tagName === "erd" && comment) {
93
+ erdNamespaces.push(comment);
94
+ } else if (tagName === "describe" && comment) {
95
+ describeNamespaces.push(comment);
96
+ } else if (tagName === "hidden") {
97
+ hidden = true;
98
+ }
86
99
  }
87
100
  }
88
101
  return {
@@ -96,7 +109,9 @@ function parseEntityJsDoc(jsDocs) {
96
109
  function extractDescription(jsDocs) {
97
110
  for (const doc of jsDocs) {
98
111
  const desc = doc.getDescription().trim();
99
- if (desc) return desc;
112
+ if (desc) {
113
+ return desc;
114
+ }
100
115
  }
101
116
  return void 0;
102
117
  }
@@ -115,7 +130,8 @@ async function loadEntityMetadata(options) {
115
130
  try {
116
131
  orm = await import_core.MikroORM.init({
117
132
  ...options,
118
- debug: false
133
+ debug: false,
134
+ connect: false
119
135
  });
120
136
  } catch (cause) {
121
137
  throw new MetadataLoadError(
@@ -123,17 +139,13 @@ async function loadEntityMetadata(options) {
123
139
  cause
124
140
  );
125
141
  }
126
- try {
127
- const all = Object.values(orm.getMetadata().getAll());
128
- if (all.length === 0) {
129
- throw new MetadataLoadError(
130
- "No entities were discovered. Check that your config specifies at least one entity path or class."
131
- );
132
- }
133
- return all;
134
- } finally {
135
- await orm.close(true);
142
+ const all = Object.values(orm.getMetadata().getAll());
143
+ if (all.length === 0) {
144
+ throw new MetadataLoadError(
145
+ "No entities were discovered. Check that your config specifies at least one entity path or class."
146
+ );
136
147
  }
148
+ return all;
137
149
  }
138
150
 
139
151
  // src/render/mermaid.ts
@@ -155,9 +167,13 @@ function buildEntityModel(meta, metaByClass) {
155
167
  const isStiChild = Boolean(meta.extends) && meta.discriminatorValue !== void 0;
156
168
  const columns = [];
157
169
  for (const prop of Object.values(meta.properties)) {
158
- if (isStiRoot && prop.inherited === true) continue;
170
+ if (isStiRoot && prop.inherited === true) {
171
+ continue;
172
+ }
159
173
  const col = buildColumn(prop, metaByClass, meta);
160
- if (col !== null) columns.push(col);
174
+ if (col !== null) {
175
+ columns.push(col);
176
+ }
161
177
  }
162
178
  return {
163
179
  className: meta.className,
@@ -171,7 +187,9 @@ function buildEntityModel(meta, metaByClass) {
171
187
  };
172
188
  }
173
189
  function buildColumn(prop, metaByClass, owningMeta) {
174
- if (prop.kind === import_core2.ReferenceKind.EMBEDDED) return null;
190
+ if (prop.kind === import_core2.ReferenceKind.EMBEDDED) {
191
+ return null;
192
+ }
175
193
  if (prop.kind === import_core2.ReferenceKind.SCALAR) {
176
194
  const formulaExpr = prop.formula !== void 0 ? resolveFormulaExpr(prop.formula) : void 0;
177
195
  let embeddedIn;
@@ -209,9 +227,12 @@ function buildColumn(prop, metaByClass, owningMeta) {
209
227
  }
210
228
  function resolveFormulaExpr(cb) {
211
229
  try {
212
- const cols = new Proxy({}, {
213
- get: (_target, key) => typeof key === "string" ? key : ""
214
- });
230
+ const cols = new Proxy(
231
+ {},
232
+ {
233
+ get: (_target, key) => typeof key === "string" ? key : ""
234
+ }
235
+ );
215
236
  return cb(FORMULA_DUMMY_TABLE, cols);
216
237
  } catch {
217
238
  return "";
@@ -219,7 +240,9 @@ function resolveFormulaExpr(cb) {
219
240
  }
220
241
  function resolveFkType(referencedClassName, metaByClass) {
221
242
  const refMeta = metaByClass.get(referencedClassName);
222
- if (!refMeta) return "integer";
243
+ if (!refMeta) {
244
+ return "integer";
245
+ }
223
246
  const pkProp = Object.values(refMeta.properties).find((p) => p.primary === true);
224
247
  return pkProp ? normalizeType(pkProp.type) : "integer";
225
248
  }
@@ -242,7 +265,9 @@ function buildConstraints(meta) {
242
265
  });
243
266
  }
244
267
  for (const check of meta.checks ?? []) {
245
- if (typeof check.expression !== "string") continue;
268
+ if (typeof check.expression !== "string") {
269
+ continue;
270
+ }
246
271
  result.push({
247
272
  type: "check",
248
273
  properties: [],
@@ -255,10 +280,14 @@ function buildConstraints(meta) {
255
280
  function buildRelationEdges(metas) {
256
281
  const edges = [];
257
282
  for (const meta of metas) {
258
- if (meta.pivotTable || meta.embeddable) continue;
283
+ if (meta.pivotTable || meta.embeddable) {
284
+ continue;
285
+ }
259
286
  for (const prop of Object.values(meta.properties)) {
260
287
  const edge = buildEdge(meta.className, prop);
261
- if (edge !== null) edges.push(edge);
288
+ if (edge !== null) {
289
+ edges.push(edge);
290
+ }
262
291
  }
263
292
  }
264
293
  return edges;
@@ -304,17 +333,19 @@ function renderErDiagram(model) {
304
333
  lines.push(" }");
305
334
  }
306
335
  for (const rel of model.relations) {
307
- lines.push(
308
- ` ${rel.fromEntity} ${rel.fromCardinality}--${rel.toCardinality} ${rel.toEntity} : "${rel.label}"`
309
- );
336
+ lines.push(` ${rel.fromEntity} ${rel.fromCardinality}--${rel.toCardinality} ${rel.toEntity} : "${rel.label}"`);
310
337
  }
311
338
  return lines.join("\n");
312
339
  }
313
340
  function renderColumnLine(col) {
314
341
  let qualifier = "";
315
- if (col.isPrimary) qualifier = " PK";
316
- else if (col.isForeignKey) qualifier = " FK";
317
- else if (col.isUnique) qualifier = " UK";
342
+ if (col.isPrimary) {
343
+ qualifier = " PK";
344
+ } else if (col.isForeignKey) {
345
+ qualifier = " FK";
346
+ } else if (col.isUnique) {
347
+ qualifier = " UK";
348
+ }
318
349
  let comment;
319
350
  if (col.formula !== void 0) {
320
351
  comment = col.formula ? `formula: ${col.formula}` : "formula";
@@ -338,25 +369,27 @@ function buildDocumentModel(metas, jsDocResult, title, description) {
338
369
  const enrichedByClass = /* @__PURE__ */ new Map();
339
370
  for (const model of diagramEntities) {
340
371
  const jsDoc = jsDocResult.entities.get(model.className);
341
- if (jsDoc?.hidden) continue;
372
+ if (jsDoc?.hidden) {
373
+ continue;
374
+ }
342
375
  const propDocs = jsDocResult.props.get(model.className) ?? /* @__PURE__ */ new Map();
343
376
  enrichedByClass.set(model.className, { model, jsDoc, propDocs });
344
377
  }
345
378
  const groupNames = /* @__PURE__ */ new Set();
346
379
  let anyUntagged = false;
347
380
  for (const { jsDoc } of enrichedByClass.values()) {
348
- const allNs = [
349
- ...jsDoc?.namespaces ?? [],
350
- ...jsDoc?.erdNamespaces ?? [],
351
- ...jsDoc?.describeNamespaces ?? []
352
- ];
381
+ const allNs = [...jsDoc?.namespaces ?? [], ...jsDoc?.erdNamespaces ?? [], ...jsDoc?.describeNamespaces ?? []];
353
382
  if (allNs.length === 0) {
354
383
  anyUntagged = true;
355
384
  } else {
356
- for (const ns of allNs) groupNames.add(ns);
385
+ for (const ns of allNs) {
386
+ groupNames.add(ns);
387
+ }
357
388
  }
358
389
  }
359
- if (anyUntagged) groupNames.add("default");
390
+ if (anyUntagged) {
391
+ groupNames.add("default");
392
+ }
360
393
  const groups = [];
361
394
  for (const groupName of groupNames) {
362
395
  const isDefault = groupName === "default";
@@ -367,30 +400,42 @@ function buildDocumentModel(metas, jsDocResult, title, description) {
367
400
  ({ jsDoc }) => belongsToGroupForText(jsDoc, groupName, isDefault)
368
401
  );
369
402
  const erdClassNames = new Set(erdEntities.map((e) => e.model.className));
370
- const erdRelations = allRelations.filter(
371
- (r) => erdClassNames.has(r.fromEntity) && erdClassNames.has(r.toEntity)
372
- );
403
+ const erdRelations = allRelations.filter((r) => erdClassNames.has(r.fromEntity) && erdClassNames.has(r.toEntity));
373
404
  groups.push({ name: groupName, erdEntities, textEntities, erdRelations });
374
405
  }
375
406
  groups.sort((a, b) => {
376
- if (a.name === "default") return 1;
377
- if (b.name === "default") return -1;
407
+ if (a.name === "default") {
408
+ return 1;
409
+ }
410
+ if (b.name === "default") {
411
+ return -1;
412
+ }
378
413
  return a.name.localeCompare(b.name);
379
414
  });
380
415
  return { title, groups, ...description !== void 0 && { description } };
381
416
  }
382
417
  function hasNoNamespaceTags(jsDoc) {
383
- if (!jsDoc) return true;
418
+ if (!jsDoc) {
419
+ return true;
420
+ }
384
421
  return jsDoc.namespaces.length === 0 && jsDoc.erdNamespaces.length === 0 && jsDoc.describeNamespaces.length === 0;
385
422
  }
386
423
  function belongsToGroupForErd(jsDoc, groupName, isDefault) {
387
- if (isDefault) return hasNoNamespaceTags(jsDoc);
388
- if (!jsDoc) return false;
424
+ if (isDefault) {
425
+ return hasNoNamespaceTags(jsDoc);
426
+ }
427
+ if (!jsDoc) {
428
+ return false;
429
+ }
389
430
  return jsDoc.namespaces.includes(groupName) || jsDoc.erdNamespaces.includes(groupName);
390
431
  }
391
432
  function belongsToGroupForText(jsDoc, groupName, isDefault) {
392
- if (isDefault) return hasNoNamespaceTags(jsDoc);
393
- if (!jsDoc) return false;
433
+ if (isDefault) {
434
+ return hasNoNamespaceTags(jsDoc);
435
+ }
436
+ if (!jsDoc) {
437
+ return false;
438
+ }
394
439
  return jsDoc.namespaces.includes(groupName) || jsDoc.describeNamespaces.includes(groupName);
395
440
  }
396
441
 
@@ -425,9 +470,7 @@ function renderEntitySection(entity) {
425
470
  parts.push(`> ${entity.jsDoc.description}`);
426
471
  }
427
472
  if (entity.model.discriminatorColumn) {
428
- parts.push(
429
- `*STI root \u2014 discriminator column: \`${entity.model.discriminatorColumn}\`*`
430
- );
473
+ parts.push(`*STI root \u2014 discriminator column: \`${entity.model.discriminatorColumn}\`*`);
431
474
  } else if (entity.model.extendsEntity) {
432
475
  parts.push(`*Extends \`${entity.model.extendsEntity}\` (Single Table Inheritance)*`);
433
476
  }
@@ -451,14 +494,24 @@ function renderColumnTable(entity) {
451
494
  return [header, sep, ...rows].join("\n");
452
495
  }
453
496
  function resolveColumnKey(col) {
454
- if (col.isPrimary) return "PK";
497
+ if (col.isPrimary) {
498
+ return "PK";
499
+ }
455
500
  if (col.isForeignKey) {
456
501
  return col.fieldName !== col.propName ? `FK (${col.propName})` : "FK";
457
502
  }
458
- if (col.isUnique) return "UK";
459
- if (col.formula !== void 0) return `formula: ${col.formula}`;
460
- if (col.isDiscriminator) return "discriminator";
461
- if (col.embeddedIn !== void 0) return `[${col.embeddedIn}]`;
503
+ if (col.isUnique) {
504
+ return "UK";
505
+ }
506
+ if (col.formula !== void 0) {
507
+ return `formula: ${col.formula}`;
508
+ }
509
+ if (col.isDiscriminator) {
510
+ return "discriminator";
511
+ }
512
+ if (col.embeddedIn !== void 0) {
513
+ return `[${col.embeddedIn}]`;
514
+ }
462
515
  return "";
463
516
  }
464
517
  function renderConstraints(constraints) {
@@ -507,7 +560,7 @@ ${err instanceof Error ? err.message : String(err)}${hint}
507
560
  markdown = await generateMarkdown({
508
561
  orm: ormOptions,
509
562
  title: opts.title,
510
- src: opts.src,
563
+ src: opts.src ?? [],
511
564
  ...opts.description !== void 0 && { description: opts.description }
512
565
  });
513
566
  } catch (err) {
@@ -520,12 +573,7 @@ ${err instanceof Error ? err.message : String(err)}${hint}
520
573
  process.stdout.write(`\u2713 Written to ${path.relative(process.cwd(), outPath)}
521
574
  `);
522
575
  }
523
- var program = new import_commander.Command().name("mikro-orm-markdown").description("Generate Mermaid ERD + markdown docs from MikroORM entities").requiredOption("-c, --config <path>", "MikroORM config file path").option("-o, --out <path>", "Output markdown file path", "./ERD.md").option("-t, --title <string>", "Document title", "Database Schema").option("-d, --description <string>", "Optional description paragraph shown below the title").option(
524
- "-s, --src <glob>",
525
- "Glob pattern for entity source files, repeatable (for JSDoc extraction)",
526
- (val, prev) => [...prev, val],
527
- []
528
- ).action(run);
576
+ var program = new import_commander.Command().name("mikro-orm-markdown").description("Generate Mermaid ERD + markdown docs from MikroORM entities").requiredOption("-c, --config <path>", "MikroORM config file path").option("-o, --out <path>", "Output markdown file path", "./ERD.md").option("-t, --title <string>", "Document title", "Database Schema").option("-d, --description <string>", "Optional description paragraph shown below the title").option("-s, --src <glob>", "JSDoc source glob (repeatable)", (val, prev = []) => [...prev, val]).action(run);
529
577
  program.parseAsync(process.argv).catch((err) => {
530
578
  process.stderr.write(`${err instanceof Error ? err.message : String(err)}
531
579
  `);