@mandujs/core 0.12.1 → 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.
- package/README.ko.md +304 -304
- package/README.md +653 -653
- package/package.json +8 -8
- package/src/brain/architecture/analyzer.ts +28 -26
- package/src/brain/doctor/analyzer.ts +1 -1
- package/src/bundler/build.ts +91 -91
- package/src/bundler/css.ts +302 -302
- package/src/bundler/dev.ts +0 -1
- package/src/change/history.ts +3 -3
- package/src/change/snapshot.ts +10 -9
- package/src/change/transaction.ts +2 -2
- package/src/client/Link.tsx +227 -227
- package/src/client/globals.ts +44 -44
- package/src/client/hooks.ts +267 -267
- package/src/client/index.ts +5 -5
- package/src/client/island.ts +8 -8
- package/src/client/router.ts +435 -435
- package/src/client/runtime.ts +23 -23
- package/src/client/serialize.ts +404 -404
- package/src/client/window-state.ts +101 -101
- package/src/config/mandu.ts +94 -96
- package/src/config/validate.ts +213 -215
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/content-layer.ts +314 -314
- package/src/content/content.test.ts +433 -433
- package/src/content/data-store.ts +245 -245
- package/src/content/digest.ts +133 -133
- package/src/content/index.ts +164 -164
- package/src/content/loader-context.ts +172 -172
- package/src/content/loaders/api.ts +216 -216
- package/src/content/loaders/file.ts +169 -169
- package/src/content/loaders/glob.ts +252 -252
- package/src/content/loaders/index.ts +34 -34
- package/src/content/loaders/types.ts +137 -137
- package/src/content/meta-store.ts +209 -209
- package/src/content/types.ts +282 -282
- package/src/content/watcher.ts +135 -135
- package/src/contract/client-safe.test.ts +42 -42
- package/src/contract/client-safe.ts +114 -114
- package/src/contract/client.ts +16 -16
- package/src/contract/define.ts +459 -459
- package/src/contract/handler.ts +10 -10
- package/src/contract/normalize.test.ts +276 -276
- package/src/contract/normalize.ts +404 -404
- package/src/contract/registry.test.ts +206 -206
- package/src/contract/registry.ts +568 -568
- package/src/contract/schema.ts +48 -48
- package/src/contract/types.ts +58 -58
- package/src/contract/validator.ts +32 -32
- package/src/devtools/ai/context-builder.ts +375 -375
- package/src/devtools/ai/index.ts +25 -25
- package/src/devtools/ai/mcp-connector.ts +465 -465
- package/src/devtools/client/catchers/error-catcher.ts +327 -327
- package/src/devtools/client/catchers/index.ts +18 -18
- package/src/devtools/client/catchers/network-proxy.ts +363 -363
- package/src/devtools/client/components/index.ts +39 -39
- package/src/devtools/client/components/kitchen-root.tsx +362 -362
- package/src/devtools/client/components/mandu-character.tsx +241 -241
- package/src/devtools/client/components/overlay.tsx +368 -368
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
- package/src/devtools/client/components/panel/guard-panel.tsx +244 -244
- package/src/devtools/client/components/panel/index.ts +32 -32
- package/src/devtools/client/components/panel/islands-panel.tsx +304 -304
- package/src/devtools/client/components/panel/network-panel.tsx +292 -292
- package/src/devtools/client/components/panel/panel-container.tsx +259 -259
- package/src/devtools/client/filters/context-filters.ts +282 -282
- package/src/devtools/client/filters/index.ts +16 -16
- package/src/devtools/client/index.ts +63 -63
- package/src/devtools/client/persistence.ts +335 -335
- package/src/devtools/client/state-manager.ts +478 -478
- package/src/devtools/design-tokens.ts +263 -263
- package/src/devtools/hook/create-hook.ts +207 -207
- package/src/devtools/hook/index.ts +13 -13
- package/src/devtools/index.ts +439 -439
- package/src/devtools/init.ts +266 -266
- package/src/devtools/protocol.ts +237 -237
- package/src/devtools/server/index.ts +17 -17
- package/src/devtools/server/source-context.ts +444 -444
- package/src/devtools/types.ts +319 -319
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +222 -222
- package/src/devtools/worker/worker-manager.ts +409 -409
- package/src/error/classifier.ts +2 -2
- package/src/error/domains.ts +265 -265
- package/src/error/formatter.ts +32 -32
- package/src/error/result.ts +46 -46
- package/src/error/stack-analyzer.ts +5 -0
- package/src/error/types.ts +6 -6
- package/src/errors/extractor.ts +409 -409
- package/src/errors/index.ts +19 -19
- package/src/filling/auth.ts +308 -308
- package/src/filling/context.ts +569 -569
- package/src/filling/deps.ts +238 -238
- package/src/generator/contract-glue.ts +2 -1
- package/src/generator/generate.ts +12 -10
- package/src/generator/index.ts +3 -3
- package/src/generator/templates.ts +80 -79
- package/src/guard/analyzer.ts +360 -360
- package/src/guard/ast-analyzer.ts +806 -806
- package/src/guard/auto-correct.ts +1 -1
- package/src/guard/check.ts +128 -128
- package/src/guard/contract-guard.ts +9 -9
- package/src/guard/file-type.test.ts +24 -24
- package/src/guard/healing.ts +2 -0
- package/src/guard/index.ts +2 -0
- package/src/guard/negotiation.ts +430 -4
- package/src/guard/presets/atomic.ts +70 -70
- package/src/guard/presets/clean.ts +77 -77
- package/src/guard/presets/cqrs.test.ts +175 -0
- package/src/guard/presets/cqrs.ts +107 -0
- package/src/guard/presets/fsd.ts +79 -79
- package/src/guard/presets/hexagonal.ts +68 -68
- package/src/guard/presets/index.ts +291 -288
- package/src/guard/reporter.ts +445 -445
- package/src/guard/rules.ts +12 -12
- package/src/guard/statistics.ts +578 -578
- package/src/guard/suggestions.ts +358 -352
- package/src/guard/types.ts +348 -347
- package/src/guard/validator.ts +834 -834
- package/src/guard/watcher.ts +404 -404
- package/src/index.ts +1 -0
- package/src/intent/index.ts +310 -310
- package/src/island/index.ts +304 -304
- package/src/logging/index.ts +22 -22
- package/src/logging/transports.ts +365 -365
- package/src/paths.test.ts +47 -0
- package/src/paths.ts +47 -0
- package/src/plugins/index.ts +38 -38
- package/src/plugins/registry.ts +377 -377
- package/src/plugins/types.ts +363 -363
- package/src/report/build.ts +1 -1
- package/src/report/index.ts +1 -1
- package/src/router/fs-patterns.ts +387 -387
- package/src/router/fs-routes.ts +344 -401
- package/src/router/fs-scanner.ts +497 -497
- package/src/router/fs-types.ts +270 -278
- package/src/router/index.ts +81 -81
- package/src/runtime/boundary.tsx +232 -232
- package/src/runtime/compose.ts +222 -222
- package/src/runtime/lifecycle.ts +381 -381
- package/src/runtime/logger.test.ts +345 -345
- package/src/runtime/logger.ts +677 -677
- package/src/runtime/router.test.ts +476 -476
- package/src/runtime/router.ts +105 -105
- package/src/runtime/security.ts +155 -155
- package/src/runtime/server.ts +24 -24
- package/src/runtime/session-key.ts +328 -328
- package/src/runtime/ssr.ts +367 -367
- package/src/runtime/streaming-ssr.ts +1245 -1245
- package/src/runtime/trace.ts +144 -144
- package/src/seo/index.ts +214 -214
- package/src/seo/integration/ssr.ts +307 -307
- package/src/seo/render/basic.ts +427 -427
- package/src/seo/render/index.ts +143 -143
- package/src/seo/render/jsonld.ts +539 -539
- package/src/seo/render/opengraph.ts +191 -191
- package/src/seo/render/robots.ts +116 -116
- package/src/seo/render/sitemap.ts +137 -137
- package/src/seo/render/twitter.ts +126 -126
- package/src/seo/resolve/index.ts +353 -353
- package/src/seo/resolve/opengraph.ts +143 -143
- package/src/seo/resolve/robots.ts +73 -73
- package/src/seo/resolve/title.ts +94 -94
- package/src/seo/resolve/twitter.ts +73 -73
- package/src/seo/resolve/url.ts +97 -97
- package/src/seo/routes/index.ts +290 -290
- package/src/seo/types.ts +575 -575
- package/src/slot/validator.ts +39 -39
- package/src/spec/index.ts +3 -3
- package/src/spec/load.ts +76 -76
- package/src/spec/lock.ts +56 -56
- package/src/utils/bun.ts +8 -8
- package/src/utils/lru-cache.ts +75 -75
- package/src/utils/safe-io.ts +188 -188
- package/src/utils/string-safe.ts +298 -298
- package/src/watcher/rules.ts +5 -5
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 타입 안전 전역 상태 접근자
|
|
3
|
-
* window 객체 직접 접근 대신 이 모듈의 함수 사용
|
|
4
|
-
*/
|
|
5
|
-
import type { Root } from "react-dom/client";
|
|
6
|
-
import type { RouterState } from "./router";
|
|
7
|
-
|
|
8
|
-
// ============================================
|
|
9
|
-
// 환경 체크
|
|
10
|
-
// ============================================
|
|
11
|
-
|
|
12
|
-
export function isBrowser(): boolean {
|
|
13
|
-
return typeof window !== "undefined";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// ============================================
|
|
17
|
-
// Router State
|
|
18
|
-
// ============================================
|
|
19
|
-
|
|
20
|
-
export function getRouterState(): RouterState | undefined {
|
|
21
|
-
if (!isBrowser()) return undefined;
|
|
22
|
-
return window.__MANDU_ROUTER_STATE__;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function setRouterState(state: RouterState): void {
|
|
26
|
-
if (!isBrowser()) return;
|
|
27
|
-
window.__MANDU_ROUTER_STATE__ = state;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function getRouterListeners(): Set<(state: RouterState) => void> {
|
|
31
|
-
if (!isBrowser()) return new Set();
|
|
32
|
-
|
|
33
|
-
if (!window.__MANDU_ROUTER_LISTENERS__) {
|
|
34
|
-
window.__MANDU_ROUTER_LISTENERS__ = new Set();
|
|
35
|
-
}
|
|
36
|
-
return window.__MANDU_ROUTER_LISTENERS__;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ============================================
|
|
40
|
-
// Route & Data
|
|
41
|
-
// ============================================
|
|
42
|
-
|
|
43
|
-
export function getManduRoute():
|
|
44
|
-
| { id: string; pattern: string; params: Record<string, string> }
|
|
45
|
-
| undefined {
|
|
46
|
-
if (!isBrowser()) return undefined;
|
|
47
|
-
return window.__MANDU_ROUTE__;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function getManduData():
|
|
51
|
-
| Record<string, { serverData: unknown; timestamp?: number }>
|
|
52
|
-
| undefined {
|
|
53
|
-
if (!isBrowser()) return undefined;
|
|
54
|
-
return window.__MANDU_DATA__;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function getManduDataRaw(): string | undefined {
|
|
58
|
-
if (!isBrowser()) return undefined;
|
|
59
|
-
return window.__MANDU_DATA_RAW__;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 특정 라우트의 서버 데이터 조회 (타입 안전)
|
|
64
|
-
*/
|
|
65
|
-
export function getServerData<T>(routeId: string): T | undefined {
|
|
66
|
-
const data = getManduData();
|
|
67
|
-
return data?.[routeId]?.serverData as T | undefined;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* 서버 데이터 설정
|
|
72
|
-
*/
|
|
73
|
-
export function setServerData(routeId: string, data: unknown): void {
|
|
74
|
-
if (!isBrowser()) return;
|
|
75
|
-
|
|
76
|
-
if (!window.__MANDU_DATA__) {
|
|
77
|
-
window.__MANDU_DATA__ = {};
|
|
78
|
-
}
|
|
79
|
-
window.__MANDU_DATA__[routeId] = { serverData: data };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ============================================
|
|
83
|
-
// Hydration Roots
|
|
84
|
-
// ============================================
|
|
85
|
-
|
|
86
|
-
export function getHydratedRoots(): Map<string, Root> {
|
|
87
|
-
if (!isBrowser()) return new Map();
|
|
88
|
-
|
|
89
|
-
if (!window.__MANDU_ROOTS__) {
|
|
90
|
-
window.__MANDU_ROOTS__ = new Map();
|
|
91
|
-
}
|
|
92
|
-
return window.__MANDU_ROOTS__;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function setHydratedRoot(id: string, root: Root): void {
|
|
96
|
-
getHydratedRoots().set(id, root);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function removeHydratedRoot(id: string): boolean {
|
|
100
|
-
return getHydratedRoots().delete(id);
|
|
101
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 타입 안전 전역 상태 접근자
|
|
3
|
+
* window 객체 직접 접근 대신 이 모듈의 함수 사용
|
|
4
|
+
*/
|
|
5
|
+
import type { Root } from "react-dom/client";
|
|
6
|
+
import type { RouterState } from "./router";
|
|
7
|
+
|
|
8
|
+
// ============================================
|
|
9
|
+
// 환경 체크
|
|
10
|
+
// ============================================
|
|
11
|
+
|
|
12
|
+
export function isBrowser(): boolean {
|
|
13
|
+
return typeof window !== "undefined";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// Router State
|
|
18
|
+
// ============================================
|
|
19
|
+
|
|
20
|
+
export function getRouterState(): RouterState | undefined {
|
|
21
|
+
if (!isBrowser()) return undefined;
|
|
22
|
+
return window.__MANDU_ROUTER_STATE__;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function setRouterState(state: RouterState): void {
|
|
26
|
+
if (!isBrowser()) return;
|
|
27
|
+
window.__MANDU_ROUTER_STATE__ = state;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getRouterListeners(): Set<(state: RouterState) => void> {
|
|
31
|
+
if (!isBrowser()) return new Set();
|
|
32
|
+
|
|
33
|
+
if (!window.__MANDU_ROUTER_LISTENERS__) {
|
|
34
|
+
window.__MANDU_ROUTER_LISTENERS__ = new Set();
|
|
35
|
+
}
|
|
36
|
+
return window.__MANDU_ROUTER_LISTENERS__;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ============================================
|
|
40
|
+
// Route & Data
|
|
41
|
+
// ============================================
|
|
42
|
+
|
|
43
|
+
export function getManduRoute():
|
|
44
|
+
| { id: string; pattern: string; params: Record<string, string> }
|
|
45
|
+
| undefined {
|
|
46
|
+
if (!isBrowser()) return undefined;
|
|
47
|
+
return window.__MANDU_ROUTE__;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function getManduData():
|
|
51
|
+
| Record<string, { serverData: unknown; timestamp?: number }>
|
|
52
|
+
| undefined {
|
|
53
|
+
if (!isBrowser()) return undefined;
|
|
54
|
+
return window.__MANDU_DATA__;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getManduDataRaw(): string | undefined {
|
|
58
|
+
if (!isBrowser()) return undefined;
|
|
59
|
+
return window.__MANDU_DATA_RAW__;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 특정 라우트의 서버 데이터 조회 (타입 안전)
|
|
64
|
+
*/
|
|
65
|
+
export function getServerData<T>(routeId: string): T | undefined {
|
|
66
|
+
const data = getManduData();
|
|
67
|
+
return data?.[routeId]?.serverData as T | undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 서버 데이터 설정
|
|
72
|
+
*/
|
|
73
|
+
export function setServerData(routeId: string, data: unknown): void {
|
|
74
|
+
if (!isBrowser()) return;
|
|
75
|
+
|
|
76
|
+
if (!window.__MANDU_DATA__) {
|
|
77
|
+
window.__MANDU_DATA__ = {};
|
|
78
|
+
}
|
|
79
|
+
window.__MANDU_DATA__[routeId] = { serverData: data };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ============================================
|
|
83
|
+
// Hydration Roots
|
|
84
|
+
// ============================================
|
|
85
|
+
|
|
86
|
+
export function getHydratedRoots(): Map<string, Root> {
|
|
87
|
+
if (!isBrowser()) return new Map();
|
|
88
|
+
|
|
89
|
+
if (!window.__MANDU_ROOTS__) {
|
|
90
|
+
window.__MANDU_ROOTS__ = new Map();
|
|
91
|
+
}
|
|
92
|
+
return window.__MANDU_ROOTS__;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function setHydratedRoot(id: string, root: Root): void {
|
|
96
|
+
getHydratedRoots().set(id, root);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function removeHydratedRoot(id: string): boolean {
|
|
100
|
+
return getHydratedRoots().delete(id);
|
|
101
|
+
}
|
package/src/config/mandu.ts
CHANGED
|
@@ -1,96 +1,94 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import { readJsonFile } from "../utils/bun";
|
|
3
|
-
|
|
4
|
-
export type GuardRuleSeverity = "error" | "warn" | "warning" | "off";
|
|
5
|
-
|
|
6
|
-
export interface ManduConfig {
|
|
7
|
-
server?: {
|
|
8
|
-
port?: number;
|
|
9
|
-
hostname?: string;
|
|
10
|
-
cors?:
|
|
11
|
-
| boolean
|
|
12
|
-
| {
|
|
13
|
-
origin?: string | string[];
|
|
14
|
-
methods?: string[];
|
|
15
|
-
credentials?: boolean;
|
|
16
|
-
};
|
|
17
|
-
streaming?: boolean;
|
|
18
|
-
};
|
|
19
|
-
guard?: {
|
|
20
|
-
preset?: "mandu" | "fsd" | "clean" | "hexagonal" | "atomic";
|
|
21
|
-
srcDir?: string;
|
|
22
|
-
exclude?: string[];
|
|
23
|
-
realtime?: boolean;
|
|
24
|
-
rules?: Record<string, GuardRuleSeverity>;
|
|
25
|
-
contractRequired?: GuardRuleSeverity;
|
|
26
|
-
};
|
|
27
|
-
build?: {
|
|
28
|
-
outDir?: string;
|
|
29
|
-
minify?: boolean;
|
|
30
|
-
sourcemap?: boolean;
|
|
31
|
-
splitting?: boolean;
|
|
32
|
-
};
|
|
33
|
-
dev?: {
|
|
34
|
-
hmr?: boolean;
|
|
35
|
-
watchDirs?: string[];
|
|
36
|
-
};
|
|
37
|
-
fsRoutes?: {
|
|
38
|
-
routesDir?: string;
|
|
39
|
-
extensions?: string[];
|
|
40
|
-
exclude?: string[];
|
|
41
|
-
islandSuffix?: string;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"mandu.config.
|
|
54
|
-
"mandu.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return {};
|
|
96
|
-
}
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { readJsonFile } from "../utils/bun";
|
|
3
|
+
|
|
4
|
+
export type GuardRuleSeverity = "error" | "warn" | "warning" | "off";
|
|
5
|
+
|
|
6
|
+
export interface ManduConfig {
|
|
7
|
+
server?: {
|
|
8
|
+
port?: number;
|
|
9
|
+
hostname?: string;
|
|
10
|
+
cors?:
|
|
11
|
+
| boolean
|
|
12
|
+
| {
|
|
13
|
+
origin?: string | string[];
|
|
14
|
+
methods?: string[];
|
|
15
|
+
credentials?: boolean;
|
|
16
|
+
};
|
|
17
|
+
streaming?: boolean;
|
|
18
|
+
};
|
|
19
|
+
guard?: {
|
|
20
|
+
preset?: "mandu" | "fsd" | "clean" | "hexagonal" | "atomic";
|
|
21
|
+
srcDir?: string;
|
|
22
|
+
exclude?: string[];
|
|
23
|
+
realtime?: boolean;
|
|
24
|
+
rules?: Record<string, GuardRuleSeverity>;
|
|
25
|
+
contractRequired?: GuardRuleSeverity;
|
|
26
|
+
};
|
|
27
|
+
build?: {
|
|
28
|
+
outDir?: string;
|
|
29
|
+
minify?: boolean;
|
|
30
|
+
sourcemap?: boolean;
|
|
31
|
+
splitting?: boolean;
|
|
32
|
+
};
|
|
33
|
+
dev?: {
|
|
34
|
+
hmr?: boolean;
|
|
35
|
+
watchDirs?: string[];
|
|
36
|
+
};
|
|
37
|
+
fsRoutes?: {
|
|
38
|
+
routesDir?: string;
|
|
39
|
+
extensions?: string[];
|
|
40
|
+
exclude?: string[];
|
|
41
|
+
islandSuffix?: string;
|
|
42
|
+
};
|
|
43
|
+
seo?: {
|
|
44
|
+
enabled?: boolean;
|
|
45
|
+
defaultTitle?: string;
|
|
46
|
+
titleTemplate?: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const CONFIG_FILES = [
|
|
51
|
+
"mandu.config.ts",
|
|
52
|
+
"mandu.config.js",
|
|
53
|
+
"mandu.config.json",
|
|
54
|
+
path.join(".mandu", "guard.json"),
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
export function coerceConfig(raw: unknown, source: string): ManduConfig {
|
|
58
|
+
if (!raw || typeof raw !== "object") return {};
|
|
59
|
+
|
|
60
|
+
// .mandu/guard.json can be guard-only
|
|
61
|
+
if (source.endsWith("guard.json") && !("guard" in (raw as Record<string, unknown>))) {
|
|
62
|
+
return { guard: raw as ManduConfig["guard"] };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return raw as ManduConfig;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function loadManduConfig(rootDir: string): Promise<ManduConfig> {
|
|
69
|
+
for (const fileName of CONFIG_FILES) {
|
|
70
|
+
const filePath = path.join(rootDir, fileName);
|
|
71
|
+
if (!(await Bun.file(filePath).exists())) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (fileName.endsWith(".json")) {
|
|
76
|
+
try {
|
|
77
|
+
const parsed = await readJsonFile(filePath);
|
|
78
|
+
return coerceConfig(parsed, fileName);
|
|
79
|
+
} catch {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const module = await import(filePath);
|
|
86
|
+
const raw = module?.default ?? module;
|
|
87
|
+
return coerceConfig(raw, fileName);
|
|
88
|
+
} catch {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {};
|
|
94
|
+
}
|