@jogak/core 0.1.0-alpha.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 +86 -0
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/actions.d.ts +22 -0
- package/dist/build/generate.d.ts +22 -0
- package/dist/build/index.d.ts +2 -0
- package/dist/build/index.js +72 -0
- package/dist/build/index.mjs +101 -0
- package/dist/extractor-client-CReBed7x.js +134 -0
- package/dist/extractor-client-CiWszHel.cjs +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +417 -0
- package/dist/meta/extract-core.d.ts +42 -0
- package/dist/meta/extract-props.d.ts +42 -0
- package/dist/meta/extractor-child.d.ts +1 -0
- package/dist/meta/extractor-child.js +1 -0
- package/dist/meta/extractor-child.mjs +305 -0
- package/dist/meta/extractor-client.d.ts +2 -0
- package/dist/registry.d.ts +86 -0
- package/dist/types.d.ts +142 -0
- package/dist/vite/cache-validate.d.ts +17 -0
- package/dist/vite/index.js +41 -0
- package/dist/vite/index.mjs +277 -0
- package/dist/vite/plugin.d.ts +3 -0
- package/dist/vite/virtual-ids.d.ts +19 -0
- package/package.json +82 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
var $ = Object.defineProperty;
|
|
2
|
+
var C = (s) => {
|
|
3
|
+
throw TypeError(s);
|
|
4
|
+
};
|
|
5
|
+
var q = (s, t, e) => t in s ? $(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
|
|
6
|
+
var z = (s, t, e) => q(s, typeof t != "symbol" ? t + "" : t, e), b = (s, t, e) => t.has(s) || C("Cannot " + e);
|
|
7
|
+
var i = (s, t, e) => (b(s, t, "read from private field"), e ? e.call(s) : t.get(s)), g = (s, t, e) => t.has(s) ? C("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(s) : t.set(s, e), l = (s, t, e, n) => (b(s, t, "write to private field"), n ? n.call(s, e) : t.set(s, e), e), u = (s, t, e) => (b(s, t, "access private method"), e);
|
|
8
|
+
var F = (s, t, e, n) => ({
|
|
9
|
+
set _(o) {
|
|
10
|
+
l(s, t, o, e);
|
|
11
|
+
},
|
|
12
|
+
get _() {
|
|
13
|
+
return i(s, t, n);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
class L extends Error {
|
|
17
|
+
constructor(e) {
|
|
18
|
+
super(`[jogak] Unknown entry id: ${e}`);
|
|
19
|
+
z(this, "id");
|
|
20
|
+
this.name = "UnknownEntryError", this.id = e;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
var a, T, j, k, v, E, w, d, m, N;
|
|
24
|
+
class D {
|
|
25
|
+
constructor() {
|
|
26
|
+
g(this, d);
|
|
27
|
+
g(this, a, /* @__PURE__ */ new Map());
|
|
28
|
+
g(this, T);
|
|
29
|
+
// ── F2: subscribe + 내부 캐시 ────────────────────────────────────────
|
|
30
|
+
g(this, j, /* @__PURE__ */ new Set());
|
|
31
|
+
g(this, k);
|
|
32
|
+
g(this, v);
|
|
33
|
+
/** register()가 registerMeta + hydrateEntry를 합쳐 호출할 때 중간 notify를 억제한다. */
|
|
34
|
+
g(this, E, !1);
|
|
35
|
+
/** batch 도중에 mutation이 한 번이라도 일어났는지 — false면 batch 종료 시 notify 안 한다. */
|
|
36
|
+
g(this, w, !1);
|
|
37
|
+
}
|
|
38
|
+
// ── 기존 외부 API: 시그니처 변경 없음. 시맨틱은 hydrated만 표면. ───────────
|
|
39
|
+
/**
|
|
40
|
+
* 즉시 hydrated 상태로 entry를 등록한다.
|
|
41
|
+
* 정적 빌드(`generateRegistryFile` 결과) / 테스트 / 기존 호출자 호환 경로.
|
|
42
|
+
*
|
|
43
|
+
* 내부 구현은 `registerMeta` + `hydrateEntry`의 compatibility shim.
|
|
44
|
+
* 두 mutation은 batch로 묶여 단일 notify만 발생한다.
|
|
45
|
+
*/
|
|
46
|
+
register(t) {
|
|
47
|
+
const e = O(t);
|
|
48
|
+
u(this, d, N).call(this, () => {
|
|
49
|
+
this.registerMeta(e), this.hydrateEntry(t.id, t.jogaks, t.meta.component);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
unregister(t) {
|
|
53
|
+
const e = i(this, a).get(t);
|
|
54
|
+
e !== void 0 && (e.kind === "pending" && e.reject(new L(t)), i(this, a).delete(t), u(this, d, m).call(this));
|
|
55
|
+
}
|
|
56
|
+
/** hydrated일 때만 RegistryEntry를 반환한다. meta-only/pending이면 undefined. */
|
|
57
|
+
get(t) {
|
|
58
|
+
const e = i(this, a).get(t);
|
|
59
|
+
return (e == null ? void 0 : e.kind) === "hydrated" ? e.entry : void 0;
|
|
60
|
+
}
|
|
61
|
+
/** hydrated 항목만 반환. meta-only는 `getAllMeta()` 사용. */
|
|
62
|
+
getAll() {
|
|
63
|
+
const t = [];
|
|
64
|
+
for (const e of i(this, a).values())
|
|
65
|
+
e.kind === "hydrated" && t.push(e.entry);
|
|
66
|
+
return t;
|
|
67
|
+
}
|
|
68
|
+
search(t) {
|
|
69
|
+
const e = t.toLowerCase();
|
|
70
|
+
return this.getAll().filter((n) => n.title.toLowerCase().includes(e));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* title의 '/' 구분자로 hydrated entry만의 계층 트리를 구성한다.
|
|
74
|
+
*/
|
|
75
|
+
getTree() {
|
|
76
|
+
const t = {};
|
|
77
|
+
for (const e of this.getAll()) {
|
|
78
|
+
const n = e.title.split("/");
|
|
79
|
+
let o = t;
|
|
80
|
+
for (let h = 0; h < n.length - 1; h++) {
|
|
81
|
+
const c = n[h];
|
|
82
|
+
if (c === void 0) continue;
|
|
83
|
+
const f = o[c];
|
|
84
|
+
(f === void 0 || "id" in f) && (o[c] = {}), o = o[c];
|
|
85
|
+
}
|
|
86
|
+
const r = n[n.length - 1];
|
|
87
|
+
r !== void 0 && (o[r] = e);
|
|
88
|
+
}
|
|
89
|
+
return t;
|
|
90
|
+
}
|
|
91
|
+
clear() {
|
|
92
|
+
if (i(this, a).size !== 0) {
|
|
93
|
+
for (const t of i(this, a).values())
|
|
94
|
+
t.kind === "pending" && t.reject(new Error("[jogak] registry cleared"));
|
|
95
|
+
i(this, a).clear(), u(this, d, m).call(this);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** hydrated 개수. */
|
|
99
|
+
get size() {
|
|
100
|
+
let t = 0;
|
|
101
|
+
for (const e of i(this, a).values())
|
|
102
|
+
e.kind === "hydrated" && t++;
|
|
103
|
+
return t;
|
|
104
|
+
}
|
|
105
|
+
// ── NEW: 메타 / lazy API ─────────────────────────────────────────────
|
|
106
|
+
/**
|
|
107
|
+
* 인덱스 가상모듈이 호출. 기존 hydrated 항목이 있으면 meta만 갱신(HMR) — entry는 보존.
|
|
108
|
+
* meta 등록만으로는 `getAll()` 결과에 안 들어간다.
|
|
109
|
+
*/
|
|
110
|
+
registerMeta(t) {
|
|
111
|
+
const e = i(this, a).get(t.id);
|
|
112
|
+
if (e === void 0) {
|
|
113
|
+
i(this, a).set(t.id, { kind: "meta", meta: t }), u(this, d, m).call(this);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (e.kind === "meta") {
|
|
117
|
+
i(this, a).set(t.id, { kind: "meta", meta: t }), u(this, d, m).call(this);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (e.kind === "pending") {
|
|
121
|
+
i(this, a).set(t.id, {
|
|
122
|
+
kind: "pending",
|
|
123
|
+
meta: t,
|
|
124
|
+
promise: e.promise,
|
|
125
|
+
resolve: e.resolve,
|
|
126
|
+
reject: e.reject
|
|
127
|
+
}), u(this, d, m).call(this);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const n = {
|
|
131
|
+
...e.entry,
|
|
132
|
+
title: t.title,
|
|
133
|
+
filePath: t.filePath,
|
|
134
|
+
source: t.source,
|
|
135
|
+
meta: S(t, e.entry.meta.component)
|
|
136
|
+
};
|
|
137
|
+
i(this, a).set(t.id, { kind: "hydrated", meta: t, entry: n }), u(this, d, m).call(this);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* entry 가상모듈이 호출. pending Promise들을 resolve.
|
|
141
|
+
* meta가 없는 상태에서 호출되면(=직접 import) 임시 meta를 합성한다 (defensive).
|
|
142
|
+
*/
|
|
143
|
+
hydrateEntry(t, e, n) {
|
|
144
|
+
const o = i(this, a).get(t);
|
|
145
|
+
let r;
|
|
146
|
+
o === void 0 ? (console.warn(
|
|
147
|
+
`[jogak] hydrateEntry called for unknown id "${t}" — synthesizing minimal meta`
|
|
148
|
+
), r = {
|
|
149
|
+
id: t,
|
|
150
|
+
title: t,
|
|
151
|
+
jogakNames: e.map((c) => c.name),
|
|
152
|
+
autoArgTypes: {},
|
|
153
|
+
userArgTypes: {},
|
|
154
|
+
source: "",
|
|
155
|
+
filePath: "",
|
|
156
|
+
metaExtras: {}
|
|
157
|
+
}) : r = o.meta;
|
|
158
|
+
const h = {
|
|
159
|
+
id: r.id,
|
|
160
|
+
title: r.title,
|
|
161
|
+
jogaks: e,
|
|
162
|
+
meta: S(r, n),
|
|
163
|
+
...r.filePath ? { filePath: r.filePath } : {},
|
|
164
|
+
...r.source ? { source: r.source } : {}
|
|
165
|
+
};
|
|
166
|
+
if ((o == null ? void 0 : o.kind) === "pending") {
|
|
167
|
+
i(this, a).set(t, { kind: "hydrated", meta: r, entry: h }), u(this, d, m).call(this), o.resolve(h);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
i(this, a).set(t, { kind: "hydrated", meta: r, entry: h }), u(this, d, m).call(this);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 어댑터가 호출. hydrated였던 entry를 meta 상태로 되돌린다.
|
|
174
|
+
* HMR meta-update 이벤트에서 args/component 변경을 강제 re-hydrate 시키기 위함.
|
|
175
|
+
* unknown / meta / pending 상태에는 영향 없음.
|
|
176
|
+
*/
|
|
177
|
+
invalidateEntry(t) {
|
|
178
|
+
const e = i(this, a).get(t);
|
|
179
|
+
e === void 0 || e.kind !== "hydrated" || (i(this, a).set(t, { kind: "meta", meta: e.meta }), u(this, d, m).call(this));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* UI/어댑터가 호출. entry id로 완전한 RegistryEntry를 비동기 획득.
|
|
183
|
+
*
|
|
184
|
+
* - hydrated → 즉시 resolve된 Promise
|
|
185
|
+
* - pending → 기존 Promise 반환 (멱등)
|
|
186
|
+
* - meta → loader 트리거 후 새 Promise 반환, 상태를 pending으로
|
|
187
|
+
* - unknown → 즉시 reject (UnknownEntryError)
|
|
188
|
+
*/
|
|
189
|
+
requestEntry(t) {
|
|
190
|
+
const e = i(this, a).get(t);
|
|
191
|
+
if (e === void 0)
|
|
192
|
+
return Promise.reject(new L(t));
|
|
193
|
+
if (e.kind === "hydrated")
|
|
194
|
+
return Promise.resolve(e.entry);
|
|
195
|
+
if (e.kind === "pending")
|
|
196
|
+
return e.promise;
|
|
197
|
+
const n = i(this, T);
|
|
198
|
+
if (n === void 0)
|
|
199
|
+
return Promise.reject(
|
|
200
|
+
new Error(
|
|
201
|
+
"[jogak] entry loader not set — virtual:jogak index module did not load"
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
let o, r;
|
|
205
|
+
const h = new Promise((c, f) => {
|
|
206
|
+
o = c, r = f;
|
|
207
|
+
});
|
|
208
|
+
return i(this, a).set(t, {
|
|
209
|
+
kind: "pending",
|
|
210
|
+
meta: e.meta,
|
|
211
|
+
promise: h,
|
|
212
|
+
resolve: o,
|
|
213
|
+
reject: r
|
|
214
|
+
}), n(t).then(
|
|
215
|
+
() => {
|
|
216
|
+
const c = i(this, a).get(t);
|
|
217
|
+
(c == null ? void 0 : c.kind) !== "hydrated" && r(
|
|
218
|
+
new Error(`[jogak] entry module loaded but did not hydrate: ${t}`)
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
(c) => {
|
|
222
|
+
const f = c instanceof Error ? c : new Error(String(c)), p = i(this, a).get(t);
|
|
223
|
+
(p == null ? void 0 : p.kind) === "pending" && p.promise === h && i(this, a).set(t, { kind: "meta", meta: e.meta }), r(f);
|
|
224
|
+
}
|
|
225
|
+
), h;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* 사이드바 메타 전용 — meta-only / pending / hydrated 모두 포함.
|
|
229
|
+
*
|
|
230
|
+
* F2: 내부 캐시. mutation 시점에 invalidate되며 재계산 전까지 동일 reference를 반환한다.
|
|
231
|
+
* useSyncExternalStore의 referential identity 요구를 만족시키기 위함.
|
|
232
|
+
*/
|
|
233
|
+
getAllMeta() {
|
|
234
|
+
if (i(this, k) !== void 0) return i(this, k);
|
|
235
|
+
const t = [];
|
|
236
|
+
for (const n of i(this, a).values())
|
|
237
|
+
t.push(n.meta);
|
|
238
|
+
const e = t;
|
|
239
|
+
return l(this, k, e), e;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* 사이드바 트리 전용 — 모든 상태의 meta를 트리화.
|
|
243
|
+
* F2: getAllMeta와 동일한 캐시 정책.
|
|
244
|
+
*/
|
|
245
|
+
getMetaTree() {
|
|
246
|
+
if (i(this, v) !== void 0) return i(this, v);
|
|
247
|
+
const t = {};
|
|
248
|
+
for (const e of i(this, a).values()) {
|
|
249
|
+
const n = e.meta, o = n.title.split("/");
|
|
250
|
+
let r = t;
|
|
251
|
+
for (let c = 0; c < o.length - 1; c++) {
|
|
252
|
+
const f = o[c];
|
|
253
|
+
if (f === void 0) continue;
|
|
254
|
+
const p = r[f];
|
|
255
|
+
(p === void 0 || "id" in p) && (r[f] = {}), r = r[f];
|
|
256
|
+
}
|
|
257
|
+
const h = o[o.length - 1];
|
|
258
|
+
h !== void 0 && (r[h] = n);
|
|
259
|
+
}
|
|
260
|
+
return l(this, v, t), t;
|
|
261
|
+
}
|
|
262
|
+
/** 진단 — 상태 머신 노출. */
|
|
263
|
+
getEntryState(t) {
|
|
264
|
+
const e = i(this, a).get(t);
|
|
265
|
+
return e === void 0 ? "unknown" : e.kind;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* dynamic import 함수를 외부에서 주입. plugin이 인덱스 모듈에서 호출한다.
|
|
269
|
+
* 빌드/SSR에서 정적 import 매핑으로 교체할 때도 사용.
|
|
270
|
+
*/
|
|
271
|
+
setEntryLoader(t) {
|
|
272
|
+
l(this, T, t);
|
|
273
|
+
}
|
|
274
|
+
// ── F2: subscribe API ────────────────────────────────────────────────
|
|
275
|
+
/**
|
|
276
|
+
* 등록/해제/메타 갱신/hydrate/clear 시 호출되는 listener를 등록한다.
|
|
277
|
+
*
|
|
278
|
+
* - listener는 무인자, 동기 호출. 어떤 변화가 있었는지는 listener가
|
|
279
|
+
* `getAllMeta()`/`getMetaTree()`로 직접 확인.
|
|
280
|
+
* - mutation 도중 listener에서 `subscribe`/`unsubscribe`를 호출하는 재진입은
|
|
281
|
+
* 안전 (내부적으로 listener Set을 한 번 복사한 뒤 순회).
|
|
282
|
+
* - listener 예외는 catch + console.error 후 계속 (다른 listener 보장).
|
|
283
|
+
* - 반환값은 unsubscribe 함수 (멱등 — 두 번 호출해도 안전).
|
|
284
|
+
*/
|
|
285
|
+
subscribe(t) {
|
|
286
|
+
i(this, j).add(t);
|
|
287
|
+
let e = !0;
|
|
288
|
+
return () => {
|
|
289
|
+
e && (e = !1, i(this, j).delete(t));
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
a = new WeakMap(), T = new WeakMap(), j = new WeakMap(), k = new WeakMap(), v = new WeakMap(), E = new WeakMap(), w = new WeakMap(), d = new WeakSet(), // ── 내부 헬퍼 ─────────────────────────────────────────────────────────
|
|
294
|
+
/**
|
|
295
|
+
* 캐시 invalidate + listener 통지를 단일 헬퍼로.
|
|
296
|
+
* batch 모드에서는 dirty 플래그만 켜고 실제 통지는 batch 종료 시점에 한다.
|
|
297
|
+
*/
|
|
298
|
+
m = function() {
|
|
299
|
+
if (l(this, k, void 0), l(this, v, void 0), i(this, E)) {
|
|
300
|
+
l(this, w, !0);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const t = Array.from(i(this, j));
|
|
304
|
+
for (const e of t)
|
|
305
|
+
try {
|
|
306
|
+
e();
|
|
307
|
+
} catch (n) {
|
|
308
|
+
console.error("[jogak] subscribe listener threw:", n);
|
|
309
|
+
}
|
|
310
|
+
}, /**
|
|
311
|
+
* register() 처럼 여러 mutation을 묶어 단일 notify로 처리.
|
|
312
|
+
* 내부 전용 — public API 아님.
|
|
313
|
+
*/
|
|
314
|
+
N = function(t) {
|
|
315
|
+
if (i(this, E)) {
|
|
316
|
+
t();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
l(this, E, !0), l(this, w, !1);
|
|
320
|
+
try {
|
|
321
|
+
t();
|
|
322
|
+
} finally {
|
|
323
|
+
l(this, E, !1), i(this, w) && (l(this, w, !1), u(this, d, m).call(this));
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
function O(s) {
|
|
327
|
+
const t = s.meta.argTypes ?? {};
|
|
328
|
+
return {
|
|
329
|
+
id: s.id,
|
|
330
|
+
title: s.title,
|
|
331
|
+
jogakNames: s.jogaks.map((e) => e.name),
|
|
332
|
+
autoArgTypes: {},
|
|
333
|
+
userArgTypes: t,
|
|
334
|
+
source: s.source ?? "",
|
|
335
|
+
filePath: s.filePath ?? "",
|
|
336
|
+
metaExtras: {
|
|
337
|
+
...s.meta.tags !== void 0 ? { tags: s.meta.tags } : {},
|
|
338
|
+
...s.meta.parameters !== void 0 ? { parameters: s.meta.parameters } : {}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function S(s, t) {
|
|
343
|
+
const e = {
|
|
344
|
+
...s.autoArgTypes
|
|
345
|
+
};
|
|
346
|
+
for (const n of Object.keys(s.userArgTypes)) {
|
|
347
|
+
const o = s.userArgTypes[n];
|
|
348
|
+
o !== void 0 && (e[n] = { ...e[n], ...o });
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
title: s.title,
|
|
352
|
+
component: t,
|
|
353
|
+
argTypes: e,
|
|
354
|
+
...s.metaExtras.tags !== void 0 ? { tags: s.metaExtras.tags } : {},
|
|
355
|
+
...s.metaExtras.parameters !== void 0 ? { parameters: s.metaExtras.parameters } : {}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
const J = new D();
|
|
359
|
+
var y, A, P, x, M;
|
|
360
|
+
class R {
|
|
361
|
+
constructor() {
|
|
362
|
+
g(this, x);
|
|
363
|
+
g(this, y, []);
|
|
364
|
+
g(this, A, /* @__PURE__ */ new Set());
|
|
365
|
+
g(this, P, 1);
|
|
366
|
+
}
|
|
367
|
+
emit(t, e) {
|
|
368
|
+
const n = {
|
|
369
|
+
id: F(this, P)._++,
|
|
370
|
+
name: t,
|
|
371
|
+
args: e,
|
|
372
|
+
timestamp: Date.now()
|
|
373
|
+
};
|
|
374
|
+
l(this, y, [...i(this, y), n]), u(this, x, M).call(this);
|
|
375
|
+
}
|
|
376
|
+
subscribe(t) {
|
|
377
|
+
return i(this, A).add(t), t(i(this, y)), () => {
|
|
378
|
+
i(this, A).delete(t);
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
clear() {
|
|
382
|
+
i(this, y).length !== 0 && (l(this, y, []), u(this, x, M).call(this));
|
|
383
|
+
}
|
|
384
|
+
getLogs() {
|
|
385
|
+
return i(this, y);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
y = new WeakMap(), A = new WeakMap(), P = new WeakMap(), x = new WeakSet(), M = function() {
|
|
389
|
+
for (const t of i(this, A)) t(i(this, y));
|
|
390
|
+
};
|
|
391
|
+
const U = new R();
|
|
392
|
+
function B(s, t = U) {
|
|
393
|
+
return (...e) => {
|
|
394
|
+
t.emit(s, e);
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
function V(s, t, e = U) {
|
|
398
|
+
const n = { ...s };
|
|
399
|
+
for (const o of Object.keys(t)) {
|
|
400
|
+
const r = t[o];
|
|
401
|
+
if (r === void 0) continue;
|
|
402
|
+
const h = r.action !== void 0 && r.action !== !1, c = r.type === "function";
|
|
403
|
+
if (!h && !c || typeof n[o] == "function") continue;
|
|
404
|
+
const f = typeof r.action == "string" ? r.action : o;
|
|
405
|
+
n[o] = B(f, e);
|
|
406
|
+
}
|
|
407
|
+
return n;
|
|
408
|
+
}
|
|
409
|
+
export {
|
|
410
|
+
R as ActionChannel,
|
|
411
|
+
D as ComponentRegistry,
|
|
412
|
+
L as UnknownEntryError,
|
|
413
|
+
B as action,
|
|
414
|
+
U as defaultActionChannel,
|
|
415
|
+
J as defaultRegistry,
|
|
416
|
+
V as injectActions
|
|
417
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SourceFile } from 'ts-morph';
|
|
2
|
+
import { ArgType } from '../types.js';
|
|
3
|
+
export interface ExtractCoreOptions {
|
|
4
|
+
readonly tsConfigFilePath?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* 인덱스 가상모듈에 들어갈 메타 정보 (직렬화 가능 부분만).
|
|
8
|
+
* `RegistryEntryMeta`의 일부와 1:1 — registry import를 피하기 위해 분리 정의.
|
|
9
|
+
*/
|
|
10
|
+
export interface ExtractedMeta {
|
|
11
|
+
readonly title: string;
|
|
12
|
+
readonly jogakNames: readonly string[];
|
|
13
|
+
readonly userArgTypes: Readonly<Record<string, ArgType>>;
|
|
14
|
+
readonly metaExtras: {
|
|
15
|
+
readonly tags?: readonly string[];
|
|
16
|
+
readonly parameters?: Readonly<Record<string, unknown>>;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface InProcessExtractor {
|
|
20
|
+
extract(filePath: string): Record<string, ArgType>;
|
|
21
|
+
extractMeta(filePath: string): ExtractedMeta | undefined;
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* ts-morph Project를 단일 V8 isolate 안에서 보유하는 동기 추출기.
|
|
26
|
+
*
|
|
27
|
+
* 메모리 노트: skipAddingFilesFromTsConfig:true 는 RSS를 오히려 악화시킴
|
|
28
|
+
* (size=500에서 1035MB → 1674MB). typeChecker가 lazy 로딩으로 의존 파일을
|
|
29
|
+
* 매번 재해석하면서 Program이 커지기 때문. tsconfig include 일괄 로딩이
|
|
30
|
+
* 안정적이며, 자식 프로세스 단위 dispose가 RSS 회수에 가장 효과적.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createInProcessExtractor(options?: ExtractCoreOptions): InProcessExtractor;
|
|
33
|
+
export declare function extractFromSourceFile(sourceFile: SourceFile): Record<string, ArgType>;
|
|
34
|
+
/**
|
|
35
|
+
* 인덱스 가상모듈용 메타 추출.
|
|
36
|
+
*
|
|
37
|
+
* - default export(`Meta`)에서 `title`, `argTypes`(직렬화 가능 부분), `tags`, `parameters` 추출
|
|
38
|
+
* - named export 중 `name`이 string-literal인 객체들의 `name` 목록 추출
|
|
39
|
+
*
|
|
40
|
+
* 직렬화 불가능한 값(함수 reference 등)은 안전하게 빈 객체/생략으로 처리한다.
|
|
41
|
+
*/
|
|
42
|
+
export declare function extractMetaFromSourceFile(sourceFile: SourceFile): ExtractedMeta | undefined;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ArgType } from '../types.js';
|
|
2
|
+
export interface PropsExtractorOptions {
|
|
3
|
+
readonly tsConfigFilePath?: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* 자식 프로세스 RPC가 돌려보내는 메타 페이로드 — 직렬화 가능한 부분만.
|
|
7
|
+
* `RegistryEntryMeta`의 일부와 1:1 (id/source/filePath/autoArgTypes는 부모가 채운다).
|
|
8
|
+
*/
|
|
9
|
+
export interface ExtractedMetaPayload {
|
|
10
|
+
readonly title: string;
|
|
11
|
+
readonly jogakNames: readonly string[];
|
|
12
|
+
readonly userArgTypes: Readonly<Record<string, ArgType>>;
|
|
13
|
+
readonly metaExtras: {
|
|
14
|
+
readonly tags?: readonly string[];
|
|
15
|
+
readonly parameters?: Readonly<Record<string, unknown>>;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface PropsExtractor {
|
|
19
|
+
/**
|
|
20
|
+
* 단일 jogak 파일을 받아 props 메타데이터를 추출한다.
|
|
21
|
+
*
|
|
22
|
+
* 반환 타입이 Promise인 이유: 추출은 별도 child_process에서 IPC로 수행된다.
|
|
23
|
+
* V8 GC가 ts-morph가 만든 대형 페이지를 OS에 반환하지 않는 문제를
|
|
24
|
+
* "프로세스 자체를 kill"로 해결하기 위해서.
|
|
25
|
+
*/
|
|
26
|
+
extract(jogakFilePath: string): Promise<Record<string, ArgType>>;
|
|
27
|
+
/**
|
|
28
|
+
* 사용자 jogak 파일의 default-export 메타(`title`, `argTypes`, `tags`, `parameters`)와
|
|
29
|
+
* named-export 중 jogak 객체들의 `name` 목록을 추출한다.
|
|
30
|
+
* 추출 불가능(ts-morph가 default export object literal을 못 찾음)하면 `null`.
|
|
31
|
+
*
|
|
32
|
+
* **부모 프로세스에는 ts-morph가 절대 로드되지 않는다.**
|
|
33
|
+
* 모든 ts-morph 작업은 자식 프로세스에서 수행된다.
|
|
34
|
+
*/
|
|
35
|
+
extractMeta(jogakFilePath: string): Promise<ExtractedMetaPayload | null>;
|
|
36
|
+
/**
|
|
37
|
+
* 자식 프로세스를 즉시 종료하고 모든 메모리를 OS에 반환한다.
|
|
38
|
+
* 다음 extract 호출 시 자식이 다시 spawn된다 (~수백ms warmup).
|
|
39
|
+
*/
|
|
40
|
+
releaseCache(): void;
|
|
41
|
+
}
|
|
42
|
+
export { createPropsExtractor } from './extractor-client.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const o=require("ts-morph");function y(e={}){function t(){return e.tsConfigFilePath!==void 0?new o.Project({tsConfigFilePath:e.tsConfigFilePath}):new o.Project({skipAddingFilesFromTsConfig:!0})}let r;function i(){return r===void 0&&(r=t()),r}function n(s){const a=i();let c=a.getSourceFile(s);return c===void 0?c=a.addSourceFileAtPathIfExists(s):c.refreshFromFileSystemSync(),c}return{extract(s){const a=n(s);return a===void 0?{}:A(a)},extractMeta(s){const a=n(s);if(a!==void 0)return F(a)},dispose(){r=void 0}}}function A(e){const t=e.getDefaultExportSymbol();if(t===void 0)return{};const r=t.getAliasedSymbol()??t,i=r.getDeclarations()[0]??t.getDeclarations()[0];if(i===void 0)return{};const s=r.getTypeAtLocation(i).getProperty("component");if(s===void 0)return{};const a=s.getTypeAtLocation(i),c=h(a,i);if(c===void 0)return{};const d={};for(const v of c.getProperties()){const E=v.getName(),P=v.getTypeAtLocation(i),u=L(P);if(u===null)continue;const S=!j(v),T={type:u.type,required:S,...u.control!==void 0?{control:u.control}:{},...u.options!==void 0?{options:u.options}:{},...u.action===!0?{action:!0}:{}};d[E]=T}return d}function h(e,t){const i=e.getCallSignatures()[0];if(i===void 0)return;const s=i.getParameters()[0];if(s===void 0)return;const a=s.getValueDeclaration()??t;return s.getTypeAtLocation(a)}function j(e){for(const t of e.getDeclarations())if((o.Node.isPropertySignature(t)||o.Node.isPropertyDeclaration(t)||o.Node.isParameterDeclaration(t))&&t.hasQuestionToken())return!0;return!1}function L(e){if(e.isUnion()){const t=e.getUnionTypes().filter(r=>!r.isUndefined()&&!r.isNull());if(t.length===0)return null;if(t.length===1){const r=t[0];return r!==void 0?L(r):null}return t.every(r=>r.isStringLiteral())?{type:"enum",control:"select",options:t.map(r=>D(r))}:t.length===2&&t.every(r=>r.isBooleanLiteral())?{type:"boolean",control:"boolean"}:null}return e.isString()||e.isStringLiteral()?{type:"string",control:"text"}:e.isNumber()||e.isNumberLiteral()?{type:"number",control:"number"}:e.isBoolean()?{type:"boolean",control:"boolean"}:e.getCallSignatures().length>0?{type:"function",action:!0}:null}function D(e){const t=e.getLiteralValue();return typeof t=="string"?t:e.getText().replace(/^["']|["']$/g,"")}function F(e){const t=O(e);if(t===void 0)return;const r=b(t,"title");if(r===void 0)return;const i=z(t),n=I(t,"tags"),s=C(t,"parameters"),a=V(e),c={...n!==void 0?{tags:n}:{},...s!==void 0?{parameters:s}:{}};return{title:r,jogakNames:a,userArgTypes:i,metaExtras:c}}function O(e){for(const r of e.getExportAssignments()){if(r.isExportEquals())continue;const i=r.getExpression();if(o.Node.isObjectLiteralExpression(i))return i;if(o.Node.isAsExpression(i)){const n=i.getExpression();if(o.Node.isObjectLiteralExpression(n))return n}if(o.Node.isSatisfiesExpression(i)){const n=i.getExpression();if(o.Node.isObjectLiteralExpression(n))return n}if(o.Node.isIdentifier(i)){const n=i.getSymbol();if(n!==void 0){for(const s of n.getDeclarations())if(o.Node.isVariableDeclaration(s)){const a=s.getInitializer();if(a!==void 0){const c=f(a);if(c!==void 0)return c}}}}}const t=e.getDefaultExportSymbol();if(t!==void 0){const r=t.getAliasedSymbol()??t;for(const i of r.getDeclarations())if(o.Node.isVariableDeclaration(i)){const n=i.getInitializer();if(n!==void 0){const s=f(n);if(s!==void 0)return s}}}}function f(e){if(o.Node.isObjectLiteralExpression(e))return e;if(o.Node.isAsExpression(e)||o.Node.isSatisfiesExpression(e)||o.Node.isParenthesizedExpression(e))return f(e.getExpression())}function b(e,t){const r=e.getProperty(t);if(r===void 0||!o.Node.isPropertyAssignment(r))return;const i=r.getInitializer();if(i!==void 0&&(o.Node.isStringLiteral(i)||o.Node.isNoSubstitutionTemplateLiteral(i)))return i.getLiteralText()}function I(e,t){const r=e.getProperty(t);if(r===void 0||!o.Node.isPropertyAssignment(r))return;const i=r.getInitializer();if(i===void 0||!o.Node.isArrayLiteralExpression(i))return;const n=[];for(const s of i.getElements())(o.Node.isStringLiteral(s)||o.Node.isNoSubstitutionTemplateLiteral(s))&&n.push(s.getLiteralText());return n}function z(e){const t=e.getProperty("argTypes");if(t===void 0||!o.Node.isPropertyAssignment(t))return{};const r=t.getInitializer();if(r===void 0||!o.Node.isObjectLiteralExpression(r))return{};const i={};for(const n of r.getProperties()){if(!o.Node.isPropertyAssignment(n))continue;const s=g(n);if(s===void 0)continue;const a=n.getInitializer();if(a===void 0||!o.Node.isObjectLiteralExpression(a))continue;const c=k(a);c!==void 0&&(i[s]=c)}return i}function g(e){const t=e.getNameNode();if(o.Node.isIdentifier(t))return t.getText();if(o.Node.isStringLiteral(t)||o.Node.isNoSubstitutionTemplateLiteral(t))return t.getLiteralText()}function k(e){const t={};for(const r of e.getProperties()){if(!o.Node.isPropertyAssignment(r))continue;const i=g(r);if(i===void 0)continue;const n=r.getInitializer();if(n===void 0)continue;const s=l(n);s!==void 0&&(t[i]=s)}return t}function C(e,t){const r=e.getProperty(t);if(r===void 0||!o.Node.isPropertyAssignment(r))return;const i=r.getInitializer();if(i===void 0||!o.Node.isObjectLiteralExpression(i))return;const n={};for(const s of i.getProperties()){if(!o.Node.isPropertyAssignment(s))continue;const a=g(s);if(a===void 0)continue;const c=s.getInitializer();if(c===void 0)continue;const d=l(c);d!==void 0&&(n[a]=d)}return n}function l(e){if(o.Node.isStringLiteral(e)||o.Node.isNoSubstitutionTemplateLiteral(e))return e.getLiteralText();if(o.Node.isNumericLiteral(e))return Number(e.getText());if(o.Node.isTrueLiteral(e))return!0;if(o.Node.isFalseLiteral(e))return!1;if(o.Node.isNullLiteral(e))return null;if(o.Node.isPrefixUnaryExpression(e)){const t=e.getOperand();if(o.Node.isNumericLiteral(t)){const r=e.getOperatorToken(),i=Number(t.getText());return r===41?-i:i}return}if(o.Node.isArrayLiteralExpression(e)){const t=[];for(const r of e.getElements()){const i=l(r);if(i===void 0)return;t.push(i)}return t}if(o.Node.isObjectLiteralExpression(e)){const t={};for(const r of e.getProperties()){if(!o.Node.isPropertyAssignment(r))return;const i=g(r);if(i===void 0)return;const n=r.getInitializer();if(n===void 0)return;const s=l(n);if(s===void 0)return;t[i]=s}return t}if(o.Node.isAsExpression(e)||o.Node.isSatisfiesExpression(e)||o.Node.isParenthesizedExpression(e))return l(e.getExpression())}function V(e){const t=[];for(const r of e.getVariableStatements())if(r.isExported()&&!r.hasDefaultKeyword())for(const i of r.getDeclarations()){const n=i.getInitializer();if(n===void 0)continue;const s=f(n);if(s===void 0)continue;const a=b(s,"name");a!==void 0&&t.push(a)}return t}const m=process.argv[2]??"",N=m.length>0?m:void 0,x=N!==void 0?y({tsConfigFilePath:N}):y();function p(e){typeof process.send=="function"&&process.send(e)}process.on("message",e=>{if(e.type==="extract"){const{id:t,filePath:r}=e;try{const i=x.extract(r);p({type:"result",id:t,argTypes:i})}catch(i){const n=i instanceof Error?i.message:String(i);p({type:"error",id:t,message:n})}return}if(e.type==="extractMeta"){const{id:t,filePath:r}=e;try{const i=x.extractMeta(r);p({type:"metaResult",id:t,meta:i??null})}catch(i){const n=i instanceof Error?i.message:String(i);p({type:"error",id:t,message:n})}return}});process.on("disconnect",()=>{process.exit(0)});
|