@mandujs/core 0.12.2 → 0.13.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.
Files changed (173) hide show
  1. package/README.ko.md +304 -304
  2. package/README.md +653 -653
  3. package/package.json +1 -1
  4. package/src/brain/architecture/analyzer.ts +28 -26
  5. package/src/brain/doctor/analyzer.ts +1 -1
  6. package/src/bundler/build.ts +91 -91
  7. package/src/bundler/css.ts +302 -302
  8. package/src/bundler/dev.ts +0 -1
  9. package/src/change/history.ts +3 -3
  10. package/src/change/snapshot.ts +10 -9
  11. package/src/change/transaction.ts +2 -2
  12. package/src/client/Link.tsx +227 -227
  13. package/src/client/globals.ts +44 -44
  14. package/src/client/hooks.ts +267 -267
  15. package/src/client/index.ts +5 -5
  16. package/src/client/island.ts +8 -8
  17. package/src/client/router.ts +435 -435
  18. package/src/client/runtime.ts +23 -23
  19. package/src/client/serialize.ts +404 -404
  20. package/src/client/window-state.ts +101 -101
  21. package/src/config/mandu.ts +94 -96
  22. package/src/config/validate.ts +213 -215
  23. package/src/config/watcher.ts +311 -311
  24. package/src/constants.ts +40 -40
  25. package/src/content/content-layer.ts +314 -314
  26. package/src/content/content.test.ts +433 -433
  27. package/src/content/data-store.ts +245 -245
  28. package/src/content/digest.ts +133 -133
  29. package/src/content/index.ts +164 -164
  30. package/src/content/loader-context.ts +172 -172
  31. package/src/content/loaders/api.ts +216 -216
  32. package/src/content/loaders/file.ts +169 -169
  33. package/src/content/loaders/glob.ts +252 -252
  34. package/src/content/loaders/index.ts +34 -34
  35. package/src/content/loaders/types.ts +137 -137
  36. package/src/content/meta-store.ts +209 -209
  37. package/src/content/types.ts +282 -282
  38. package/src/content/watcher.ts +135 -135
  39. package/src/contract/client-safe.test.ts +42 -42
  40. package/src/contract/client-safe.ts +114 -114
  41. package/src/contract/client.ts +16 -16
  42. package/src/contract/define.ts +459 -459
  43. package/src/contract/handler.ts +10 -10
  44. package/src/contract/normalize.test.ts +276 -276
  45. package/src/contract/normalize.ts +404 -404
  46. package/src/contract/registry.test.ts +206 -206
  47. package/src/contract/registry.ts +568 -568
  48. package/src/contract/schema.ts +48 -48
  49. package/src/contract/types.ts +58 -58
  50. package/src/contract/validator.ts +32 -32
  51. package/src/devtools/ai/context-builder.ts +375 -375
  52. package/src/devtools/ai/index.ts +25 -25
  53. package/src/devtools/ai/mcp-connector.ts +465 -465
  54. package/src/devtools/client/catchers/error-catcher.ts +327 -327
  55. package/src/devtools/client/catchers/index.ts +18 -18
  56. package/src/devtools/client/catchers/network-proxy.ts +363 -363
  57. package/src/devtools/client/components/index.ts +39 -39
  58. package/src/devtools/client/components/kitchen-root.tsx +362 -362
  59. package/src/devtools/client/components/mandu-character.tsx +241 -241
  60. package/src/devtools/client/components/overlay.tsx +368 -368
  61. package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
  62. package/src/devtools/client/components/panel/guard-panel.tsx +244 -244
  63. package/src/devtools/client/components/panel/index.ts +32 -32
  64. package/src/devtools/client/components/panel/islands-panel.tsx +304 -304
  65. package/src/devtools/client/components/panel/network-panel.tsx +292 -292
  66. package/src/devtools/client/components/panel/panel-container.tsx +259 -259
  67. package/src/devtools/client/filters/context-filters.ts +282 -282
  68. package/src/devtools/client/filters/index.ts +16 -16
  69. package/src/devtools/client/index.ts +63 -63
  70. package/src/devtools/client/persistence.ts +335 -335
  71. package/src/devtools/client/state-manager.ts +478 -478
  72. package/src/devtools/design-tokens.ts +263 -263
  73. package/src/devtools/hook/create-hook.ts +207 -207
  74. package/src/devtools/hook/index.ts +13 -13
  75. package/src/devtools/index.ts +439 -439
  76. package/src/devtools/init.ts +266 -266
  77. package/src/devtools/protocol.ts +237 -237
  78. package/src/devtools/server/index.ts +17 -17
  79. package/src/devtools/server/source-context.ts +444 -444
  80. package/src/devtools/types.ts +319 -319
  81. package/src/devtools/worker/index.ts +25 -25
  82. package/src/devtools/worker/redaction-worker.ts +222 -222
  83. package/src/devtools/worker/worker-manager.ts +409 -409
  84. package/src/error/classifier.ts +2 -2
  85. package/src/error/domains.ts +265 -265
  86. package/src/error/formatter.ts +32 -32
  87. package/src/error/result.ts +46 -46
  88. package/src/error/stack-analyzer.ts +5 -0
  89. package/src/error/types.ts +6 -6
  90. package/src/errors/extractor.ts +409 -409
  91. package/src/errors/index.ts +19 -19
  92. package/src/filling/auth.ts +308 -308
  93. package/src/filling/context.ts +569 -569
  94. package/src/filling/deps.ts +238 -238
  95. package/src/generator/contract-glue.ts +2 -1
  96. package/src/generator/generate.ts +12 -10
  97. package/src/generator/index.ts +3 -3
  98. package/src/generator/templates.ts +80 -79
  99. package/src/guard/analyzer.ts +360 -360
  100. package/src/guard/ast-analyzer.ts +806 -806
  101. package/src/guard/auto-correct.ts +1 -1
  102. package/src/guard/check.ts +128 -128
  103. package/src/guard/contract-guard.ts +9 -9
  104. package/src/guard/file-type.test.ts +24 -24
  105. package/src/guard/presets/atomic.ts +70 -70
  106. package/src/guard/presets/clean.ts +77 -77
  107. package/src/guard/presets/cqrs.test.ts +35 -14
  108. package/src/guard/presets/fsd.ts +79 -79
  109. package/src/guard/presets/hexagonal.ts +68 -68
  110. package/src/guard/presets/index.ts +291 -291
  111. package/src/guard/reporter.ts +445 -445
  112. package/src/guard/rules.ts +12 -12
  113. package/src/guard/statistics.ts +578 -578
  114. package/src/guard/suggestions.ts +358 -358
  115. package/src/guard/types.ts +348 -348
  116. package/src/guard/validator.ts +834 -834
  117. package/src/guard/watcher.ts +404 -404
  118. package/src/index.ts +1 -0
  119. package/src/intent/index.ts +310 -310
  120. package/src/island/index.ts +304 -304
  121. package/src/logging/index.ts +22 -22
  122. package/src/logging/transports.ts +365 -365
  123. package/src/paths.test.ts +47 -0
  124. package/src/paths.ts +47 -0
  125. package/src/plugins/index.ts +38 -38
  126. package/src/plugins/registry.ts +377 -377
  127. package/src/plugins/types.ts +363 -363
  128. package/src/report/build.ts +1 -1
  129. package/src/report/index.ts +1 -1
  130. package/src/router/fs-patterns.ts +387 -387
  131. package/src/router/fs-routes.ts +344 -401
  132. package/src/router/fs-scanner.ts +497 -497
  133. package/src/router/fs-types.ts +270 -278
  134. package/src/router/index.ts +81 -81
  135. package/src/runtime/boundary.tsx +232 -232
  136. package/src/runtime/compose.ts +222 -222
  137. package/src/runtime/lifecycle.ts +381 -381
  138. package/src/runtime/logger.test.ts +345 -345
  139. package/src/runtime/logger.ts +677 -677
  140. package/src/runtime/router.test.ts +476 -476
  141. package/src/runtime/router.ts +105 -105
  142. package/src/runtime/security.ts +155 -155
  143. package/src/runtime/server.ts +24 -24
  144. package/src/runtime/session-key.ts +328 -328
  145. package/src/runtime/ssr.ts +367 -367
  146. package/src/runtime/streaming-ssr.ts +1245 -1245
  147. package/src/runtime/trace.ts +144 -144
  148. package/src/seo/index.ts +214 -214
  149. package/src/seo/integration/ssr.ts +307 -307
  150. package/src/seo/render/basic.ts +427 -427
  151. package/src/seo/render/index.ts +143 -143
  152. package/src/seo/render/jsonld.ts +539 -539
  153. package/src/seo/render/opengraph.ts +191 -191
  154. package/src/seo/render/robots.ts +116 -116
  155. package/src/seo/render/sitemap.ts +137 -137
  156. package/src/seo/render/twitter.ts +126 -126
  157. package/src/seo/resolve/index.ts +353 -353
  158. package/src/seo/resolve/opengraph.ts +143 -143
  159. package/src/seo/resolve/robots.ts +73 -73
  160. package/src/seo/resolve/title.ts +94 -94
  161. package/src/seo/resolve/twitter.ts +73 -73
  162. package/src/seo/resolve/url.ts +97 -97
  163. package/src/seo/routes/index.ts +290 -290
  164. package/src/seo/types.ts +575 -575
  165. package/src/slot/validator.ts +39 -39
  166. package/src/spec/index.ts +3 -3
  167. package/src/spec/load.ts +76 -76
  168. package/src/spec/lock.ts +56 -56
  169. package/src/utils/bun.ts +8 -8
  170. package/src/utils/lru-cache.ts +75 -75
  171. package/src/utils/safe-io.ts +188 -188
  172. package/src/utils/string-safe.ts +298 -298
  173. package/src/watcher/rules.ts +5 -5
