mikro-orm-markdown 0.1.0-alpha.4 → 0.1.0
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 +18 -0
- package/README.ko.md +88 -1
- package/README.md +91 -1
- package/dist/cli.cjs +88 -18
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +88 -18
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +59 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +59 -17
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.0] - 2026-06-30
|
|
9
|
+
|
|
10
|
+
First stable release. All alpha features are considered production-ready.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `AGENTS.md` with project overview, source layout, development commands, and conventions for AI agent context
|
|
15
|
+
- Planned Features section in README (en/ko) documenting `--check` mode, `--watch` mode, and `EntitySchema` support as upcoming work
|
|
16
|
+
|
|
17
|
+
## [0.1.0-alpha.5] - 2026-06-29
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `--mermaid-layout <layout>` and `--mermaid-theme <theme>` CLI options to inject Mermaid YAML frontmatter into each `erDiagram` fence
|
|
22
|
+
- `mermaid` option in the programmatic API (`generateMarkdown({ mermaid: { layout, theme } })`) with the same effect
|
|
23
|
+
- `MermaidLayout`, `MermaidTheme`, and `MermaidRenderOptions` types exported from the public API
|
|
24
|
+
- When neither option is set, output is identical to previous versions — no frontmatter is emitted
|
|
25
|
+
|
|
8
26
|
## [0.1.0-alpha.4] - 2026-06-29
|
|
9
27
|
|
|
10
28
|
### Fixed
|
package/README.ko.md
CHANGED
|
@@ -79,6 +79,8 @@ npm run erd
|
|
|
79
79
|
| `-d, --description <string>` | — | 제목 아래에 표시할 설명 문단 (선택) |
|
|
80
80
|
| `--tsconfig <path>` | — | `.ts` config 로드 시 사용할 `tsconfig.json`; 기본값은 config 파일 근처의 가장 가까운 파일 |
|
|
81
81
|
| `--src <paths...>` | — | 원본 TypeScript 엔티티 소스 경로/glob; MikroORM이 컴파일된 JavaScript에서 엔티티를 discovery할 때만 필요 |
|
|
82
|
+
| `--mermaid-layout <layout>` | — | Mermaid 레이아웃 엔진 (`dagre\|elk\|elk.stress`). 생략하면 뷰어 기본값 사용. |
|
|
83
|
+
| `--mermaid-theme <theme>` | — | Mermaid 테마 (`default\|neutral\|dark\|forest\|base`). 생략하면 뷰어 기본값 사용. |
|
|
82
84
|
|
|
83
85
|
> 설명이 길거나 여러 줄이라면 CLI 대신 [프로그래밍 API](#프로그래밍-api)를 사용하세요 — 쉘 인용 부호 제약 없이 문자열을 그대로 전달할 수 있습니다.
|
|
84
86
|
|
|
@@ -214,7 +216,7 @@ erDiagram
|
|
|
214
216
|
Post {
|
|
215
217
|
integer id PK
|
|
216
218
|
string title
|
|
217
|
-
|
|
219
|
+
string body
|
|
218
220
|
integer author_id FK
|
|
219
221
|
}
|
|
220
222
|
Author {
|
|
@@ -392,6 +394,7 @@ await writeFile('./ERD.md', markdown, 'utf-8');
|
|
|
392
394
|
| `description` | 제목 아래에 표시할 설명 문단입니다. CLI flag와 달리 쉘 quoting 제약 없이 문자열을 그대로 전달할 수 있습니다. |
|
|
393
395
|
| `src` | 원본 TypeScript 엔티티 소스 경로/glob입니다. `orm.entities`가 컴파일된 JavaScript를 discovery할 때만 필요합니다. |
|
|
394
396
|
| `onWarn` | 컴파일된 JavaScript에서 JSDoc을 읽지 못하는 상황 같은 non-fatal warning을 받을 callback입니다. |
|
|
397
|
+
| `mermaid` | Mermaid 렌더링 옵션입니다. 아래 [Mermaid 렌더링 옵션](#mermaid-렌더링-옵션)을 참고하세요. |
|
|
395
398
|
|
|
396
399
|
MikroORM config를 비동기적으로 만들어야 한다면 직접 resolve한 뒤 결과 options object를 전달하세요:
|
|
397
400
|
|
|
@@ -400,6 +403,90 @@ const ormConfig = await createOrmConfig();
|
|
|
400
403
|
const markdown = await generateMarkdown({ orm: ormConfig });
|
|
401
404
|
```
|
|
402
405
|
|
|
406
|
+
### Mermaid 렌더링 옵션
|
|
407
|
+
|
|
408
|
+
기본적으로 mikro-orm-markdown은 Mermaid frontmatter config를 출력하지 않습니다. 이렇게 해야 각 Markdown 뷰어의 기본 Mermaid 렌더링 동작이 유지됩니다.
|
|
409
|
+
|
|
410
|
+
CLI에서 Mermaid 렌더링 옵션을 사용하려면:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --mermaid-layout elk
|
|
414
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --mermaid-theme forest
|
|
415
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --mermaid-layout elk --mermaid-theme neutral
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
프로그래밍 API에서는:
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
const markdown = await generateMarkdown({
|
|
422
|
+
orm: ormConfig,
|
|
423
|
+
mermaid: {
|
|
424
|
+
layout: 'elk',
|
|
425
|
+
theme: 'forest',
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
layout 또는 theme을 지정하면 각 `erDiagram` 펜스 앞에 YAML frontmatter 블록이 삽입됩니다:
|
|
431
|
+
|
|
432
|
+
````markdown
|
|
433
|
+
```mermaid
|
|
434
|
+
---
|
|
435
|
+
config:
|
|
436
|
+
layout: elk
|
|
437
|
+
theme: forest
|
|
438
|
+
---
|
|
439
|
+
erDiagram
|
|
440
|
+
...
|
|
441
|
+
```
|
|
442
|
+
````
|
|
443
|
+
|
|
444
|
+
**사용 가능한 layout 값:**
|
|
445
|
+
|
|
446
|
+
| 값 | 설명 |
|
|
447
|
+
| -- | ---- |
|
|
448
|
+
| `dagre` | Mermaid 기본 레이아웃 엔진. |
|
|
449
|
+
| `elk` | 대체 레이아웃 엔진. 엔티티가 많거나 관계선이 복잡한 ERD에서 선 라우팅을 개선할 수 있습니다. |
|
|
450
|
+
| `elk.stress` | ELK stress 레이아웃 변형. Mermaid 버전과 뷰어에 따라 지원 여부가 다릅니다. |
|
|
451
|
+
|
|
452
|
+
**사용 가능한 theme 값:** `default`, `neutral`, `dark`, `forest`, `base`.
|
|
453
|
+
|
|
454
|
+
> `elk`와 theme 지원 여부는 뷰어마다 다릅니다. `--mermaid-layout`이나 `--mermaid-theme`을 지정하지 않으면 frontmatter는 출력되지 않습니다.
|
|
455
|
+
|
|
456
|
+
## 추후 구현 예정 기능
|
|
457
|
+
|
|
458
|
+
다음 기능들은 향후 릴리즈에서 지원할 예정입니다.
|
|
459
|
+
|
|
460
|
+
### `--check` 모드
|
|
461
|
+
|
|
462
|
+
출력 파일이 현재 엔티티 메타데이터와 다를 경우 non-zero 코드로 종료하는 `--check` 플래그입니다. 파일을 직접 수정하지 않으며, CI 파이프라인에서 `ERD.md`가 엔티티 변경 사항과 함께 항상 커밋되었는지 검증하는 용도로 사용합니다.
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --check
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### `--watch` 모드
|
|
469
|
+
|
|
470
|
+
엔티티 소스 파일을 감지하여 변경이 발생할 때마다 출력 문서를 자동으로 재생성하는 `--watch` 플래그입니다. CLI를 매번 수동으로 실행하지 않아도 ERD를 최신 상태로 유지할 수 있어 개발 중에 유용합니다.
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --watch
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### `EntitySchema` 지원
|
|
477
|
+
|
|
478
|
+
현재는 decorator 기반 엔티티(`@Entity()` 클래스)만 지원합니다. 향후 릴리즈에서는 TypeScript decorator 없이 Plain Object로 스키마를 정의하는 [`EntitySchema`](https://mikro-orm.io/docs/entity-schema) 방식도 지원할 예정입니다.
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
const PostSchema = new EntitySchema({
|
|
482
|
+
name: 'Post',
|
|
483
|
+
properties: {
|
|
484
|
+
id: { primary: true, type: 'integer' },
|
|
485
|
+
title: { type: 'string' },
|
|
486
|
+
},
|
|
487
|
+
});
|
|
488
|
+
```
|
|
489
|
+
|
|
403
490
|
## 라이선스
|
|
404
491
|
|
|
405
492
|
MIT
|
package/README.md
CHANGED
|
@@ -79,6 +79,8 @@ npm run erd
|
|
|
79
79
|
| `-d, --description <string>` | — | Optional description paragraph shown below the title |
|
|
80
80
|
| `--tsconfig <path>` | — | `tsconfig.json` used when loading a `.ts` config; defaults to the nearest one beside the config file |
|
|
81
81
|
| `--src <paths...>` | — | Original TypeScript entity source paths/globs; only needed when MikroORM discovers entities from compiled JavaScript |
|
|
82
|
+
| `--mermaid-layout <layout>` | — | Mermaid layout engine (`dagre\|elk\|elk.stress`). Omit to use the viewer's default. |
|
|
83
|
+
| `--mermaid-theme <theme>` | — | Mermaid theme (`default\|neutral\|dark\|forest\|base`). Omit to use the viewer's default. |
|
|
82
84
|
|
|
83
85
|
> For a long or multiline description, use the [programmatic API](#programmatic-api) instead — it accepts any string directly, without shell quoting limits.
|
|
84
86
|
|
|
@@ -214,7 +216,7 @@ erDiagram
|
|
|
214
216
|
Post {
|
|
215
217
|
integer id PK
|
|
216
218
|
string title
|
|
217
|
-
|
|
219
|
+
string body
|
|
218
220
|
integer author_id FK
|
|
219
221
|
}
|
|
220
222
|
Author {
|
|
@@ -392,6 +394,7 @@ Programmatic options:
|
|
|
392
394
|
| `description` | Optional paragraph below the title. Unlike the CLI flag, this can be any string without shell quoting concerns. |
|
|
393
395
|
| `src` | Original TypeScript entity source paths/globs. Only needed when `orm.entities` discovers compiled JavaScript. |
|
|
394
396
|
| `onWarn` | Callback for non-fatal warnings, such as compiled JavaScript JSDoc loss. |
|
|
397
|
+
| `mermaid` | Optional Mermaid rendering options. See [Mermaid rendering options](#mermaid-rendering-options) below. |
|
|
395
398
|
|
|
396
399
|
If your MikroORM config is asynchronous, resolve it yourself and pass the resulting options object:
|
|
397
400
|
|
|
@@ -400,6 +403,93 @@ const ormConfig = await createOrmConfig();
|
|
|
400
403
|
const markdown = await generateMarkdown({ orm: ormConfig });
|
|
401
404
|
```
|
|
402
405
|
|
|
406
|
+
### Mermaid rendering options
|
|
407
|
+
|
|
408
|
+
By default, mikro-orm-markdown does not emit Mermaid frontmatter config. This preserves each Markdown viewer's default Mermaid rendering behavior.
|
|
409
|
+
|
|
410
|
+
You can opt into Mermaid rendering options via the CLI:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --mermaid-layout elk
|
|
414
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --mermaid-theme forest
|
|
415
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --mermaid-layout elk --mermaid-theme neutral
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
Or via the programmatic API:
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
const markdown = await generateMarkdown({
|
|
422
|
+
orm: ormConfig,
|
|
423
|
+
mermaid: {
|
|
424
|
+
layout: 'elk',
|
|
425
|
+
theme: 'forest',
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
When a layout or theme is set, a YAML frontmatter block is prepended to each `erDiagram` fence:
|
|
431
|
+
|
|
432
|
+
````markdown
|
|
433
|
+
```mermaid
|
|
434
|
+
---
|
|
435
|
+
config:
|
|
436
|
+
layout: elk
|
|
437
|
+
theme: forest
|
|
438
|
+
---
|
|
439
|
+
erDiagram
|
|
440
|
+
...
|
|
441
|
+
```
|
|
442
|
+
````
|
|
443
|
+
|
|
444
|
+
**Available layout values:**
|
|
445
|
+
|
|
446
|
+
| Value | Description |
|
|
447
|
+
| ----- | ----------- |
|
|
448
|
+
| `dagre` | Mermaid's default layered layout. |
|
|
449
|
+
| `elk` | Alternative layout engine; can improve line routing on larger or denser ERDs. |
|
|
450
|
+
| `elk.stress` | ELK stress layout variant. Support varies by Mermaid version and viewer. |
|
|
451
|
+
|
|
452
|
+
**Available theme values:** `default`, `neutral`, `dark`, `forest`, `base`.
|
|
453
|
+
|
|
454
|
+
> Viewer support for `elk` and theme values varies. If no `--mermaid-layout` or `--mermaid-theme` is provided, no frontmatter is emitted.
|
|
455
|
+
|
|
456
|
+
## Planned Features
|
|
457
|
+
|
|
458
|
+
The following features are planned for future releases.
|
|
459
|
+
|
|
460
|
+
### `--check` mode
|
|
461
|
+
|
|
462
|
+
A `--check` flag that exits with a non-zero code when the output file is out of sync with the current entity metadata — without writing any files.
|
|
463
|
+
Intended for CI pipelines to enforce that `ERD.md` is always committed alongside entity changes.
|
|
464
|
+
|
|
465
|
+
```bash
|
|
466
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --check
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### `--watch` mode
|
|
470
|
+
|
|
471
|
+
A `--watch` flag that monitors entity source files and regenerates the output document automatically on each change.
|
|
472
|
+
Useful during active development when you want the ERD to stay current without running the CLI manually.
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
mikro-orm-markdown --config ./mikro-orm.config.ts --watch
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### `EntitySchema` support
|
|
479
|
+
|
|
480
|
+
Currently only decorator-based entities (`@Entity()` classes) are supported.
|
|
481
|
+
A future release will add support for [`EntitySchema`](https://mikro-orm.io/docs/entity-schema)-defined entities, which describe the schema as a plain object without TypeScript decorators.
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
const PostSchema = new EntitySchema({
|
|
485
|
+
name: 'Post',
|
|
486
|
+
properties: {
|
|
487
|
+
id: { primary: true, type: 'integer' },
|
|
488
|
+
title: { type: 'string' },
|
|
489
|
+
},
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
403
493
|
## License
|
|
404
494
|
|
|
405
495
|
MIT
|
package/dist/cli.cjs
CHANGED
|
@@ -53,7 +53,7 @@ var import_commander = require("commander");
|
|
|
53
53
|
|
|
54
54
|
// src/docs/jsdoc.ts
|
|
55
55
|
var import_ts_morph = require("ts-morph");
|
|
56
|
-
function loadJsDoc(filePaths) {
|
|
56
|
+
function loadJsDoc(filePaths, onWarn) {
|
|
57
57
|
const entities = /* @__PURE__ */ new Map();
|
|
58
58
|
const props = /* @__PURE__ */ new Map();
|
|
59
59
|
const classNames = /* @__PURE__ */ new Set();
|
|
@@ -70,8 +70,12 @@ function loadJsDoc(filePaths) {
|
|
|
70
70
|
});
|
|
71
71
|
for (const filePath of filePaths) {
|
|
72
72
|
try {
|
|
73
|
-
project.addSourceFilesAtPaths(filePath);
|
|
74
|
-
|
|
73
|
+
const sourceFiles2 = project.addSourceFilesAtPaths(filePath);
|
|
74
|
+
if (sourceFiles2.length === 0 && !hasGlobPattern(filePath)) {
|
|
75
|
+
onWarn?.(`No JSDoc source file matched path: ${filePath}`);
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
onWarn?.(`Could not load JSDoc source path "${filePath}": ${formatUnknownError(err)}`);
|
|
75
79
|
}
|
|
76
80
|
}
|
|
77
81
|
const sourceFiles = project.getSourceFiles();
|
|
@@ -102,11 +106,18 @@ function loadJsDoc(filePaths) {
|
|
|
102
106
|
props.set(className, propMap);
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
|
-
} catch {
|
|
109
|
+
} catch (err) {
|
|
110
|
+
onWarn?.(`Could not parse JSDoc source file "${sourceFile.getFilePath()}": ${formatUnknownError(err)}`);
|
|
106
111
|
}
|
|
107
112
|
}
|
|
108
113
|
return { entities, props, sourceFileCount: sourceFiles.length, classNames };
|
|
109
114
|
}
|
|
115
|
+
function formatUnknownError(err) {
|
|
116
|
+
return err instanceof Error ? err.message : String(err);
|
|
117
|
+
}
|
|
118
|
+
function hasGlobPattern(filePath) {
|
|
119
|
+
return /[*?[\]{}]/.test(filePath);
|
|
120
|
+
}
|
|
110
121
|
function parseEntityJsDoc(jsDocs) {
|
|
111
122
|
const namespaces = [];
|
|
112
123
|
const erdNamespaces = [];
|
|
@@ -281,6 +292,8 @@ function toMarkdownAnchor(value) {
|
|
|
281
292
|
}
|
|
282
293
|
|
|
283
294
|
// src/render/mermaid.ts
|
|
295
|
+
var MERMAID_LAYOUTS = ["dagre", "elk", "elk.stress"];
|
|
296
|
+
var MERMAID_THEMES = ["default", "neutral", "dark", "forest", "base"];
|
|
284
297
|
var FORMULA_DUMMY_TABLE = {
|
|
285
298
|
alias: "e0",
|
|
286
299
|
name: "",
|
|
@@ -567,8 +580,19 @@ function normalizeType(type) {
|
|
|
567
580
|
}
|
|
568
581
|
return type;
|
|
569
582
|
}
|
|
570
|
-
function renderErDiagram(model) {
|
|
571
|
-
const lines = [
|
|
583
|
+
function renderErDiagram(model, mermaid) {
|
|
584
|
+
const lines = [];
|
|
585
|
+
if (mermaid?.layout !== void 0 || mermaid?.theme !== void 0) {
|
|
586
|
+
lines.push("---", "config:");
|
|
587
|
+
if (mermaid.layout !== void 0) {
|
|
588
|
+
lines.push(` layout: ${mermaid.layout}`);
|
|
589
|
+
}
|
|
590
|
+
if (mermaid.theme !== void 0) {
|
|
591
|
+
lines.push(` theme: ${mermaid.theme}`);
|
|
592
|
+
}
|
|
593
|
+
lines.push("---");
|
|
594
|
+
}
|
|
595
|
+
lines.push("erDiagram");
|
|
572
596
|
for (const entity of model.entities) {
|
|
573
597
|
lines.push(` ${toMermaidIdentifier(entity.className)} {`);
|
|
574
598
|
for (const col of entity.columns) {
|
|
@@ -763,7 +787,8 @@ function isCrossNamespaceInGroup(jsDoc, groupName, isDefault) {
|
|
|
763
787
|
if (isDefault || !jsDoc) {
|
|
764
788
|
return false;
|
|
765
789
|
}
|
|
766
|
-
|
|
790
|
+
const hasHomeNamespace = jsDoc.namespaces.length > 0 || jsDoc.describeNamespaces.length > 0;
|
|
791
|
+
return hasHomeNamespace && jsDoc.erdNamespaces.includes(groupName) && !jsDoc.namespaces.includes(groupName) && !jsDoc.describeNamespaces.includes(groupName);
|
|
767
792
|
}
|
|
768
793
|
|
|
769
794
|
// src/provider.ts
|
|
@@ -787,16 +812,16 @@ async function withTsMorphMetadataProvider(options, onWarn) {
|
|
|
787
812
|
}
|
|
788
813
|
|
|
789
814
|
// src/render/markdown.ts
|
|
790
|
-
function renderMarkdown(docModel) {
|
|
815
|
+
function renderMarkdown(docModel, mermaid) {
|
|
791
816
|
const sections = [`# ${escapeMarkdownInline(docModel.title)}`];
|
|
792
817
|
if (docModel.description) {
|
|
793
818
|
sections.push(escapeMarkdownParagraph(docModel.description));
|
|
794
819
|
}
|
|
795
820
|
if (docModel.groups.length > 1) {
|
|
796
|
-
sections.push(renderTableOfContents(docModel.groups));
|
|
821
|
+
sections.push(renderTableOfContents(docModel.groups, resolveGroupAnchors(docModel)));
|
|
797
822
|
}
|
|
798
823
|
for (const group of docModel.groups) {
|
|
799
|
-
sections.push(renderGroupSection(group));
|
|
824
|
+
sections.push(renderGroupSection(group, mermaid));
|
|
800
825
|
}
|
|
801
826
|
return sections.join("\n\n");
|
|
802
827
|
}
|
|
@@ -807,20 +832,39 @@ function renderBulletSection(header, items, renderItem) {
|
|
|
807
832
|
}
|
|
808
833
|
return lines.join("\n");
|
|
809
834
|
}
|
|
810
|
-
function renderTableOfContents(groups) {
|
|
835
|
+
function renderTableOfContents(groups, anchors) {
|
|
811
836
|
return renderBulletSection("## Contents", groups, (group) => {
|
|
812
837
|
const label = escapeMarkdownInline(group.name).replace(/[[\]]/g, "\\$&");
|
|
813
|
-
return `- [${label}](#${toMarkdownAnchor(group.name)})`;
|
|
838
|
+
return `- [${label}](#${anchors.get(group) ?? toMarkdownAnchor(group.name)})`;
|
|
814
839
|
});
|
|
815
840
|
}
|
|
816
|
-
function
|
|
841
|
+
function resolveGroupAnchors(docModel) {
|
|
842
|
+
const seenAnchors = /* @__PURE__ */ new Map();
|
|
843
|
+
const groupAnchors = /* @__PURE__ */ new Map();
|
|
844
|
+
resolveHeadingAnchor(docModel.title, seenAnchors);
|
|
845
|
+
resolveHeadingAnchor("Contents", seenAnchors);
|
|
846
|
+
for (const group of docModel.groups) {
|
|
847
|
+
groupAnchors.set(group, resolveHeadingAnchor(group.name, seenAnchors));
|
|
848
|
+
for (const entity of group.textEntities) {
|
|
849
|
+
resolveHeadingAnchor(entity.model.className, seenAnchors);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
return groupAnchors;
|
|
853
|
+
}
|
|
854
|
+
function resolveHeadingAnchor(value, seenAnchors) {
|
|
855
|
+
const baseAnchor = toMarkdownAnchor(value);
|
|
856
|
+
const previousCount = seenAnchors.get(baseAnchor) ?? 0;
|
|
857
|
+
seenAnchors.set(baseAnchor, previousCount + 1);
|
|
858
|
+
return previousCount === 0 ? baseAnchor : `${baseAnchor}-${previousCount}`;
|
|
859
|
+
}
|
|
860
|
+
function renderGroupSection(group, mermaid) {
|
|
817
861
|
const parts = [`## ${escapeMarkdownInline(group.name)}`];
|
|
818
862
|
if (group.erdEntities.length > 0) {
|
|
819
863
|
const diagramModel = {
|
|
820
864
|
entities: group.erdEntities.map((e) => e.model),
|
|
821
865
|
relations: group.erdRelations
|
|
822
866
|
};
|
|
823
|
-
parts.push("```mermaid\n" + renderErDiagram(diagramModel) + "\n```");
|
|
867
|
+
parts.push("```mermaid\n" + renderErDiagram(diagramModel, mermaid) + "\n```");
|
|
824
868
|
}
|
|
825
869
|
for (const entity of group.textEntities) {
|
|
826
870
|
parts.push(renderEntitySection(entity));
|
|
@@ -976,15 +1020,15 @@ async function loadEntityMetadataWithTsMorphFallback(originalOrm, effectiveOrm)
|
|
|
976
1020
|
}
|
|
977
1021
|
}
|
|
978
1022
|
async function generateMarkdown(options) {
|
|
979
|
-
const { orm, title = "Database Schema", description, src, onWarn } = options;
|
|
1023
|
+
const { orm, title = "Database Schema", description, src, onWarn, mermaid } = options;
|
|
980
1024
|
const effectiveOrm = await withTsMorphMetadataProvider(orm, onWarn);
|
|
981
1025
|
const { metas, sourcePaths } = await loadEntityMetadataWithTsMorphFallback(orm, effectiveOrm);
|
|
982
|
-
const jsDocResult = loadJsDoc(resolveJsDocSources(sourcePaths, src, onWarn));
|
|
1026
|
+
const jsDocResult = loadJsDoc(resolveJsDocSources(sourcePaths, src, onWarn), onWarn);
|
|
983
1027
|
if (src !== void 0 && src.length > 0) {
|
|
984
1028
|
assertExplicitJsDocSourceCoverage(metas, jsDocResult, src, onWarn);
|
|
985
1029
|
}
|
|
986
1030
|
const docModel = buildDocumentModel(metas, jsDocResult, title, description, onWarn);
|
|
987
|
-
return renderMarkdown(docModel);
|
|
1031
|
+
return renderMarkdown(docModel, mermaid);
|
|
988
1032
|
}
|
|
989
1033
|
|
|
990
1034
|
// src/cli.ts
|
|
@@ -1099,9 +1143,34 @@ async function writeMarkdownFile(outPath, markdown) {
|
|
|
1099
1143
|
${formatFileSystemError(cause)}`, { cause });
|
|
1100
1144
|
}
|
|
1101
1145
|
}
|
|
1146
|
+
function parseMermaidOptions(opts) {
|
|
1147
|
+
const { mermaidLayout, mermaidTheme } = opts;
|
|
1148
|
+
if (mermaidLayout !== void 0 && !MERMAID_LAYOUTS.includes(mermaidLayout)) {
|
|
1149
|
+
process.stderr.write(
|
|
1150
|
+
`Error: Invalid --mermaid-layout "${mermaidLayout}". Allowed values: ${MERMAID_LAYOUTS.join(", ")}
|
|
1151
|
+
`
|
|
1152
|
+
);
|
|
1153
|
+
process.exit(1);
|
|
1154
|
+
}
|
|
1155
|
+
if (mermaidTheme !== void 0 && !MERMAID_THEMES.includes(mermaidTheme)) {
|
|
1156
|
+
process.stderr.write(
|
|
1157
|
+
`Error: Invalid --mermaid-theme "${mermaidTheme}". Allowed values: ${MERMAID_THEMES.join(", ")}
|
|
1158
|
+
`
|
|
1159
|
+
);
|
|
1160
|
+
process.exit(1);
|
|
1161
|
+
}
|
|
1162
|
+
if (mermaidLayout === void 0 && mermaidTheme === void 0) {
|
|
1163
|
+
return void 0;
|
|
1164
|
+
}
|
|
1165
|
+
return {
|
|
1166
|
+
...mermaidLayout !== void 0 && { layout: mermaidLayout },
|
|
1167
|
+
...mermaidTheme !== void 0 && { theme: mermaidTheme }
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1102
1170
|
async function run(opts) {
|
|
1103
1171
|
const configPath = path2.resolve(opts.config);
|
|
1104
1172
|
const outPath = path2.resolve(opts.out);
|
|
1173
|
+
const mermaid = parseMermaidOptions(opts);
|
|
1105
1174
|
let ormOptions;
|
|
1106
1175
|
try {
|
|
1107
1176
|
ormOptions = await loadOrmOptions(configPath, opts.tsconfig);
|
|
@@ -1120,6 +1189,7 @@ ${err instanceof Error ? err.message : String(err)}
|
|
|
1120
1189
|
title: opts.title,
|
|
1121
1190
|
...opts.description !== void 0 && { description: opts.description },
|
|
1122
1191
|
...opts.src !== void 0 && { src: opts.src },
|
|
1192
|
+
...mermaid !== void 0 && { mermaid },
|
|
1123
1193
|
onWarn: (message) => void process.stderr.write(`Warning: ${message}
|
|
1124
1194
|
`)
|
|
1125
1195
|
});
|
|
@@ -1144,7 +1214,7 @@ var program = new import_commander.Command().name("mikro-orm-markdown").descript
|
|
|
1144
1214
|
).option(
|
|
1145
1215
|
"--src <paths...>",
|
|
1146
1216
|
"Source .ts file globs to read JSDoc from when entities run from compiled .js (comments are stripped at build time)"
|
|
1147
|
-
).action(run);
|
|
1217
|
+
).option("--mermaid-layout <layout>", `Mermaid layout engine injected as frontmatter (${MERMAID_LAYOUTS.join("|")})`).option("--mermaid-theme <theme>", `Mermaid theme injected as frontmatter (${MERMAID_THEMES.join("|")})`).action(run);
|
|
1148
1218
|
function isDirectCliExecution() {
|
|
1149
1219
|
const entryPoint = process.argv[1];
|
|
1150
1220
|
if (entryPoint === void 0) {
|