mikro-orm-markdown 0.1.0-alpha.2 → 0.1.0-alpha.4

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 CHANGED
@@ -5,6 +5,72 @@ 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-alpha.4] - 2026-06-29
9
+
10
+ ### Fixed
11
+
12
+ - `resolveScalarType` now preserves composite primary-key column alignment through FK-as-PK chains
13
+ - `resolveScalarType` now falls back to `integer` after depth 5 instead of leaking an entity class name
14
+ - Cross-namespace ERD filtering now treats `@describe` as a home namespace when checking `@erd` guests
15
+ - Cross-namespace ERD guest entities with no visible primary-key columns are excluded instead of rendering empty boxes
16
+
17
+ ### Changed
18
+
19
+ - Markdown tables and Mermaid ERDs now render database-specific scalar types as generic, database-agnostic types
20
+
21
+ ## [0.1.0-alpha.3] - 2026-06-29
22
+
23
+ ### Added
24
+
25
+ - `--tsconfig <path>` CLI option to override the tsconfig used when loading a `.ts` config
26
+ - `--src <paths...>` CLI option and `src` programmatic option to read JSDoc from the original `.ts` sources when entities run from compiled JavaScript
27
+ - Actual DB table name shown under each entity heading (`*Table: \`name\`*`)
28
+ - `@Enum` allowed values listed in the column description (`One of: ...`)
29
+ - STI child discriminator value shown in the Extends note
30
+ - End-to-end smoke test running the built CLI from the repo root (plus a CI step)
31
+ - Type-omitted properties (e.g. `@Property() name: string`) are now documented: when the config picks no metadata provider and `@mikro-orm/reflection` is installed, both the CLI and the programmatic API auto-use `TsMorphMetadataProvider` to read types from your TypeScript sources
32
+ - `.ts` configs default to `preferTs: true`, so MikroORM discovers your `entitiesTs` sources without extra config
33
+ - `npm pack` smoke test (`test:pack`) that installs the built tarball into a temporary project
34
+ - Metadata discovery smoke tests for SQLite, PostgreSQL, MySQL, and MariaDB drivers
35
+
36
+ ### Fixed
37
+
38
+ - Auto-applying `TsMorphMetadataProvider` no longer breaks explicit-type runtime/JavaScript entity configs when TypeScript source files are unavailable; generation falls back to MikroORM's default provider if the auto provider cannot find source files and the original config can still discover metadata
39
+ - `.ts` config loading no longer depends on the current working directory — the tsconfig beside the config file is resolved and passed to `tsx`
40
+ - Discovery failures now surface the underlying cause (missing driver, bad entities glob, …) instead of only a generic message
41
+ - Parameterized SQL types (e.g. `varchar(255)`) are preserved in the markdown table instead of being sanitized
42
+ - Non-abstract STI roots are classified correctly, no longer leaking subclass columns
43
+ - `object: true` / `array: true` embeddeds render as a single JSON column
44
+ - Non-string `@Formula` return values no longer crash rendering
45
+ - `loadJsDoc` never throws on an unreadable source file
46
+ - A warning is emitted when `@atLeastOne` cannot be matched to a relation edge
47
+ - FK columns referencing a `@hidden` entity are dropped instead of dangling
48
+ - Guarded against missing `prop.type` / `prop.fieldNames` during rendering
49
+ - Discovery failures from missing decorator metadata now explain that the CLI's `tsx` loader cannot honor `emitDecoratorMetadata`, pointing at `@mikro-orm/reflection` or explicit `type:`/`entity:` attributes
50
+ - Config default exports are validated to be a plain object (primitives and arrays are rejected with a clear message)
51
+ - Abstract STI parent entities are no longer flagged as errors when `--src` does not cover their source file; a warning is now emitted instead, explaining that `@hidden`/`@namespace` tags will not apply
52
+ - `@mikro-orm/reflection` load failures (e.g. version mismatch) now emit a warning via the `onWarn` callback instead of writing directly to `process.stderr`
53
+ - Metadata cache (`temp/`) is now always disabled during doc generation regardless of which `metadataProvider` is in use, so `temp/` is never created
54
+
55
+ ### Changed
56
+
57
+ - Driver-support wording clarified around metadata-based generation and automated SQL driver smoke coverage
58
+ - `@Formula` computed columns now render as nullable
59
+ - Index and unique constraint properties in the generated document now show actual DB column names (mapped through NamingStrategy) instead of TypeScript property names
60
+ - Metadata cache is always disabled for doc generation runs; a user-supplied `metadataCache: { enabled: true }` in the MikroORM config is intentionally overridden to prevent `temp/` from being created
61
+
62
+ ## [0.1.0-alpha.2] - 2026-06-15
63
+
64
+ ### Fixed
65
+
66
+ - Metadata discovery no longer opens a database connection
67
+ - CLI `--src` option help text was cleaned up
68
+
69
+ ### Changed
70
+
71
+ - Added tag-based npm release automation and repository contribution templates
72
+ - Migrated linting and formatting setup to Biome
73
+
8
74
  ## [0.1.0-alpha.1] - 2026-06-11