@@ -1,188 +1,188 @@
1
- /**
2
- * 안전한 파일 I/O 유틸리티
3
- *
4
- * Result<T> 패턴을 사용하여 에러 정보를 보존합니다.
5
- * try-catch 대신 이 함수들을 사용하면 에러 컨텍스트가 유지됩니다.
6
- */
7
-
8
- import { readFile, readdir, access, stat } from "fs/promises";
9
- import type { Dirent, Stats } from "fs";
10
- import type { Result } from "../error/result";
11
- import { ok, err } from "../error/result";
12
- import { FileError, DirectoryError } from "../error/domains";
13
-
14
- // ============================================================
15
- // 파일 읽기
16
- // ============================================================
17
-
18
- /**
19
- * 안전한 파일 읽기 (텍스트)
20
- *
21
- * @example
22
- * const result = await safeReadFile("path/to/file.ts");
23
- * if (!result.ok) {
24
- * console.error(result.error.message);
25
- * return;
26
- * }
27
- * const content = result.value;
28
- */
29
- export async function safeReadFile(filePath: string): Promise<Result<string>> {
30
- try {
31
- const content = await readFile(filePath, "utf-8");
32
- return ok(content);
33
- } catch (e) {
34
- return err(new FileError(filePath, "read", e).toManduError());
35
- }
36
- }
37
-
38
- /**
39
- * 안전한 파일 읽기 (Bun 최적화 버전)
40
- * Bun.file().text()는 readFile보다 빠릅니다.
41
- */
42
- export async function safeReadFileBun(filePath: string): Promise<Result<string>> {
43
- try {
44
- const content = await Bun.file(filePath).text();
45
- return ok(content);
46
- } catch (e) {
47
- return err(new FileError(filePath, "read", e).toManduError());
48
- }
49
- }
50
-
51
- /**
52
- * 파일 존재 여부 확인
53
- */
54
- export async function safeFileExists(filePath: string): Promise<Result<boolean>> {
55
- try {
56
- await access(filePath);
57
- return ok(true);
58
- } catch (e) {
59
- // ENOENT는 정상적인 "없음" 상태
60
- if ((e as NodeJS.ErrnoException).code === "ENOENT") {
61
- return ok(false);
62
- }
63
- // 그 외는 실제 에러 (권한 등)
64
- return err(new FileError(filePath, "access", e).toManduError());
65
- }
66
- }
67
-
68
- /**
69
- * 파일 정보 조회
70
- */
71
- export async function safeFileStat(filePath: string): Promise<Result<Stats>> {
72
- try {
73
- const stats = await stat(filePath);
74
- return ok(stats);
75
- } catch (e) {
76
- return err(new FileError(filePath, "stat", e).toManduError());
77
- }
78
- }
79
-
80
- // ============================================================
81
- // 디렉토리 읽기
82
- // ============================================================
83
-
84
- /**
85
- * 안전한 디렉토리 읽기
86
- */
87
- export async function safeReadDir(dirPath: string): Promise<Result<string[]>> {
88
- try {
89
- const entries = await readdir(dirPath);
90
- return ok(entries);
91
- } catch (e) {
92
- return err(new DirectoryError(dirPath, e).toManduError());
93
- }
94
- }
95
-
96
- /**
97
- * 안전한 디렉토리 읽기 (Dirent 포함)
98
- */
99
- export async function safeReadDirWithTypes(
100
- dirPath: string
101
- ): Promise<Result<Dirent[]>> {
102
- try {
103
- const entries = await readdir(dirPath, { withFileTypes: true });
104
- return ok(entries);
105
- } catch (e) {
106
- return err(new DirectoryError(dirPath, e).toManduError());
107
- }
108
- }
109
-
110
- // ============================================================
111
- // 조합 유틸리티
112
- // ============================================================
113
-
114
- /**
115
- * 여러 파일을 병렬로 읽기
116
- *
117
- * @returns 성공한 파일들만 반환, 실패는 errors에 수집
118
- */
119
- export async function safeReadFiles(
120
- filePaths: string[]
121
- ): Promise<{
122
- results: Map<string, string>;
123
- errors: Map<string, Error>;
124
- }> {
125
- const results = new Map<string, string>();
126
- const errors = new Map<string, Error>();
127
-
128
- await Promise.all(
129
- filePaths.map(async (filePath) => {
130
- const result = await safeReadFileBun(filePath);
131
- if (result.ok) {
132
- results.set(filePath, result.value);
133
- } else {
134
- errors.set(filePath, new Error(result.error.message));
135
- }
136
- })
137
- );
138
-
139
- return { results, errors };
140
- }
141
-
142
- /**
143
- * 파일이 있으면 읽고, 없으면 기본값 반환
144
- */
145
- export async function safeReadFileOrDefault(
146
- filePath: string,
147
- defaultValue: string
148
- ): Promise<string> {
149
- const result = await safeReadFileBun(filePath);
150
- return result.ok ? result.value : defaultValue;
151
- }
152
-
153
- /**
154
- * 디렉토리의 모든 파일 경로 수집 (재귀)
155
- */
156
- export async function safeGlobDir(
157
- dirPath: string,
158
- pattern?: RegExp
159
- ): Promise<Result<string[]>> {
160
- const result = await safeReadDirWithTypes(dirPath);
161
- if (!result.ok) return result;
162
-
163
- const files: string[] = [];
164
- const subDirPromises: Promise<Result<string[]>>[] = [];
165
-
166
- for (const entry of result.value) {
167
- const fullPath = `${dirPath}/${entry.name}`;
168
-
169
- if (entry.isDirectory()) {
170
- subDirPromises.push(safeGlobDir(fullPath, pattern));
171
- } else if (entry.isFile()) {
172
- if (!pattern || pattern.test(entry.name)) {
173
- files.push(fullPath);
174
- }
175
- }
176
- }
177
-
178
- // 서브 디렉토리 결과 수집
179
- const subResults = await Promise.all(subDirPromises);
180
- for (const subResult of subResults) {
181
- if (subResult.ok) {
182
- files.push(...subResult.value);
183
- }
184
- // 서브 디렉토리 에러는 무시 (접근 불가 디렉토리 스킵)
185
- }
186
-
187
- return ok(files);
188
- }
1
+ /**
2
+ * 안전한 파일 I/O 유틸리티
3
+ *
4
+ * Result<T> 패턴을 사용하여 에러 정보를 보존합니다.
5
+ * try-catch 대신 이 함수들을 사용하면 에러 컨텍스트가 유지됩니다.
6
+ */
7
+
8
+ import { readFile, readdir, access, stat } from "fs/promises";
9
+ import type { Dirent, Stats } from "fs";
10
+ import type { Result } from "../error/result";
11
+ import { ok, err } from "../error/result";
12
+ import { FileError, DirectoryError } from "../error/domains";
13
+
14
+ // ============================================================
15
+ // 파일 읽기
16
+ // ============================================================
17
+
18
+ /**
19
+ * 안전한 파일 읽기 (텍스트)
20
+ *
21
+ * @example
22
+ * const result = await safeReadFile("path/to/file.ts");
23
+ * if (!result.ok) {
24
+ * console.error(result.error.message);
25
+ * return;
26
+ * }
27
+ * const content = result.value;
28
+ */
29
+ export async function safeReadFile(filePath: string): Promise<Result<string>> {
30
+ try {
31
+ const content = await readFile(filePath, "utf-8");
32
+ return ok(content);
33
+ } catch (e) {
34
+ return err(new FileError(filePath, "read", e).toManduError());
35
+ }
36
+ }
37
+
38
+ /**
39
+ * 안전한 파일 읽기 (Bun 최적화 버전)
40
+ * Bun.file().text()는 readFile보다 빠릅니다.
41
+ */
42
+ export async function safeReadFileBun(filePath: string): Promise<Result<string>> {
43
+ try {
44
+ const content = await Bun.file(filePath).text();
45
+ return ok(content);
46
+ } catch (e) {
47
+ return err(new FileError(filePath, "read", e).toManduError());
48
+ }
49
+ }
50
+
51
+ /**
52
+ * 파일 존재 여부 확인
53
+ */
54
+ export async function safeFileExists(filePath: string): Promise<Result<boolean>> {
55
+ try {
56
+ await access(filePath);
57
+ return ok(true);
58
+ } catch (e) {
59
+ // ENOENT는 정상적인 "없음" 상태
60
+ if ((e as NodeJS.ErrnoException).code === "ENOENT") {
61
+ return ok(false);
62
+ }
63
+ // 그 외는 실제 에러 (권한 등)
64
+ return err(new FileError(filePath, "access", e).toManduError());
65
+ }
66
+ }
67
+
68
+ /**
69
+ * 파일 정보 조회
70
+ */
71
+ export async function safeFileStat(filePath: string): Promise<Result<Stats>> {
72
+ try {
73
+ const stats = await stat(filePath);
74
+ return ok(stats);
75
+ } catch (e) {
76
+ return err(new FileError(filePath, "stat", e).toManduError());
77
+ }
78
+ }
79
+
80
+ // ============================================================
81
+ // 디렉토리 읽기
82
+ // ============================================================
83
+
84
+ /**
85
+ * 안전한 디렉토리 읽기
86
+ */
87
+ export async function safeReadDir(dirPath: string): Promise<Result<string[]>> {
88
+ try {
89
+ const entries = await readdir(dirPath);
90
+ return ok(entries);
91
+ } catch (e) {
92
+ return err(new DirectoryError(dirPath, e).toManduError());
93
+ }
94
+ }
95
+
96
+ /**
97
+ * 안전한 디렉토리 읽기 (Dirent 포함)
98
+ */
99
+ export async function safeReadDirWithTypes(
100
+ dirPath: string
101
+ ): Promise<Result<Dirent[]>> {
102
+ try {
103
+ const entries = await readdir(dirPath, { withFileTypes: true });
104
+ return ok(entries);
105
+ } catch (e) {
106
+ return err(new DirectoryError(dirPath, e).toManduError());
107
+ }
108
+ }
109
+
110
+ // ============================================================
111
+ // 조합 유틸리티
112
+ // ============================================================
113
+
114
+ /**
115
+ * 여러 파일을 병렬로 읽기
116
+ *
117
+ * @returns 성공한 파일들만 반환, 실패는 errors에 수집
118
+ */
119
+ export async function safeReadFiles(
120
+ filePaths: string[]
121
+ ): Promise<{
122
+ results: Map<string, string>;
123
+ errors: Map<string, Error>;
124
+ }> {
125
+ const results = new Map<string, string>();
126
+ const errors = new Map<string, Error>();
127
+
128
+ await Promise.all(
129
+ filePaths.map(async (filePath) => {
130
+ const result = await safeReadFileBun(filePath);
131
+ if (result.ok) {
132
+ results.set(filePath, result.value);
133
+ } else {
134
+ errors.set(filePath, new Error(result.error.message));
135
+ }
136
+ })
137
+ );
138
+
139
+ return { results, errors };
140
+ }
141
+
142
+ /**
143
+ * 파일이 있으면 읽고, 없으면 기본값 반환
144
+ */
145
+ export async function safeReadFileOrDefault(
146
+ filePath: string,
147
+ defaultValue: string
148
+ ): Promise<string> {
149
+ const result = await safeReadFileBun(filePath);
150
+ return result.ok ? result.value : defaultValue;
151
+ }
152
+
153
+ /**
154
+ * 디렉토리의 모든 파일 경로 수집 (재귀)
155
+ */
156
+ export async function safeGlobDir(
157
+ dirPath: string,
158
+ pattern?: RegExp
159
+ ): Promise<Result<string[]>> {
160
+ const result = await safeReadDirWithTypes(dirPath);
161
+ if (!result.ok) return result;
162
+
163
+ const files: string[] = [];
164
+ const subDirPromises: Promise<Result<string[]>>[] = [];
165
+
166
+ for (const entry of result.value) {
167
+ const fullPath = `${dirPath}/${entry.name}`;
168
+
169
+ if (entry.isDirectory()) {
170
+ subDirPromises.push(safeGlobDir(fullPath, pattern));
171
+ } else if (entry.isFile()) {
172
+ if (!pattern || pattern.test(entry.name)) {
173
+ files.push(fullPath);
174
+ }
175
+ }
176
+ }
177
+
178
+ // 서브 디렉토리 결과 수집
179
+ const subResults = await Promise.all(subDirPromises);
180
+ for (const subResult of subResults) {
181
+ if (subResult.ok) {
182
+ files.push(...subResult.value);
183
+ }
184
+ // 서브 디렉토리 에러는 무시 (접근 불가 디렉토리 스킵)
185
+ }
186
+
187
+ return ok(files);
188
+ }