@ydant/core 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 cwd-k2
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # @ydant/core
2
+
3
+ Rendering engine and plugin system for Ydant.
4
+
5
+ ## Philosophy
6
+
7
+ **@ydant/core is a pure engine that doesn't know "what" to render.**
8
+
9
+ Core provides only:
10
+
11
+ - Generator processing
12
+ - Plugin dispatch
13
+ - Context management
14
+
15
+ It doesn't assume DOM existence. All concrete operations (DOM manipulation, lifecycle, keyed elements) are delegated to plugins. This separation keeps core's API surface minimal and stable, allowing plugins to extend functionality without modifying core.
16
+
17
+ For user-facing APIs like element factories and primitives, see `@ydant/base`.
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pnpm add @ydant/core
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```typescript
28
+ import { mount } from "@ydant/core";
29
+ import { createBasePlugin, div, text, type Component } from "@ydant/base";
30
+
31
+ const App: Component = () => div(() => [text("Hello!")]);
32
+
33
+ mount(App, document.getElementById("app")!, {
34
+ plugins: [createBasePlugin()],
35
+ });
36
+ ```
37
+
38
+ ## API
39
+
40
+ ### Mount
41
+
42
+ ```typescript
43
+ function mount(component: Component, container: HTMLElement, options?: MountOptions): void;
44
+
45
+ interface MountOptions {
46
+ plugins?: Plugin[];
47
+ }
48
+ ```
49
+
50
+ ### Plugin System
51
+
52
+ ```typescript
53
+ interface Plugin {
54
+ name: string;
55
+ types: string[];
56
+ /** Plugin names that must be registered before this plugin */
57
+ dependencies?: string[];
58
+ /** Initialize plugin-specific properties in RenderContext */
59
+ initContext?(ctx: Record<string, unknown>, parentCtx?: Record<string, unknown>): void;
60
+ /** Extend PluginAPI with plugin-specific methods */
61
+ extendAPI?(api: Record<string, unknown>, ctx: Record<string, unknown>): void;
62
+ /** Merge parent context into child context (called when creating child contexts) */
63
+ mergeChildContext?(childCtx: Record<string, unknown>, parentCtx: Record<string, unknown>): void;
64
+ /** Process a child element */
65
+ process(child: Child, api: PluginAPI): PluginResult;
66
+ }
67
+
68
+ interface PluginResult {
69
+ value?: unknown; // Value to pass back via next()
70
+ }
71
+ ```
72
+
73
+ ### Types
74
+
75
+ | Type | Description |
76
+ | ------------------ | --------------------------------------------------------------------- |
77
+ | `Tagged<T,P>` | Helper type for tagged unions: `{ type: T } & P` |
78
+ | `Child` | Union of all yieldable types (extended by plugins) |
79
+ | `ChildNext` | Union of values passed via `next()` (extended by plugins) |
80
+ | `ChildReturn` | Union of return values (extended by plugins) |
81
+ | `Render` | `Generator<Child, ChildReturn, ChildNext>` - Base rendering generator |
82
+ | `Component` | `() => Render` - Root component type |
83
+ | `ComponentWith<P>` | `(props: P) => Render` - Component type with props |
84
+ | `Builder` | `() => Instructor \| Instruction[]` - Element factory argument |
85
+ | `Instructor` | `Iterator<Child, ChildReturn, ChildNext>` - Internal iterator |
86
+ | `Instruction` | `Generator<Child, ChildReturn, ChildNext>` - Primitive return type |
87
+
88
+ ### Plugin Extension Interfaces
89
+
90
+ Plugins can extend these interfaces via module augmentation:
91
+
92
+ ```typescript
93
+ declare module "@ydant/core" {
94
+ // Extend RenderContext with custom properties
95
+ interface RenderContextExtensions {
96
+ myProperty: MyType;
97
+ }
98
+
99
+ // Extend PluginAPI with custom methods
100
+ interface PluginAPIExtensions {
101
+ myMethod(): void;
102
+ }
103
+
104
+ // Extend Child types (yieldable values)
105
+ interface PluginChildExtensions {
106
+ MyType: Tagged<"mytype", { value: string }>;
107
+ }
108
+
109
+ // Extend values passed via next()
110
+ interface PluginNextExtensions {
111
+ MyResult: MyResultType;
112
+ }
113
+
114
+ // Extend return values
115
+ interface PluginReturnExtensions {
116
+ MyResult: MyResultType;
117
+ }
118
+ }
119
+ ```
120
+
121
+ ### RenderContext
122
+
123
+ The rendering context holds state during rendering. Plugins extend it via `RenderContextExtensions`:
124
+
125
+ ```typescript
126
+ interface RenderContextCore {
127
+ parent: Node;
128
+ currentElement: Element | null;
129
+ plugins: Map<string, Plugin>;
130
+ }
131
+
132
+ type RenderContext = RenderContextCore & RenderContextExtensions;
133
+ ```
134
+
135
+ ### Utilities
136
+
137
+ | Function | Description |
138
+ | ---------------------- | -------------------------------------- |
139
+ | `isTagged(value, tag)` | Type guard for tagged union types |
140
+ | `toChildren(result)` | Normalize array/iterator to Instructor |
141
+
142
+ ## Creating Plugins
143
+
144
+ ```typescript
145
+ import type { Plugin, PluginAPI, PluginResult, Child } from "@ydant/core";
146
+
147
+ // 1. Declare type extensions
148
+ declare module "@ydant/core" {
149
+ interface RenderContextExtensions {
150
+ myData: Map<string, unknown>;
151
+ }
152
+ interface PluginAPIExtensions {
153
+ getMyData(key: string): unknown;
154
+ setMyData(key: string, value: unknown): void;
155
+ }
156
+ }
157
+
158
+ // 2. Create the plugin
159
+ export function createMyPlugin(): Plugin {
160
+ return {
161
+ name: "my-plugin",
162
+ types: ["mytype"],
163
+ dependencies: ["base"], // Ensure base plugin is registered first
164
+
165
+ // Initialize context properties
166
+ initContext(ctx, parentCtx) {
167
+ ctx.myData = parentCtx?.myData
168
+ ? new Map(parentCtx.myData as Map<string, unknown>)
169
+ : new Map();
170
+ },
171
+
172
+ // Merge parent context into child context
173
+ mergeChildContext(childCtx, parentCtx) {
174
+ childCtx.myData = new Map(parentCtx.myData as Map<string, unknown>);
175
+ },
176
+
177
+ // Extend PluginAPI with methods
178
+ extendAPI(api, ctx) {
179
+ const myData = ctx.myData as Map<string, unknown>;
180
+ api.getMyData = (key: string) => myData.get(key);
181
+ api.setMyData = (key: string, value: unknown) => myData.set(key, value);
182
+ },
183
+
184
+ // Process child elements
185
+ process(child: Child, api: PluginAPI): PluginResult {
186
+ if ((child as { type: string }).type === "mytype") {
187
+ // Process the child using api.getMyData(), api.setMyData()
188
+ return { value: result };
189
+ }
190
+ return {};
191
+ },
192
+ };
193
+ }
194
+ ```
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @ydant/core
3
+ *
4
+ * 純粋な DSL 処理系とプラグインシステム
5
+ */
6
+ export type { CleanupFn, Tagged, Child, ChildOfType, ChildNext, ChildReturn, Builder, Instructor, Instruction, Primitive, ChildContent, Render, Component, PluginChildExtensions, PluginNextExtensions, PluginReturnExtensions, } from './types';
7
+ export type { Plugin, PluginAPI, PluginAPIExtensions, PluginResult, MountOptions } from './plugin';
8
+ export { isTagged, toChildren } from './utils';
9
+ export { mount } from './mount';
10
+ export { render, processIterator, createRenderContext, createPluginAPIFactory } from './render';
11
+ export type { RenderContext, RenderContextCore, RenderContextExtensions } from './render';
@@ -0,0 +1,131 @@
1
+ function C(t, o) {
2
+ return t.type === o;
3
+ }
4
+ function y(t) {
5
+ return Array.isArray(t) ? (function* () {
6
+ for (const o of t)
7
+ yield* o;
8
+ })() : t;
9
+ }
10
+ function p(t, o) {
11
+ const n = /* @__PURE__ */ new Set();
12
+ for (const i of t.values())
13
+ n.has(i.name) || (n.add(i.name), o(i));
14
+ }
15
+ function A(t, o, n) {
16
+ return {
17
+ parent: t,
18
+ currentElement: o,
19
+ plugins: n
20
+ };
21
+ }
22
+ function d(t, o, n, i) {
23
+ const r = A(t, o, n);
24
+ return p(n, (e) => {
25
+ e.initContext?.(r, i);
26
+ }), r;
27
+ }
28
+ function g(t) {
29
+ return function o(n) {
30
+ if (n._cachedAPI)
31
+ return n._cachedAPI;
32
+ const i = {
33
+ // ========================================================================
34
+ // コア機能(プラグインが拡張する基盤)
35
+ // ========================================================================
36
+ get parent() {
37
+ return n.parent;
38
+ },
39
+ get currentElement() {
40
+ return n.currentElement;
41
+ },
42
+ processChildren(e, u) {
43
+ const l = u?.parent ?? n.parent, s = d(
44
+ l,
45
+ l instanceof globalThis.Element ? l : null,
46
+ n.plugins,
47
+ n
48
+ ), c = y(e());
49
+ t(c, s), p(n.plugins, (P) => {
50
+ P.mergeChildContext?.(n, s);
51
+ });
52
+ },
53
+ createChildAPI(e) {
54
+ const u = d(
55
+ e,
56
+ e instanceof globalThis.Element ? e : null,
57
+ n.plugins,
58
+ n
59
+ );
60
+ return o(u);
61
+ }
62
+ };
63
+ p(n.plugins, (e) => {
64
+ e.extendAPI?.(i, n);
65
+ });
66
+ const r = i;
67
+ return n._cachedAPI = r, r;
68
+ };
69
+ }
70
+ let a = null;
71
+ function h(t, o) {
72
+ a || (a = g(h));
73
+ let n = t.next();
74
+ for (; !n.done; ) {
75
+ const i = n.value;
76
+ if (i && typeof i == "object" && "type" in i) {
77
+ const r = i.type, e = o.plugins.get(r);
78
+ if (e) {
79
+ const u = a(o), l = e.process(i, u);
80
+ n = t.next(l.value);
81
+ continue;
82
+ }
83
+ }
84
+ n = t.next();
85
+ }
86
+ }
87
+ let f = null;
88
+ function m(t, o, n) {
89
+ o.innerHTML = "";
90
+ const i = d(o, null, n);
91
+ f || (f = g(h));
92
+ let r = t.next();
93
+ for (; !r.done; ) {
94
+ const e = r.value;
95
+ if (e && typeof e == "object" && "type" in e) {
96
+ const u = e.type, l = n.get(u);
97
+ if (l) {
98
+ const s = f(i), c = l.process(e, s);
99
+ r = t.next(c.value);
100
+ continue;
101
+ }
102
+ }
103
+ r = t.next(void 0);
104
+ }
105
+ }
106
+ function I(t, o, n) {
107
+ const i = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set();
108
+ if (n?.plugins) {
109
+ for (const e of n.plugins) {
110
+ r.add(e.name);
111
+ for (const u of e.types)
112
+ i.set(u, e);
113
+ }
114
+ for (const e of n.plugins)
115
+ if (e.dependencies)
116
+ for (const u of e.dependencies)
117
+ r.has(u) || console.warn(
118
+ `[ydant] Plugin "${e.name}" depends on "${u}", but "${u}" is not registered.`
119
+ );
120
+ }
121
+ m(t(), o, i);
122
+ }
123
+ export {
124
+ g as createPluginAPIFactory,
125
+ d as createRenderContext,
126
+ C as isTagged,
127
+ I as mount,
128
+ h as processIterator,
129
+ m as render,
130
+ y as toChildren
131
+ };
@@ -0,0 +1 @@
1
+ (function(l,s){typeof exports=="object"&&typeof module<"u"?s(exports):typeof define=="function"&&define.amd?define(["exports"],s):(l=typeof globalThis<"u"?globalThis:l||self,s(l.YdantCore={}))})(this,(function(l){"use strict";function s(t,i){return t.type===i}function m(t){return Array.isArray(t)?(function*(){for(const i of t)yield*i})():t}function d(t,i){const e=new Set;for(const o of t.values())e.has(o.name)||(e.add(o.name),i(o))}function A(t,i,e){return{parent:t,currentElement:i,plugins:e}}function a(t,i,e,o){const u=A(t,i,e);return d(e,n=>{n.initContext?.(u,o)}),u}function p(t){return function i(e){if(e._cachedAPI)return e._cachedAPI;const o={get parent(){return e.parent},get currentElement(){return e.currentElement},processChildren(n,r){const c=r?.parent??e.parent,f=a(c,c instanceof globalThis.Element?c:null,e.plugins,e),P=m(n());t(P,f),d(e.plugins,v=>{v.mergeChildContext?.(e,f)})},createChildAPI(n){const r=a(n,n instanceof globalThis.Element?n:null,e.plugins,e);return i(r)}};d(e.plugins,n=>{n.extendAPI?.(o,e)});const u=o;return e._cachedAPI=u,u}}let g=null;function h(t,i){g||(g=p(h));let e=t.next();for(;!e.done;){const o=e.value;if(o&&typeof o=="object"&&"type"in o){const u=o.type,n=i.plugins.get(u);if(n){const r=g(i),c=n.process(o,r);e=t.next(c.value);continue}}e=t.next()}}let y=null;function C(t,i,e){i.innerHTML="";const o=a(i,null,e);y||(y=p(h));let u=t.next();for(;!u.done;){const n=u.value;if(n&&typeof n=="object"&&"type"in n){const r=n.type,c=e.get(r);if(c){const f=y(o),P=c.process(n,f);u=t.next(P.value);continue}}u=t.next(void 0)}}function I(t,i,e){const o=new Map,u=new Set;if(e?.plugins){for(const n of e.plugins){u.add(n.name);for(const r of n.types)o.set(r,n)}for(const n of e.plugins)if(n.dependencies)for(const r of n.dependencies)u.has(r)||console.warn(`[ydant] Plugin "${n.name}" depends on "${r}", but "${r}" is not registered.`)}C(t(),i,o)}l.createPluginAPIFactory=p,l.createRenderContext=a,l.isTagged=s,l.mount=I,l.processIterator=h,l.render=C,l.toChildren=m,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
@@ -0,0 +1,24 @@
1
+ import { MountOptions } from './plugin';
2
+ import { Render } from './types';
3
+ type Component = () => Render;
4
+ /**
5
+ * Component を DOM にマウントする
6
+ *
7
+ * @param app - マウントするコンポーネント
8
+ * @param parent - マウント先の DOM 要素
9
+ * @param options - マウントオプション(プラグインなど)
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { mount } from "@ydant/core";
14
+ * import { createBasePlugin, div, text } from "@ydant/base";
15
+ *
16
+ * const App = () => div(() => [text("Hello!")]);
17
+ *
18
+ * mount(App, document.getElementById("app")!, {
19
+ * plugins: [createBasePlugin()],
20
+ * });
21
+ * ```
22
+ */
23
+ export declare function mount(app: Component, parent: HTMLElement, options?: MountOptions): void;
24
+ export {};
@@ -0,0 +1,79 @@
1
+ import { Child, ChildNext } from './types';
2
+ import { RenderContext, RenderContextCore, RenderContextExtensions } from './render/types';
3
+ /**
4
+ * プラグインが PluginAPI を拡張するためのインターフェース
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // @ydant/base で DOM 操作用のメソッドを追加
9
+ * declare module "@ydant/core" {
10
+ * interface PluginAPIExtensions extends BasePluginAPI {}
11
+ * }
12
+ * ```
13
+ */
14
+ export interface PluginAPIExtensions {
15
+ }
16
+ /**
17
+ * プラグインが使用できる API
18
+ *
19
+ * 実際のメソッドは @ydant/base の PluginAPIExtensions 拡張で定義される
20
+ */
21
+ export type PluginAPI = PluginAPIExtensions;
22
+ /**
23
+ * プラグインの処理結果
24
+ */
25
+ export interface PluginResult {
26
+ /** ジェネレータに返す値 */
27
+ value?: ChildNext | undefined;
28
+ }
29
+ /**
30
+ * DOM レンダラープラグイン
31
+ */
32
+ export interface Plugin {
33
+ /** プラグイン識別子 */
34
+ readonly name: string;
35
+ /** このプラグインが処理する type タグの配列 */
36
+ readonly types: readonly string[];
37
+ /** 依存するプラグインの name 配列 */
38
+ readonly dependencies?: readonly string[];
39
+ /**
40
+ * RenderContext を初期化する
41
+ *
42
+ * mount 時および子コンテキスト作成時に呼び出される。
43
+ * プラグインは RenderContextExtensions で定義した独自プロパティを
44
+ * ここで初期化する。
45
+ *
46
+ * @param ctx - 初期化対象のコンテキスト(構築途中のため Partial)
47
+ * @param parentCtx - 親コンテキスト(ルートの場合は undefined)
48
+ */
49
+ initContext?(ctx: RenderContextCore & Partial<RenderContextExtensions>, parentCtx?: RenderContext): void;
50
+ /**
51
+ * PluginAPI を拡張する
52
+ *
53
+ * プラグイン固有のメソッドを PluginAPI に追加する。
54
+ * PluginAPIExtensions で定義した独自のメソッドをここで実装する。
55
+ *
56
+ * @param api - 拡張対象の PluginAPI オブジェクト
57
+ * @param ctx - 現在の RenderContext(initContext 後なので構築済み)
58
+ */
59
+ extendAPI?(api: Partial<PluginAPIExtensions>, ctx: RenderContext): void;
60
+ /**
61
+ * 子コンテキストの状態を親コンテキストにマージする
62
+ *
63
+ * processChildren 内で子イテレータ処理後に呼び出される。
64
+ * プラグインは子コンテキストから親コンテキストへの状態伝搬をここで実装する。
65
+ *
66
+ * @param parentCtx - 親コンテキスト
67
+ * @param childCtx - 子コンテキスト
68
+ */
69
+ mergeChildContext?(parentCtx: RenderContext, childCtx: RenderContext): void;
70
+ /** Child を処理する */
71
+ process(child: Child, api: PluginAPI): PluginResult;
72
+ }
73
+ /**
74
+ * mount のオプション
75
+ */
76
+ export interface MountOptions {
77
+ /** 使用するプラグインの配列 */
78
+ plugins?: Plugin[];
79
+ }
@@ -0,0 +1,24 @@
1
+ import { Instructor } from '../types';
2
+ import { Plugin, PluginAPI } from '../plugin';
3
+ import { RenderContext, RenderContextCore } from './types';
4
+ /** RenderContext のコア部分を作成 */
5
+ export declare function createRenderContextCore(parent: Node, currentElement: globalThis.Element | null, plugins: Map<string, Plugin>): RenderContextCore;
6
+ /**
7
+ * RenderContext を作成し、各プラグインで初期化
8
+ *
9
+ * @param parent - 親ノード
10
+ * @param currentElement - 現在の要素
11
+ * @param plugins - 登録されたプラグイン
12
+ * @param parentCtx - 親コンテキスト(子コンテキスト作成時)
13
+ */
14
+ export declare function createRenderContext(parent: Node, currentElement: globalThis.Element | null, plugins: Map<string, Plugin>, parentCtx?: RenderContext): RenderContext;
15
+ /**
16
+ * RenderContext から PluginAPI を作成
17
+ *
18
+ * processIterator を循環参照で受け取る必要があるため、
19
+ * ファクトリ関数として実装
20
+ *
21
+ * NOTE: core は基本的な API のみを提供し、プラグイン固有のメソッドは
22
+ * 各プラグインの extendAPI で追加される。
23
+ */
24
+ export declare function createPluginAPIFactory(processIterator: (iter: Instructor, ctx: RenderContext) => void): (ctx: RenderContext) => PluginAPI;
@@ -0,0 +1,9 @@
1
+ import { Render } from '../types';
2
+ import { Plugin } from '../plugin';
3
+ /**
4
+ * Render(ジェネレータ)を DOM に描画
5
+ */
6
+ export declare function render(gen: Render, parent: HTMLElement, plugins: Map<string, Plugin>): void;
7
+ export { processIterator } from './iterator';
8
+ export { createRenderContext, createPluginAPIFactory } from './context';
9
+ export type { RenderContext, RenderContextCore, RenderContextExtensions } from './types';
@@ -0,0 +1,9 @@
1
+ import { Instructor } from '../types';
2
+ import { RenderContext } from './types';
3
+ /**
4
+ * Child イテレータを処理し、DOM に反映する
5
+ *
6
+ * すべての type はプラグインで処理される。
7
+ * 対応するプラグインがない type はスキップされる。
8
+ */
9
+ export declare function processIterator(iter: Instructor, ctx: RenderContext): void;
@@ -0,0 +1,30 @@
1
+ import { Plugin } from '../plugin';
2
+ /**
3
+ * プラグインが RenderContext を拡張するためのインターフェース
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * // @ydant/base で keyed 要素管理用のプロパティを追加
8
+ * declare module "@ydant/core" {
9
+ * interface RenderContextExtensions {
10
+ * pendingKey: string | number | null;
11
+ * keyedNodes: Map<string | number, unknown>;
12
+ * }
13
+ * }
14
+ * ```
15
+ */
16
+ export interface RenderContextExtensions {
17
+ }
18
+ /** レンダリングコンテキスト(コア部分) */
19
+ export interface RenderContextCore {
20
+ /** 親ノード */
21
+ parent: Node;
22
+ /** 現在処理中の要素 */
23
+ currentElement: globalThis.Element | null;
24
+ /** 登録されたプラグイン */
25
+ plugins: Map<string, Plugin>;
26
+ /** キャッシュされた PluginAPI(内部用) */
27
+ _cachedAPI?: import('../plugin').PluginAPI;
28
+ }
29
+ /** レンダリングコンテキスト */
30
+ export type RenderContext = RenderContextCore & RenderContextExtensions;
@@ -0,0 +1,96 @@
1
+ /** Tagged Union を作成するヘルパー型 */
2
+ export type Tagged<T extends string, P = {}> = {
3
+ type: T;
4
+ } & P;
5
+ /** ライフサイクルや副作用のクリーンアップ関数 */
6
+ export type CleanupFn = () => void;
7
+ /**
8
+ * プラグインが Child 型を拡張するためのインターフェース
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // @ydant/base で Element 型を追加
13
+ * declare module "@ydant/core" {
14
+ * interface PluginChildExtensions {
15
+ * Element: Tagged<"element", { tag: string; children: Instructor }>;
16
+ * }
17
+ * }
18
+ * ```
19
+ */
20
+ export interface PluginChildExtensions {
21
+ }
22
+ /**
23
+ * プラグインが next() に渡す値の型を拡張するためのインターフェース
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // @ydant/base で Slot を追加
28
+ * declare module "@ydant/core" {
29
+ * interface PluginNextExtensions {
30
+ * Slot: Slot;
31
+ * }
32
+ * }
33
+ * ```
34
+ */
35
+ export interface PluginNextExtensions {
36
+ }
37
+ /**
38
+ * プラグインが return で返す値の型を拡張するためのインターフェース
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * // @ydant/base で Slot を追加
43
+ * declare module "@ydant/core" {
44
+ * interface PluginReturnExtensions {
45
+ * Slot: Slot;
46
+ * }
47
+ * }
48
+ * ```
49
+ */
50
+ export interface PluginReturnExtensions {
51
+ }
52
+ /** 子要素として yield できるもの(プラグインによって拡張可能) */
53
+ export type Child = PluginChildExtensions[keyof PluginChildExtensions];
54
+ /** Child から特定の type を抽出するヘルパー型 */
55
+ export type ChildOfType<T extends string> = Extract<Child, {
56
+ type: T;
57
+ }>;
58
+ /** next() に渡される値の型(プラグインによって拡張可能) */
59
+ export type ChildNext = void | PluginNextExtensions[keyof PluginNextExtensions];
60
+ /** return で返される値の型(プラグインによって拡張可能) */
61
+ export type ChildReturn = void | PluginReturnExtensions[keyof PluginReturnExtensions];
62
+ /** レンダリング命令の Iterator(内部処理用) */
63
+ export type Instructor = Iterator<Child, ChildReturn, ChildNext>;
64
+ /** レンダリング命令(text, attr, on 等)の戻り値型 */
65
+ export type Instruction = Generator<Child, ChildReturn, ChildNext>;
66
+ /** 要素ファクトリ(div, span 等)の引数型 */
67
+ export type Builder = () => Instructor | Instruction[];
68
+ /** 副作用のみを実行する DSL プリミティブの戻り値型 */
69
+ export type Primitive<T extends Child> = Generator<T, void, void>;
70
+ /** コンポーネントの children として渡すビルダー関数の戻り値型 */
71
+ export type ChildContent = Generator<Child, unknown, ChildNext>;
72
+ /**
73
+ * Element を yield し、最終的に ChildReturn を返すジェネレーター
74
+ *
75
+ * base パッケージでは Slot が PluginReturnExtensions に追加されるため、
76
+ * より具体的な型 (Generator<Child, Slot, Slot>) として使用される
77
+ */
78
+ export type Render = Generator<Child, ChildReturn, ChildNext>;
79
+ /**
80
+ * コンポーネント型
81
+ *
82
+ * - `Component` — 引数なし `() => Render`
83
+ * - `Component<Props>` — Props を受け取る `(props: Props) => Render`
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const App: Component = () => div(function* () { ... });
88
+ *
89
+ * interface CounterProps { initial: number }
90
+ * const Counter: Component<CounterProps> = (props) =>
91
+ * div(function* () {
92
+ * yield* text(`Count: ${props.initial}`);
93
+ * });
94
+ * ```
95
+ */
96
+ export type Component<P = void> = [P] extends [void] ? () => Render : (props: P) => Render;
@@ -0,0 +1,8 @@
1
+ import { Tagged, Child, ChildOfType, Instruction, Instructor } from './types';
2
+ /** Tagged 型の判定関数(Child に対する型ガード付きオーバーロード) */
3
+ export declare function isTagged<T extends Child["type"]>(value: Child, tag: T): value is ChildOfType<T>;
4
+ export declare function isTagged<T extends string>(value: {
5
+ type: string;
6
+ }, tag: T): value is Tagged<T, Record<string, unknown>>;
7
+ /** Builder の結果を Instructor に正規化する */
8
+ export declare function toChildren(result: Instructor | Instruction[]): Instructor;
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@ydant/core",
3
+ "version": "0.1.0",
4
+ "description": "Generator-based DOM rendering DSL",
5
+ "keywords": [
6
+ "dsl",
7
+ "generator",
8
+ "rendering",
9
+ "ui",
10
+ "ydant"
11
+ ],
12
+ "homepage": "https://github.com/cwd-k2/ydant#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/cwd-k2/ydant/issues"
15
+ },
16
+ "license": "MIT",
17
+ "author": "cwd-k2",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/cwd-k2/ydant.git",
21
+ "directory": "packages/core"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "LICENSE",
26
+ "README.md"
27
+ ],
28
+ "main": "./dist/index.umd.js",
29
+ "module": "./dist/index.es.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "@ydant/dev": {
35
+ "types": "./src/index.ts",
36
+ "default": "./src/index.ts"
37
+ },
38
+ "import": "./dist/index.es.js",
39
+ "require": "./dist/index.umd.js"
40
+ }
41
+ },
42
+ "scripts": {
43
+ "build": "vite build",
44
+ "typecheck": "tsc --noEmit"
45
+ }
46
+ }