@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.
@@ -0,0 +1,277 @@
1
+ import { resolve as S, join as $ } from "node:path";
2
+ import { existsSync as j } from "node:fs";
3
+ import { stat as I, rm as G, readdir as U, readFile as C } from "node:fs/promises";
4
+ import { c as R } from "../extractor-client-CReBed7x.js";
5
+ const B = [
6
+ "@jogak/core",
7
+ "@jogak/react",
8
+ "@jogak/web-components",
9
+ "@jogak/next"
10
+ ];
11
+ async function P(t) {
12
+ try {
13
+ const u = await I(t);
14
+ if (!u.isDirectory())
15
+ return u.mtimeMs;
16
+ } catch {
17
+ return 0;
18
+ }
19
+ let n = 0, m;
20
+ try {
21
+ m = await U(t);
22
+ } catch {
23
+ return 0;
24
+ }
25
+ for (const u of m) {
26
+ const p = $(t, u);
27
+ try {
28
+ const l = await I(p);
29
+ if (l.isDirectory()) {
30
+ const a = await P(p);
31
+ a > n && (n = a);
32
+ } else l.mtimeMs > n && (n = l.mtimeMs);
33
+ } catch {
34
+ continue;
35
+ }
36
+ }
37
+ return n;
38
+ }
39
+ async function J(t) {
40
+ const n = S(t.root, "node_modules/.vite/deps");
41
+ if (!j(n))
42
+ return { purged: !1 };
43
+ const m = $(n, "_metadata.json");
44
+ if (!j(m))
45
+ return { purged: !1 };
46
+ let u;
47
+ try {
48
+ u = (await I(m)).mtimeMs;
49
+ } catch (l) {
50
+ return t.logger.warn(
51
+ `[jogak] cache validation: failed to stat _metadata.json (${l.message})`
52
+ ), { purged: !1 };
53
+ }
54
+ const p = t.packages ?? B;
55
+ for (const l of p) {
56
+ const a = S(t.root, "node_modules", l, "dist");
57
+ if (!j(a)) continue;
58
+ let i;
59
+ try {
60
+ i = await P(a);
61
+ } catch (y) {
62
+ t.logger.warn(
63
+ `[jogak] cache validation: failed to walk ${l}/dist (${y.message})`
64
+ );
65
+ continue;
66
+ }
67
+ if (i > u + 1e3)
68
+ try {
69
+ return await G(n, { recursive: !0, force: !0 }), t.logger.info(
70
+ `[jogak] vite deps cache invalidated (stale): ${l} dist newer than cache`
71
+ ), { purged: !0, reason: l };
72
+ } catch (y) {
73
+ return t.logger.warn(
74
+ `[jogak] cache validation: failed to purge ${n} (${y.message})`
75
+ ), { purged: !1 };
76
+ }
77
+ }
78
+ return { purged: !1 };
79
+ }
80
+ const D = "virtual:jogak", T = "\0" + D, F = "virtual:jogak/entry/", x = "\0" + F;
81
+ function K(t) {
82
+ return Buffer.from(t, "utf8").toString("base64url");
83
+ }
84
+ function X(t) {
85
+ return Buffer.from(t, "base64url").toString("utf8");
86
+ }
87
+ function A(t) {
88
+ return {
89
+ title: t.title,
90
+ jogakNamesKey: [...t.jogakNames].sort().join("|")
91
+ };
92
+ }
93
+ function W(t, n) {
94
+ return t !== void 0 && t.title === n.title && t.jogakNamesKey === n.jogakNamesKey;
95
+ }
96
+ function Z(t = {}) {
97
+ const {
98
+ patterns: n = ["src/**/*.jogak.ts", "src/**/*.jogak.tsx"],
99
+ codeTheme: m = "vsDark"
100
+ } = t, u = t.cwd, p = t.tsConfigFilePath, l = t.disableCacheValidation === !0;
101
+ let a, i, y;
102
+ const w = /* @__PURE__ */ new Map(), k = /* @__PURE__ */ new Map(), _ = /* @__PURE__ */ new Map();
103
+ async function N() {
104
+ const { glob: e } = await import("glob"), g = y ?? process.cwd(), o = await e(n, { cwd: g, absolute: !0 }), d = [];
105
+ w.clear(), k.clear();
106
+ for (const s of o) {
107
+ let f = "";
108
+ try {
109
+ f = await C(s, "utf8");
110
+ } catch {
111
+ continue;
112
+ }
113
+ let v = {}, r = null;
114
+ if (i !== void 0) {
115
+ try {
116
+ v = await i.extract(s);
117
+ } catch {
118
+ v = {};
119
+ }
120
+ try {
121
+ r = await i.extractMeta(s);
122
+ } catch {
123
+ r = null;
124
+ }
125
+ }
126
+ if (r === null) continue;
127
+ const c = r.title;
128
+ w.set(c, s), k.set(s, c);
129
+ const h = {
130
+ id: c,
131
+ title: r.title,
132
+ jogakNames: r.jogakNames,
133
+ autoArgTypes: v,
134
+ userArgTypes: r.userArgTypes,
135
+ source: f,
136
+ filePath: s,
137
+ metaExtras: r.metaExtras
138
+ };
139
+ _.set(s, A(h)), d.push({ id: c, filePath: s, meta: h });
140
+ }
141
+ return d;
142
+ }
143
+ return {
144
+ name: "vite-plugin-jogak",
145
+ async configResolved(e) {
146
+ y = u ?? e.root, e.command === "serve" && !l && await J({
147
+ root: e.root,
148
+ logger: {
149
+ info: (o) => e.logger.info(o),
150
+ warn: (o) => e.logger.warn(o)
151
+ }
152
+ });
153
+ const g = p ?? S(y, "tsconfig.json");
154
+ i = j(g) ? R({ tsConfigFilePath: g }) : R();
155
+ },
156
+ configureServer(e) {
157
+ a = e;
158
+ },
159
+ buildEnd() {
160
+ i == null || i.releaseCache();
161
+ },
162
+ resolveId(e) {
163
+ if (e === D)
164
+ return T;
165
+ if (e.startsWith(F))
166
+ return "\0" + e;
167
+ },
168
+ async load(e) {
169
+ if (e === T) {
170
+ const o = (await N()).map((d) => d.meta);
171
+ return `import { defaultRegistry } from '@jogak/core'
172
+
173
+ const _entryLoader = (slug) =>
174
+ import(/* @vite-ignore */ '/@id/__x00__virtual:jogak/entry/' + slug)
175
+ defaultRegistry.setEntryLoader((id) => {
176
+ const slug = ${Y()}
177
+ return _entryLoader(slug(id))
178
+ })
179
+
180
+ const _metas = ${JSON.stringify(o)}
181
+
182
+ for (const m of _metas) defaultRegistry.registerMeta(m)
183
+
184
+ export const _jogakCodeTheme = ${JSON.stringify(m)}
185
+ export const _jogakMetas = _metas
186
+ `;
187
+ }
188
+ if (e.startsWith(x)) {
189
+ const g = e.slice(x.length), o = X(g);
190
+ let d = w.get(o);
191
+ return d === void 0 && (await N(), d = w.get(o)), d === void 0 ? `// [jogak] unknown entry id: ${JSON.stringify(o)}
192
+ export {}
193
+ ` : `import * as _user from ${JSON.stringify(d)}
194
+ import { defaultRegistry } from '@jogak/core'
195
+
196
+ const _meta = _user.default
197
+ const _named = { ..._user }
198
+ delete _named.default
199
+ const _jogaks = Object.values(_named).filter(
200
+ (v) => v !== null && typeof v === 'object' && typeof v.name === 'string'
201
+ )
202
+ defaultRegistry.hydrateEntry(${JSON.stringify(o)}, _jogaks, _meta?.component)
203
+
204
+ if (import.meta.hot) {
205
+ import.meta.hot.accept()
206
+ }
207
+
208
+ export {}
209
+ `;
210
+ }
211
+ },
212
+ async handleHotUpdate({ file: e, modules: g }) {
213
+ const o = /\.jogak\.(tsx?|jsx?)$/.test(e), d = /\.(tsx?|jsx?)$/.test(e) && !o;
214
+ if (!o && !d || a === void 0 || !o) return;
215
+ const s = a.moduleGraph.getModuleById(
216
+ T
217
+ ), f = k.get(e), v = f !== void 0 ? x + K(f) : void 0, r = v !== void 0 ? a.moduleGraph.getModuleById(v) : void 0;
218
+ let c = null, h = {}, M = "";
219
+ if (i !== void 0) {
220
+ try {
221
+ c = await i.extractMeta(e);
222
+ } catch {
223
+ c = null;
224
+ }
225
+ try {
226
+ h = await i.extract(e);
227
+ } catch {
228
+ h = {};
229
+ }
230
+ try {
231
+ M = await C(e, "utf8");
232
+ } catch {
233
+ M = "";
234
+ }
235
+ }
236
+ if (c === null) {
237
+ s !== void 0 && a.moduleGraph.invalidateModule(s), r !== void 0 && a.moduleGraph.invalidateModule(r), a.ws.send({ type: "full-reload" });
238
+ return;
239
+ }
240
+ const b = A(c), O = _.get(e), L = W(O, b);
241
+ if (_.set(e, b), !L || f === void 0) {
242
+ s !== void 0 && a.moduleGraph.invalidateModule(s), r !== void 0 && a.moduleGraph.invalidateModule(r), a.ws.send({ type: "full-reload" });
243
+ return;
244
+ }
245
+ const V = {
246
+ id: f,
247
+ title: c.title,
248
+ jogakNames: c.jogakNames,
249
+ autoArgTypes: h,
250
+ userArgTypes: c.userArgTypes,
251
+ source: M,
252
+ filePath: e,
253
+ metaExtras: c.metaExtras
254
+ };
255
+ r !== void 0 && a.moduleGraph.invalidateModule(r), a.ws.send({
256
+ type: "custom",
257
+ event: "jogak:meta-update",
258
+ data: { id: f, meta: V }
259
+ });
260
+ const E = [...g];
261
+ return r !== void 0 && !E.includes(r) && E.push(r), E;
262
+ }
263
+ };
264
+ }
265
+ function Y() {
266
+ return `(rawId) => {
267
+ if (typeof Buffer !== 'undefined') return Buffer.from(rawId, 'utf8').toString('base64url')
268
+ // 브라우저 폴백: btoa는 binary string 기준이라 UTF-8을 한번 인코딩해야 한다.
269
+ const enc = new TextEncoder().encode(rawId)
270
+ let bin = ''
271
+ for (let i = 0; i < enc.length; i++) bin += String.fromCharCode(enc[i])
272
+ return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')
273
+ }`;
274
+ }
275
+ export {
276
+ Z as jogak
277
+ };
@@ -0,0 +1,3 @@
1
+ import { Plugin } from 'vite';
2
+ import { JogakPluginOptions } from '../types.js';
3
+ export declare function jogak(options?: JogakPluginOptions): Plugin;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 가상모듈 식별자 — 단일 정의 소스.
3
+ *
4
+ * - 인덱스 모듈(`virtual:jogak`): 모든 entry의 meta. user 모듈 import 0개.
5
+ * - Entry 모듈(`virtual:jogak/entry/<slug>`): 단 하나의 user jogak 파일을 import해
6
+ * `defaultRegistry.hydrateEntry`로 register하는 side-effect 모듈.
7
+ *
8
+ * id ↔ slug 변환:
9
+ * - 사용자 title이 `Form/Button` 같은 슬래시를 포함하므로 URL/모듈 경로에 직접 못 씀.
10
+ * - base64url은 모듈 식별자에 안전 (영숫자 + `-_`).
11
+ */
12
+ /** 인덱스 모듈 — 모든 entry의 meta. */
13
+ export declare const VIRTUAL_INDEX_ID = "virtual:jogak";
14
+ export declare const RESOLVED_VIRTUAL_INDEX_ID: string;
15
+ /** Entry 모듈 prefix — 뒤에 base64url(id)이 붙는다. */
16
+ export declare const VIRTUAL_ENTRY_PREFIX = "virtual:jogak/entry/";
17
+ export declare const RESOLVED_VIRTUAL_ENTRY_PREFIX: string;
18
+ export declare function idToSlug(id: string): string;
19
+ export declare function slugToId(slug: string): string;
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@jogak/core",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "Core types, registry, and Vite plugin for Jogak — a lightweight Storybook alternative.",
5
+ "keywords": [
6
+ "jogak",
7
+ "storybook",
8
+ "storybook-alternative",
9
+ "showcase",
10
+ "design-system",
11
+ "component-library",
12
+ "vite-plugin"
13
+ ],
14
+ "author": {
15
+ "name": "devclib",
16
+ "url": "https://github.com/devclib"
17
+ },
18
+ "license": "MIT",
19
+ "homepage": "https://github.com/devclib/jogak#readme",
20
+ "bugs": "https://github.com/devclib/jogak/issues",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/devclib/jogak.git",
24
+ "directory": "packages/core"
25
+ },
26
+ "type": "module",
27
+ "sideEffects": false,
28
+ "main": "./dist/index.js",
29
+ "module": "./dist/index.mjs",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.mjs",
35
+ "require": "./dist/index.js"
36
+ },
37
+ "./vite": {
38
+ "types": "./dist/vite/plugin.d.ts",
39
+ "import": "./dist/vite/index.mjs"
40
+ },
41
+ "./build": {
42
+ "types": "./dist/build/index.d.ts",
43
+ "import": "./dist/build/index.mjs"
44
+ }
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "README.md",
49
+ "LICENSE",
50
+ "CHANGELOG.md"
51
+ ],
52
+ "engines": {
53
+ "node": ">=20.18"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public",
57
+ "registry": "https://registry.npmjs.org/"
58
+ },
59
+ "dependencies": {
60
+ "glob": "^11.0.0",
61
+ "ts-morph": "^23.0.0"
62
+ },
63
+ "devDependencies": {
64
+ "vite": "^6.0.0",
65
+ "vite-plugin-dts": "^4.0.0",
66
+ "typescript": "^5.5.0",
67
+ "@types/node": "^20.14.0"
68
+ },
69
+ "peerDependencies": {
70
+ "vite": "^6.0.0"
71
+ },
72
+ "peerDependenciesMeta": {
73
+ "vite": {
74
+ "optional": true
75
+ }
76
+ },
77
+ "scripts": {
78
+ "build": "vite build",
79
+ "dev": "vite build --watch",
80
+ "typecheck": "tsc --noEmit"
81
+ }
82
+ }