9
75
 
10
76
  ### Added
@@ -0,0 +1,25 @@
1
+ # Code of Conduct
2
+
3
+ ## Our Standards
4
+
5
+ This project aims to be a respectful and practical space for users and contributors.
6
+
7
+ Examples of expected behavior:
8
+
9
+ - Use welcoming and inclusive language
10
+ - Respect differing viewpoints and experience levels
11
+ - Give constructive feedback focused on the work
12
+ - Report bugs with enough detail to help reproduce them
13
+
14
+ Examples of unacceptable behavior:
15
+
16
+ - Harassment, insults, or discriminatory language
17
+ - Personal attacks or sustained disruption
18
+ - Publishing private information without permission
19
+ - Sharing security exploit details in public issues
20
+
21
+ ## Enforcement
22
+
23
+ Project maintainers may remove comments, close issues, or block participants when behavior harms the project or its community.
24
+
25
+ If you need to report a conduct issue, contact the maintainer privately where possible. If no private channel is available, open a brief public issue asking for a private contact path without including sensitive details.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026
3
+ Copyright (c) 2026 iamkanguk97
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.ko.md CHANGED
@@ -10,25 +10,35 @@
10
10
 
11
11
  > [@samchon](https://github.com/samchon)의 [prisma-markdown](https://github.com/samchon/prisma-markdown)에서 큰 영감을 받았습니다. 좋은 아이디어에 감사드립니다.
12
12
 
13
- MikroORM에서도 동일한 ERD + Markdown 경험을 제공하며, Prisma로는 표현할 수 없는 MikroORM 고유 개념도 함께 시각화합니다.
13
+ ## 주요 기능
14
14
 
15
- - **Embeddable** 별도 테이블 없이 소유 엔티티의 테이블 안에 컬럼을 펼쳐서 저장하는 값 객체입니다. 예를 들어 `Address` 값 객체는 `address_street`, `address_city` 등의 컬럼으로 저장됩니다. DDD의 Value Object와 같은 개념입니다.
16
- - **Single Table Inheritance (STI)** `Dog`, `Cat` 같은 자식 클래스가 `animals` 테이블 하나를 공유합니다. `type` 같은 discriminator 컬럼으로 어떤 자식 클래스인지 구분합니다.
17
- - **@Formula** 실제 DB 컬럼 없이 SELECT SQL 식으로 값을 계산하는 가상 컬럼입니다. 예를 들어 `LENGTH(name)`은 DB에 컬럼이 없지만 조회 시 이름의 길이를 반환합니다.
15
+ - **Mermaid ERD 다이어그램** MikroORM 엔티티 메타데이터에서 생성합니다
16
+ - **Markdown 스키마 문서**엔티티별 컬럼 테이블, 실제 DB 컬럼명, 키, nullable 여부, 설명, 인덱스, 제약 조건을 포함합니다
17
+ - **JSDoc 기반 그룹화 노출 제어** `@namespace`, `@erd`, `@describe`, `@hidden`을 사용합니다
18
+ - **실행 중인 DB 연결 불필요** — MikroORM config의 메타데이터 discovery를 사용합니다
19
+ - **일반적인 SQL 드라이버 지원** — SQLite, PostgreSQL, MySQL, MariaDB smoke test로 검증합니다
18
20
 
19
- > 이 기능들은 MikroORM에서 완전히 지원하지만 실무에서는 자주 쓰이지 않을 수 있습니다. 특히 Embeddable은 MikroORM Entity를 Domain Entity로 함께 사용하는 구조에서 주로 활용되며, ORM 레이어와 도메인 모델을 분리해서 관리한다면 사용할 일이 거의 없습니다.
21
+ ### MikroORM 고유 개념
20
22
 
21
- - NamingStrategy가 적용된 **실제 DB 컬럼명**
22
- - **인덱스 및 제약 조건**
23
+ Prisma 기반 도구로는 표현할 없는 MikroORM 고유 개념도 함께 시각화합니다.
24
+
25
+ - **Embeddable** — 소유 엔티티의 테이블 안에 저장되는 값 객체입니다. `@Embedded` 옵션에 따라 펼쳐진 컬럼(예: `address_street`, `address_city`) 또는 JSON 컬럼으로 저장됩니다. 별도 테이블은 생성되지 않습니다.
26
+ - **Single Table Inheritance (STI)** — `Dog`, `Cat` 같은 자식 클래스가 `animals` 테이블 하나를 공유합니다. `type` 같은 discriminator 컬럼으로 어떤 자식 클래스인지 구분합니다.
27
+ - **@Formula** — 실제 DB 컬럼 없이 SELECT 시 SQL 식으로 값을 계산하는 가상 컬럼입니다. 예를 들어 `LENGTH(name)`은 DB에 컬럼이 없지만 조회 시 이름의 길이를 반환합니다.
23
28
 
24
- PostgreSQL, MySQL/MariaDB, SQLite, MSSQL 같은 MikroORM SQL 드라이버에서 동작합니다. 기존 DB 스키마를 직접 introspection하지 않고 MikroORM 설정에서 엔티티 메타데이터를 읽기 때문에 실행 중인 DB 연결이 필요하지 않습니다.
29
+ > 이들은 MikroORM의 일급 기능이지만, 모든 프로젝트에서 전부 사용하는 것은 아닙니다. `Embeddable`은 `Address`를 `address_*` 컬럼이나 JSON으로 저장하는 객체에 특히 유용하며, 여러 엔티티가 같은 컬럼 묶음을 공유할 때 중복을 줄이는 데에도 사용할 수 있습니다.
25
30
 
26
31
  ## 요구사항
27
32
 
28
- - Node.js >= 18
29
- - `@mikro-orm/core` >= 6 (peer dependency)
30
- - 사용할 DB에 맞는 MikroORM 드라이버 패키지가 설치된 MikroORM 설정 파일
31
- - TypeScript 설정 파일 사용 `tsx` 또는 `ts-node` 필요
33
+ - **Node.js >= 18**
34
+ - **MikroORM >= 6** — `@mikro-orm/core`는 peer dependency입니다.
35
+ - **MikroORM config 파일** — CLI는 plain MikroORM options object를 default export로 내보내는 파일을 기대합니다.
36
+ - **사용할 DB에 맞는 MikroORM 드라이버 패키지** 예를 들어 `@mikro-orm/postgresql`, `@mikro-orm/mysql`, `@mikro-orm/mariadb`, `@mikro-orm/sqlite`가 있습니다. 실행 중인 DB 연결은 필요 없지만, MikroORM이 메타데이터를 discovery하려면 드라이버는 필요합니다.
37
+ - **데코레이터 기반 엔티티** — 엔티티는 `@Entity()` 클래스여야 합니다. `EntitySchema`로 정의한 엔티티는 현재 지원하지 않습니다.
38
+ - **해석 가능한 프로퍼티 타입** — 각 엔티티 프로퍼티의 타입은 MikroORM discovery 시점에 알려져야 합니다. `type:` / `entity:` 같은 명시적인 데코레이터 옵션을 사용하거나, `@mikro-orm/reflection`을 설치해 CLI가 TypeScript 소스에 대해 `TsMorphMetadataProvider`를 자동으로 사용하게 하세요.
39
+ - **TypeScript config 파일을 위한 `tsx`** — CLI에서 `.ts` MikroORM config를 로드할 때만 필요합니다. `.js` config 파일에는 필요하지 않습니다.
40
+
41
+ > `@mikro-orm/reflection`을 설치한다면 **`@mikro-orm/core`와 정확히 같은 버전**으로 맞추세요. MikroORM은 공식 `@mikro-orm/*` 패키지들이 하나의 버전을 공유한다고 기대하며, 버전이 다르면 discovery가 실패할 수 있습니다.
32
42
 
33
43
  ## 설치
34
44
 
@@ -40,25 +50,18 @@ pnpm add -D mikro-orm-markdown
40
50
 
41
51
  ## 빠른 시작
42
52
 
43
- `package.json`에 스크립트를 등록합니다:
53
+ `package.json`에 스크립트를 추가하고, `--config`에 MikroORM config 파일 경로를 지정하세요:
44
54
 
45
55
  ```json
46
56
  {
47
57
  "scripts": {
48
- "erd": "mikro-orm-markdown --config ./mikro-orm.config.js --out ./ERD.md --title 'My Database' --src 'src/entities/**/*.ts'"
58
+ "erd": "mikro-orm-markdown --config ./mikro-orm.config.ts --out ./ERD.md --title 'My Database'"
49
59
  }
50
60
  }
51
61
  ```
52
62
 
53
- TypeScript 설정 파일을 사용한다면 `tsx`를 앞에 붙입니다:
54
-
55
- ```json
56
- {
57
- "scripts": {
58
- "erd": "tsx ./node_modules/.bin/mikro-orm-markdown --config ./mikro-orm.config.ts --out ./ERD.md --title 'My Database' --src 'src/entities/**/*.ts'"
59
- }
60
- }
61
- ```
63
+ - **`.ts` config** `tsx`를 devDependency로 설치하세요 (`npm install -D tsx`). CLI가 자동으로 로드하며, `preferTs`를 명시하지 않았다면 MikroORM discovery가 `entitiesTs`를 우선 사용하도록 설정합니다.
64
+ - **`.js` config** — 추가 패키지 불필요. 직접 작성한 파일이든, 빌드 결과물(예: `./dist/mikro-orm.config.js`)이든 상관없습니다.
62
65
 
63
66
  이후에는 아래 명령어 하나로 실행합니다:
64
67
 
@@ -73,11 +76,17 @@ npm run erd
73
76
  | `-c, --config <path>` | _(필수)_ | MikroORM 설정 파일 경로 |
74
77
  | `-o, --out <path>` | `./ERD.md` | 출력 Markdown 파일 경로 |
75
78
  | `-t, --title <string>` | `Database Schema` | 문서 H1 제목 |
76
- | `-s, --src <glob>` | — | 엔티티 소스 파일 glob 패턴 (반복 가능). JSDoc 태그 추출에 사용됩니다. |
79
+ | `-d, --description <string>` | — | 제목 아래에 표시할 설명 문단 (선택) |
80
+ | `--tsconfig <path>` | — | `.ts` config 로드 시 사용할 `tsconfig.json`; 기본값은 config 파일 근처의 가장 가까운 파일 |
81
+ | `--src <paths...>` | — | 원본 TypeScript 엔티티 소스 경로/glob; MikroORM이 컴파일된 JavaScript에서 엔티티를 discovery할 때만 필요 |
82
+
83
+ > 설명이 길거나 여러 줄이라면 CLI 대신 [프로그래밍 API](#프로그래밍-api)를 사용하세요 — 쉘 인용 부호 제약 없이 문자열을 그대로 전달할 수 있습니다.
77
84
 
78
85
  ## JSDoc 태그
79
86
 
80
- 엔티티 클래스에 JSDoc 태그를 추가해 문서의 섹션과 노출 여부를 제어합니다.
87
+ 엔티티 클래스에 JSDoc 태그를 추가해 문서의 섹션과 노출 여부를 제어합니다. JSDoc 주석은 TypeScript 엔티티 소스 파일에서 읽습니다.
88
+
89
+ > **권장 설정:** `.ts` MikroORM config를 사용하고 `entitiesTs`가 소스 엔티티를 가리키게 하세요. 이 설정에서는 JSDoc을 원본 TypeScript 파일에서 읽으므로 `--src`가 필요하지 않습니다.
81
90
 
82
91
  ```typescript
83
92
  /**
@@ -92,6 +101,8 @@ export class Post {
92
101
  }
93
102
  ```
94
103
 
104
+ 태그가 없는 일반 JSDoc 텍스트는 설명이 됩니다. **클래스** 위 텍스트는 엔티티 설명, **프로퍼티** 위 텍스트는 해당 컬럼 설명이 됩니다. 프로퍼티에 JSDoc이 없으면 `@Property({ comment })` 값(DDL 컬럼 코멘트)을 컬럼 설명으로 대신 사용합니다.
105
+
95
106
  | 태그 | 설명 |
96
107
  | ------------------- | ------------------------------------- |
97
108
  | `@namespace <Name>` | `Name` 섹션에 포함 (ERD + 본문 표) |
@@ -102,14 +113,101 @@ export class Post {
102
113
  태그가 없는 엔티티는 `default` 섹션에 들어갑니다.
103
114
  하나의 엔티티에 여러 태그를 지정할 수 있습니다.
104
115
 
105
- > **NestJS Swagger Plugin**: `@namespace`, `@erd`, `@describe`, `@hidden`은 Swagger가 인식하지 못하는 커스텀 태그이므로 무시됩니다. 엔티티 클래스를 DTO로 직접 사용하는 구조라면 JSDoc 설명이 Swagger 문서에도 함께 표시될 수 있지만, 기능적인 충돌은 없습니다.
116
+ ### 컴파일된 JavaScript 빌드
117
+
118
+ MikroORM config가 `entities: ['./dist/**/*.js']`처럼 컴파일된 `.js` 파일에서 엔티티를 discovery한다면, 엔티티 구조는 여전히 찾을 수 있지만 JSDoc 주석은 빌드 과정에서 제거되었을 수 있습니다.
119
+
120
+ 이 경우 설명과 `@namespace`, `@hidden` 같은 태그를 해당 `.js` 파일에서 읽을 수 없습니다.
121
+
122
+ 이 경우에만 `--src`를 사용하세요:
123
+
124
+ ```bash
125
+ mikro-orm-markdown \
126
+ --config ./dist/mikro-orm.config.js \
127
+ --src "src/**/*.entity.ts"
128
+ ```
129
+
130
+ `--src`가 어떤 파일과도 매칭되지 않거나 발견된 엔티티 선언을 빠뜨리면, 불완전한 문서를 조용히 생성하는 대신 실패합니다.
131
+
132
+ ### 관계 카디널리티: `@atLeastOne`
133
+
134
+ `@atLeastOne`은 TypeScript decorator가 아니라 JSDoc 태그입니다.
135
+
136
+ 컬렉션 관계(`1:N` 또는 `M:N`)는 기본적으로 _0개 이상_으로 렌더링됩니다. 컬렉션 프로퍼티에 `@atLeastOne`를 붙이면 해당 컬렉션 쪽이 _1개 이상_으로 표시됩니다:
137
+
138
+ ```typescript
139
+ @Entity()
140
+ export class Author {
141
+ /** @atLeastOne */
142
+ @OneToMany(() => Post, (post) => post.author)
143
+ posts = new Collection<Post>(this);
144
+ }
145
+ ```
146
+
147
+ 이렇게 하면 ERD 관계선이 `Post }o--|| Author`에서 `Post }|--|| Author`로 바뀝니다. 이는 문서용 힌트일 뿐이며 — MikroORM에는 스키마 레벨의 최소 개수 개념이 없어 실제로 강제되지는 않습니다. (Mermaid는 0개 이상 / 1개 이상만 구분하므로 그보다 큰 최소값은 표현할 수 없습니다.)
148
+
149
+ 하나의 관계선은 **양 끝이 따로 결정**됩니다:
150
+
151
+ - **단수(1) 쪽** (`@ManyToOne`, 또는 소유 측 `@OneToOne`) — 스키마에서 자동으로 읽으며 태그가 필요 없습니다: 기본 _정확히 1_ (`||`), `nullable: true`이면 _0 또는 1_ (`o|`).
152
+ - **컬렉션(N) 쪽** (`@OneToMany` / `@ManyToMany`) — 기본 _0개 이상_이며, `@atLeastOne`을 붙이면 해당 쪽이 _1개 이상_으로 바뀝니다. Mermaid에서는 컬렉션이 렌더링되는 방향에 따라 `}o` → `}|` 또는 `o{` → `|{`를 사용합니다.
153
+
154
+ 네 가지 조합 (`Post` ↔ `Author`):
155
+
156
+ ```text
157
+ Post }o--|| Author → 작성자 글 0개+, 글은 작성자 정확히 1명 (기본)
158
+ Post }o--o| Author → 작성자 글 0개+, 글은 작성자 0~1명 (nullable: true)
159
+ Post }|--|| Author → 작성자 글 1개+, 글은 작성자 정확히 1명 (@atLeastOne)
160
+ Post }|--o| Author → 작성자 글 1개+, 글은 작성자 0~1명 (둘 다)
161
+ ```
162
+
163
+ > **NestJS Swagger Plugin**: `@namespace`, `@erd`, `@describe`, `@hidden`, `@atLeastOne`은 `mikro-orm-markdown`용 커스텀 태그입니다. NestJS Swagger는 이 태그들을 OpenAPI 메타데이터로 사용하지 않습니다. 엔티티 클래스를 DTO로 직접 사용하고 Swagger comment introspection을 켠 경우, 일반 JSDoc 설명은 Swagger 문서에도 표시될 수 있지만 이 커스텀 태그들이 기능적인 충돌을 만들지는 않습니다.
106
164
 
107
165
  ## 출력 예시
108
166
 
109
- 네임스페이스마다 섹션이 생성되고, 섹션에는 Mermaid ERD 블록과 엔티티별 컬럼 표가 포함됩니다.
167
+ 다음과 같은 엔티티가 있다고 가정합니다:
168
+
169
+ ```typescript
170
+ /**
171
+ * 등록된 사용자가 작성한 블로그 게시글입니다.
172
+ * @namespace Blog
173
+ */
174
+ @Entity()
175
+ export class Post {
176
+ @PrimaryKey({ type: 'integer' })
177
+ id!: number;
178
+
179
+ /** 게시글 제목 */
180
+ @Property({ type: 'string' })
181
+ title!: string;
182
+
183
+ @Property({ type: 'text', nullable: true })
184
+ body?: string;
185
+
186
+ @ManyToOne({ entity: () => Author })
187
+ author!: Author;
188
+ }
189
+
190
+ /** @namespace Blog */
191
+ @Entity()
192
+ export class Author {
193
+ @PrimaryKey({ type: 'integer' })
194
+ id!: number;
195
+
196
+ @Property({ type: 'string' })
197
+ name!: string;
198
+
199
+ @Property({ type: 'string', unique: true })
200
+ email!: string;
201
+
202
+ /** @atLeastOne */
203
+ @OneToMany({ entity: () => Post, mappedBy: 'author' })
204
+ posts = new Collection<Post>(this);
205
+ }
206
+ ```
207
+
208
+ > **예시 참고:** import 문은 간결성을 위해 생략했습니다. 이 예시는 별도 reflection 설정 없이 동작하도록 `type:`을 명시합니다. `@mikro-orm/reflection`이 설치되어 있다면 MikroORM은 `@Property() title!: string` 같은 단순 scalar 타입도 discovery할 수 있습니다.
110
209
 
111
- ````markdown
112
- ## Blog
210
+ 두 엔티티 모두 `@namespace Blog` 태그를 가지므로 하나의 `## Blog` 섹션에 묶입니다. MikroORM의 기본 naming strategy를 기준으로 생성된 `ERD.md`에는 다음과 같은 ERD가 포함됩니다:
113
211
 
114
212
  ```mermaid
115
213
  erDiagram
@@ -117,18 +215,41 @@ erDiagram
117
215
  integer id PK
118
216
  string title
119
217
  text body
120
- integer author_id FK "author"
218
+ integer author_id FK
121
219
  }
122
220
  Author {
123
221
  integer id PK
124
222
  string name
125
223
  string email UK
126
224
  }
127
- Post }o--|| Author : "author"
225
+ Post }|--|| Author : "author"
128
226
  ```
129
227
 
228
+ **코드가 출력으로 어떻게 매핑되는가:**
229
+
230
+ - `@namespace Blog` → 두 엔티티가 `## Blog` 섹션 아래로 묶임
231
+ - `@ManyToOne({ entity: () => Author })` → `Post`에서 `Author`로 향하는 관계선과 `author_id FK` 컬럼
232
+ - `Author.posts`의 `@atLeastOne` → 컬렉션 쪽이 1개 이상으로 렌더링됨: `Post }|--|| Author`
233
+ - `email`의 `unique: true` → `email`이 `UK`(unique key)로 표시됨
234
+ - `body`의 `@Property({ nullable: true })` → `Nullable` 칸이 `Y`로 표시됨
235
+ - `/** 게시글 제목 */` → `title`의 **Description** 칸을 채움
236
+
237
+ **키 표기:**
238
+
239
+ | 표기 | 의미 |
240
+ | ---- | ---- |
241
+ | `PK` | Primary key |
242
+ | `FK` | Foreign key |
243
+ | `UK` | Unique key |
244
+ | `Nullable`의 `Y` | nullable 컬럼 |
245
+
246
+ 각 엔티티는 컬럼 표로도 표현됩니다. 예를 들어 생성된 `Post` 섹션은 다음과 같습니다:
247
+
248
+ ```markdown
130
249
  ### Post
131
250
 
251
+ *Table: `post`*
252
+
132
253
  > 등록된 사용자가 작성한 블로그 게시글입니다.
133
254
 
134
255
  | Column | Type | Key | Nullable | Description |
@@ -137,13 +258,13 @@ erDiagram
137
258
  | title | string | | | 게시글 제목 |
138
259
  | body | text | | Y | |
139
260
  | author_id | integer | FK (author) | | |
140
- ````
261
+ ```
141
262
 
142
- **Key 컬럼 주석 의미:**
263
+ **생성 결과의 MikroORM 전용 표기 의미:**
143
264
 
144
265
  | 표기 | 의미 |
145
266
  | ------------------ | -------------------------------------------- |
146
- | `formula: <expr>` | `@Formula` 계산 컬럼 실제 DB 컬럼 없음 |
267
+ | `formula: <expr>` | `@Formula` 계산 컬럼의 Mermaid 주석 |
147
268
  | `[EmbeddableType]` | `@Embedded` 값 객체에서 flat으로 저장된 컬럼 |
148
269
  | `discriminator` | STI 구분자 컬럼 |
149
270
 
@@ -156,23 +277,91 @@ STI는 여러 엔티티 클래스가 하나의 DB 테이블을 공유하는 패
156
277
  ```typescript
157
278
  @Entity({ discriminatorColumn: 'type', abstract: true })
158
279
  export class Animal {
159
- @PrimaryKey()
280
+ @PrimaryKey({ type: 'integer' })
160
281
  id!: number;
161
282
 
162
- @Property()
283
+ @Property({ type: 'string' })
163
284
  name!: string;
164
285
  }
165
286
 
166
287
  @Entity({ discriminatorValue: 'dog' })
167
288
  export class Dog extends Animal {
168
- @Property({ nullable: true })
289
+ @Property({ type: 'string', nullable: true })
169
290
  breed?: string;
170
291
  }
171
292
  ```
172
293
 
173
- 엔티티에 `discriminatorColumn`이 설정되어 있으면 `mikro-orm-markdown`이 자동으로 감지해 출력에 discriminator 컬럼을 표시합니다.
294
+ 엔티티에 `discriminatorColumn`이 설정되어 있으면 `mikro-orm-markdown`이 자동으로 감지합니다. 서브클래스들은 물리적으로 하나의 테이블을 공유하지만, 다이어그램에서는 **각 클래스가 별도 박스**로 그려져 서브클래스마다 실제 컬럼 구성을 보여줍니다:
295
+
296
+ ```mermaid
297
+ erDiagram
298
+ Animal {
299
+ integer id PK
300
+ string name
301
+ string type "discriminator"
302
+ }
303
+ Dog {
304
+ integer id PK
305
+ string name
306
+ string type
307
+ string breed
308
+ }
309
+ ```
310
+
311
+ 루트(`Animal`)는 공유 컬럼만 나열하고 discriminator(`type`)를 표시하며, 각 서브클래스(`Dog`)는 상속 컬럼을 반복한 뒤 자기 컬럼을 추가합니다.
312
+
313
+ 생성된 Markdown 표에도 STI note가 함께 표시됩니다. 루트에는 `STI root — discriminator column: type`, 각 서브클래스에는 `Extends Animal (Single Table Inheritance, discriminator value: dog)` 같은 문구가 추가됩니다.
314
+
315
+ > **트레이드오프:** STI는 여러 엔티티 타입을 하나의 테이블에 보관할 수 있게 하지만, 쿼리 복잡도를 높이고 nullable 컬럼이 많이 생길 수 있습니다. 하나의 테이블을 공유하는 것이 모델의 의도일 때 사용하세요.
316
+
317
+ ## 문제 해결
318
+
319
+ **"엔티티가 발견되지 않았습니다" (No entities were discovered)**
174
320
 
175
- > **대부분의 프로젝트에는 권장하지 않습니다.** STI는 테이블 단순화 대신 쿼리 복잡도 증가와 nullable 컬럼 낭비를 초래합니다. 여러 엔티티 타입을 하나의 테이블에 저장해야 하는 명확한 이유가 있을 때만 사용하세요.
321
+ MikroORM config가 엔티티를 0개 찾은 경우입니다. 보통 CLI가 config를 로드하는 방식과 엔티티 경로가 맞지 않아 발생합니다.
322
+
323
+ - `.ts` config를 사용 중이라면(CLI가 `tsx`를 자동으로 로드하고 기본적으로 `preferTs: true`를 적용합니다), `entitiesTs`가 TypeScript 소스 파일을 가리키는지 확인하세요.
324
+ - 빌드된 `.js` config를 사용 중이라면, `entities`가 **빌드 결과물**(예: `./dist/**/*.entity.js`)을 가리키고 빌드를 먼저 실행했는지 확인하세요.
325
+ - MikroORM은 TypeScript 모드에서는 `entitiesTs`를, 그 외에는 `entities`를 사용합니다. 폴더/파일 기반 discovery를 쓴다면 두 옵션을 모두 지정하세요.
326
+
327
+ **"Please provide either 'type' or 'entity' attribute"**
328
+
329
+ MikroORM이 metadata discovery 중 프로퍼티 타입을 해석하지 못한 경우입니다. CLI는 `.ts` config를 `tsx`로 로드하므로, 이 경로에서는 `emitDecoratorMetadata`를 켜는 것만으로는 해결되지 않습니다.
330
+
331
+ 다음 중 하나로 해결하세요:
332
+
333
+ - `@Property({ type: 'string' })`, `@ManyToOne({ entity: () => User })`처럼 데코레이터 옵션을 명시합니다.
334
+ - `@mikro-orm/reflection`을 `@mikro-orm/core`와 정확히 같은 버전으로 설치해 CLI가 `TsMorphMetadataProvider`를 자동으로 사용하게 합니다.
335
+
336
+ **"Cannot find module '@/...'" (경로 alias)**
337
+
338
+ config나 엔티티에서 `tsconfig`의 경로 alias(예: `@/entities/user`)를 사용한다면, `tsx`가 올바른 `tsconfig.json`을 찾지 못했을 때 alias를 해석하지 못할 수 있습니다. config 파일을 `tsconfig.json`과 같은 프로젝트 루트에 두면 이 문제를 피할 수 있습니다. config가 다른 위치에 있다면 명시적으로 전달하세요:
339
+
340
+ ```bash
341
+ mikro-orm-markdown --config ./packages/api/mikro-orm.config.ts --tsconfig ./packages/api/tsconfig.json
342
+ ```
343
+
344
+ **JSDoc 태그가 누락되거나 `@hidden` 엔티티가 노출되는 경우**
345
+
346
+ 엔티티가 컴파일된 JavaScript에서 discovery되고 있을 가능성이 큽니다. 빌드 도구는 `.js` 파일에서 주석을 제거할 수 있으므로, 설명과 `@namespace`, `@hidden`을 읽지 못할 수 있습니다.
347
+
348
+ 가능하면 `.ts` config와 원본 소스 파일을 가리키는 `entitiesTs`를 사용하세요. 반드시 컴파일된 `.js`에서 실행해야 한다면 원본 TypeScript 소스를 함께 전달하세요:
349
+
350
+ ```bash
351
+ mikro-orm-markdown --config ./dist/mikro-orm.config.js --src "src/**/*.entity.ts"
352
+ ```
353
+
354
+ **Config 파일 요구사항**
355
+
356
+ config 파일은 일반 설정 객체를 **default export** 해야 합니다.
357
+
358
+ ```typescript
359
+ export default defineConfig({ ... }); // ✅
360
+ export const config = defineConfig({ ... }); // ❌ named export 미지원
361
+ export default async () => defineConfig({ ... }); // ❌ 함수/Promise 미지원
362
+ ```
363
+
364
+ config를 비동기적으로 만들어야 한다면, 아래 프로그래밍 API를 사용하세요.
176
365
 
177
366
  ## 고급 사용법
178
367
 
@@ -181,16 +370,34 @@ export class Dog extends Animal {
181
370
  커스텀 빌드 스크립트에 통합하거나 출력 결과를 직접 가공해야 할 때 사용합니다:
182
371
 
183
372
  ```typescript
373
+ import { writeFile } from 'node:fs/promises';
184
374
  import { generateMarkdown } from 'mikro-orm-markdown';
185
375
  import ormConfig from './mikro-orm.config.js';
186
376
 
187
377
  const markdown = await generateMarkdown({
188
378
  orm: ormConfig,
189
379
  title: 'My Database',
190
- src: ['src/entities/**/*.ts'],
380
+ description: 'MikroORM metadata에서 생성한 스키마 문서입니다.',
191
381
  });
192
382
 
193
- await fs.writeFile('./ERD.md', markdown, 'utf-8');
383
+ await writeFile('./ERD.md', markdown, 'utf-8');
384
+ ```
385
+
386
+ 프로그래밍 API 옵션:
387
+
388
+ | 옵션 | 설명 |
389
+ | ---- | ---- |
390
+ | `orm` | MikroORM options object입니다. 필수입니다. |
391
+ | `title` | H1 제목입니다. 기본값은 `Database Schema`입니다. |
392
+ | `description` | 제목 아래에 표시할 설명 문단입니다. CLI flag와 달리 쉘 quoting 제약 없이 문자열을 그대로 전달할 수 있습니다. |
393
+ | `src` | 원본 TypeScript 엔티티 소스 경로/glob입니다. `orm.entities`가 컴파일된 JavaScript를 discovery할 때만 필요합니다. |
394
+ | `onWarn` | 컴파일된 JavaScript에서 JSDoc을 읽지 못하는 상황 같은 non-fatal warning을 받을 callback입니다. |
395
+
396
+ MikroORM config를 비동기적으로 만들어야 한다면 직접 resolve한 뒤 결과 options object를 전달하세요:
397
+
398
+ ```typescript
399
+ const ormConfig = await createOrmConfig();
400
+ const markdown = await generateMarkdown({ orm: ormConfig });
194
401
  ```
195
402
 
196
403
  ## 라이선스