@lankajs/solid 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) 2026 lankajs contributors
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,43 @@
1
+ # @lankajs/solid
2
+
3
+ **▸ module** · Solid binding
4
+
5
+ > One function — `useLankaVM` — over a signal, and the access tracking core already does.
6
+
7
+ A library in the same box. The app imports and calls it; core does not know it exists.
8
+
9
+ **Runs in:** the browser.
10
+
11
+ **Requires:** Solid. Enforced by `check-runtime.mjs`, which refuses an import of any other.
12
+
13
+ **How to use it:** [GUIDE.md](./GUIDE.md) — the user guide, with examples. **How to change it:** [SKILL.md](./SKILL.md).
14
+
15
+ ## Contents
16
+
17
+ - `useLankaVM` — the one name, and the same one every member of this shelf publishes
18
+ - `renderWithLanka` (from `@lankajs/solid/testing`) — a render with a bootstrapped framework
19
+
20
+ ## What a Solid call answers
21
+
22
+ An `Accessor`: `state().todos`. Solid has no re-render — a component function runs
23
+ ONCE and what updates is the DOM node that read the signal — so `renders()` in the
24
+ conformance suite counts what the reading effect ran, which is the closest thing
25
+ this framework has to the question every other binding answers directly.
26
+
27
+ ## Access tracking still earns its place, for a different reason
28
+
29
+ Solid already skips work a signal did not feed, so a coarse binding would be less
30
+ wrong here than elsewhere. It would still be wrong: without tracking, every change
31
+ writes a new object into the signal and every effect reading ANY part of it re-runs.
32
+ The tracker is what keeps the signal unchanged when nothing a reader looked at moved.
33
+
34
+ ## `onCleanup`, and the one case it is not there
35
+
36
+ Inside a component or a root, Solid releases the subscription with the owner. Called
37
+ outside one there is no owner, so the accessor carries `stop()` and the caller owns
38
+ it — the same seam `@lankajs/vue` has for the same reason, and neither framework
39
+ warns loudly enough for a note to be sufficient.
40
+
41
+ ---
42
+
43
+ Repository map: [../../../README.md](../../../README.md)
@@ -0,0 +1,31 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
+ // If the importer is in node compatibility mode or this is not an ESM
20
+ // file that has been converted to a CommonJS file using a Babel-
21
+ // compatible transform (i.e. "__esModule" has not been set), then set
22
+ // "default" to the CommonJS "module.exports" for node compatibility.
23
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
+ mod
25
+ ));
26
+
27
+ export {
28
+ __commonJS,
29
+ __toESM
30
+ };
31
+ //# sourceMappingURL=chunk-5WRI5ZAA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,109 @@
1
+ import { ILankaReadableVM } from 'lanka/viewmodel';
2
+ import { Accessor } from 'solid-js';
3
+
4
+ /**
5
+ * A ViewModel read the way Solid reads shared state.
6
+ *
7
+ * The state's own members, directly, plus the one meta member a caller needs.
8
+ * `$`-prefixed so it cannot collide with a state key, which is the same reason
9
+ * Solid's own stores keep their helpers off the object.
10
+ *
11
+ * Called a ViewModel and not a store, deliberately: `createStore` is Solid's
12
+ * noun for the shape, and what holds the state, the actions and the scenario
13
+ * bindings is the ViewModel.
14
+ */
15
+ type TLankaSolidVM<TState extends object> = TState & {
16
+ /** Releases the subscription. Rarely needed: an owner does it. */
17
+ $stop: () => void;
18
+ };
19
+ /**
20
+ * Reads a ViewModel the way Solid reads an object, with no call on the outside.
21
+ *
22
+ * ```tsx
23
+ * const todos = toLankaSolidVM(todosVM);
24
+ *
25
+ * <For each={todos.rows}>{(row) => <li>{row}</li>}</For>
26
+ * ```
27
+ *
28
+ * ## Why this exists beside `useLankaVM`
29
+ *
30
+ * `useLankaVM` answers an `Accessor`, which is Solid's own shape for a value and
31
+ * the one every other binding on the shelf parallels: `state().rows`. It is also
32
+ * not how Solid holds an OBJECT. `createStore` gives a proxy read as `state.rows`
33
+ * — no call, and the read itself is the subscription — and that is what a Solid
34
+ * codebase has in it. A consumer with that habit writes `todos.rows`, gets
35
+ * `undefined`, and learns that lanka is a foreign object.
36
+ *
37
+ * ## The read is the subscription, in both graphs at once
38
+ *
39
+ * A read goes through the access tracker, which records the key, AND through the
40
+ * signal, which registers the surrounding computation with Solid. One access,
41
+ * two graphs — the same alignment the Svelte binding gets from getters, and the
42
+ * reason neither of them needs a diff.
43
+ *
44
+ * The signal holds a VERSION rather than the state. A tracked read hands back the
45
+ * same proxy while the state object is unchanged, and Solid compares by identity,
46
+ * so a signal holding the state would be a no-op exactly when the tracker did its
47
+ * job — and a signal holding the state is also a SNAPSHOT, which is wrong for
48
+ * something read from ordinary code at arbitrary moments. `store.load()` followed
49
+ * by `store.rows` is the shape that settles it.
50
+ *
51
+ * ## What it is not
52
+ *
53
+ * Not `createStore`. Solid's store is a write path as well as a read one, and a
54
+ * ViewModel's writes belong to its actions — `setStore` beside them would be a
55
+ * second place state changes. This is the read half, which is the half a screen
56
+ * has.
57
+ */
58
+ declare const toLankaSolidVM: <TState extends object>(viewModel: ILankaReadableVM<TState>) => TLankaSolidVM<TState>;
59
+
60
+ /** A ViewModel read from Solid: an accessor, and a way to stop reading it. */
61
+ type TLankaVMAccessor<TValue> = Accessor<TValue> & {
62
+ /**
63
+ * Releases the subscription.
64
+ *
65
+ * Called for you by `onCleanup` inside a component or a root. It is published
66
+ * because a read made where there is no owner — module level, a test — has
67
+ * nobody to call it, and Solid warns about that case rather than handling it.
68
+ */
69
+ stop: () => void;
70
+ };
71
+ /**
72
+ * Reads a ViewModel from Solid.
73
+ *
74
+ * ```tsx
75
+ * export const TodoScreen = () => {
76
+ * const state = useLankaVM(todoVM);
77
+ *
78
+ * return <For each={state().todos}>{(todo) => <li>{todo.title}</li>}</For>;
79
+ * };
80
+ * ```
81
+ *
82
+ * Without a selector the accessor answers a Proxy that records which keys were
83
+ * read, and the signal changes only when one of THOSE moves. With a selector the
84
+ * selector decides and tracking is bypassed.
85
+ *
86
+ * ## Why tracking still earns its place here
87
+ *
88
+ * Solid already skips work a signal did not feed, so a coarse binding would be
89
+ * less wrong here than elsewhere. It would still be wrong: without tracking every
90
+ * change writes a new object into the signal, and every effect reading ANY part
91
+ * of it re-runs. The tracker is what keeps the signal UNCHANGED when nothing a
92
+ * reader looked at moved — and an unchanged signal is work Solid never starts.
93
+ *
94
+ * ## What "a render" means in a framework that has none
95
+ *
96
+ * A Solid component runs once; what updates is the DOM node that read the signal.
97
+ * So there is nothing here that corresponds to a re-render, and the conformance
98
+ * suite's `renders()` counts the reading effect's runs instead — which is the
99
+ * closest question this framework can be asked.
100
+ *
101
+ * ## What this function does NOT contain
102
+ *
103
+ * The recording, the comparison and the blind-spot warning are in core. If this
104
+ * file ever needs more than the port gives it, the port has the defect.
105
+ */
106
+ declare function useLankaVM<TState extends object>(viewModel: ILankaReadableVM<TState>): TLankaVMAccessor<TState>;
107
+ declare function useLankaVM<TState extends object, TSelected>(viewModel: ILankaReadableVM<TState>, selector: (state: TState) => TSelected): TLankaVMAccessor<TSelected>;
108
+
109
+ export { type TLankaSolidVM, type TLankaVMAccessor, toLankaSolidVM, useLankaVM };
package/dist/index.js ADDED
@@ -0,0 +1,63 @@
1
+ import "./chunk-5WRI5ZAA.js";
2
+
3
+ // src/to-lanka-solid-vm/toLankaSolidVM.ts
4
+ import { createSignal, getOwner, onCleanup } from "solid-js";
5
+ import { createLankaViewSubscription } from "lanka/extend";
6
+ var readsTheViewModel = (current, stop) => ({
7
+ get: (_target, key) => key === "$stop" ? stop : Reflect.get(current(), key),
8
+ has: (_target, key) => key === "$stop" || key in current(),
9
+ ownKeys: () => Reflect.ownKeys(current()),
10
+ /*
11
+ * Reported as configurable, always.
12
+ *
13
+ * A Proxy must not claim a non-configurable descriptor its target lacks — the
14
+ * runtime throws. The target here is a bare object while the keys live on the
15
+ * state, so every descriptor this hands back is invented and must say it can be
16
+ * redefined. Without it `{ ...store }` and `Object.keys(store)` throw rather
17
+ * than read, and a devtool does one of them on sight.
18
+ */
19
+ getOwnPropertyDescriptor: (_target, key) => key === "$stop" ? { value: stop, configurable: true, enumerable: false, writable: false } : { ...Reflect.getOwnPropertyDescriptor(current(), key), configurable: true }
20
+ });
21
+ var toLankaSolidVM = (viewModel) => {
22
+ const [version, setVersion] = createSignal(0);
23
+ const view = createLankaViewSubscription(viewModel, () => {
24
+ setVersion((seen) => seen + 1);
25
+ });
26
+ if (getOwner()) onCleanup(view.stop);
27
+ const current = () => {
28
+ void version();
29
+ return view.read();
30
+ };
31
+ return new Proxy({}, readsTheViewModel(current, view.stop));
32
+ };
33
+
34
+ // src/use-lanka-vm/useLankaVM.ts
35
+ import { createSignal as createSignal2, getOwner as getOwner2, onCleanup as onCleanup2 } from "solid-js";
36
+ import { createLankaAccessTracker } from "lanka/extend";
37
+ function useLankaVM(viewModel, selector) {
38
+ const tracker = createLankaAccessTracker(viewModel);
39
+ const read = () => selector ? selector(viewModel.getState()) : tracker.read();
40
+ const [state, setState] = createSignal2(read(), { equals: false });
41
+ const stop = viewModel.subscribe((next, prev) => {
42
+ if (selector) {
43
+ const picked = read();
44
+ if (Object.is(picked, state())) return;
45
+ setState(() => picked);
46
+ return;
47
+ }
48
+ if (!tracker.shouldNotify(next, prev)) {
49
+ tracker.reportSkipped(next, prev);
50
+ return;
51
+ }
52
+ setState(() => read());
53
+ });
54
+ const accessor = state;
55
+ accessor.stop = stop;
56
+ if (getOwner2()) onCleanup2(stop);
57
+ return accessor;
58
+ }
59
+ export {
60
+ toLankaSolidVM,
61
+ useLankaVM
62
+ };
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/to-lanka-solid-vm/toLankaSolidVM.ts","../src/use-lanka-vm/useLankaVM.ts"],"sourcesContent":["import { createSignal, getOwner, onCleanup } from \"solid-js\";\nimport { createLankaViewSubscription } from \"lanka/extend\";\nimport type { ILankaReadableVM } from \"lanka/viewmodel\";\n\n/**\n * A ViewModel read the way Solid reads shared state.\n *\n * The state's own members, directly, plus the one meta member a caller needs.\n * `$`-prefixed so it cannot collide with a state key, which is the same reason\n * Solid's own stores keep their helpers off the object.\n *\n * Called a ViewModel and not a store, deliberately: `createStore` is Solid's\n * noun for the shape, and what holds the state, the actions and the scenario\n * bindings is the ViewModel.\n */\nexport type TLankaSolidVM<TState extends object> = TState & {\n\t/** Releases the subscription. Rarely needed: an owner does it. */\n\t$stop: () => void;\n};\n\n/**\n * How the store answers for the ViewModel behind it.\n *\n * Its own function, because the traps are the whole mechanism and the factory\n * above is then the subscription and the Proxy. Read together they were sixty\n * lines whose shape said \"a function doing two things\", which is what the\n * composition canon calls it.\n */\nconst readsTheViewModel = <TState extends object, TStore extends object>(\n\tcurrent: () => TState,\n\tstop: () => void,\n): ProxyHandler<TStore> => ({\n\tget: (_target, key) => (key === \"$stop\" ? stop : Reflect.get(current(), key)),\n\n\thas: (_target, key) => key === \"$stop\" || key in current(),\n\n\townKeys: () => Reflect.ownKeys(current()),\n\n\t/*\n\t * Reported as configurable, always.\n\t *\n\t * A Proxy must not claim a non-configurable descriptor its target lacks — the\n\t * runtime throws. The target here is a bare object while the keys live on the\n\t * state, so every descriptor this hands back is invented and must say it can be\n\t * redefined. Without it `{ ...store }` and `Object.keys(store)` throw rather\n\t * than read, and a devtool does one of them on sight.\n\t */\n\tgetOwnPropertyDescriptor: (_target, key) =>\n\t\tkey === \"$stop\"\n\t\t\t? { value: stop, configurable: true, enumerable: false, writable: false }\n\t\t\t: { ...Reflect.getOwnPropertyDescriptor(current(), key), configurable: true },\n});\n\n/**\n * Reads a ViewModel the way Solid reads an object, with no call on the outside.\n *\n * ```tsx\n * const todos = toLankaSolidVM(todosVM);\n *\n * <For each={todos.rows}>{(row) => <li>{row}</li>}</For>\n * ```\n *\n * ## Why this exists beside `useLankaVM`\n *\n * `useLankaVM` answers an `Accessor`, which is Solid's own shape for a value and\n * the one every other binding on the shelf parallels: `state().rows`. It is also\n * not how Solid holds an OBJECT. `createStore` gives a proxy read as `state.rows`\n * — no call, and the read itself is the subscription — and that is what a Solid\n * codebase has in it. A consumer with that habit writes `todos.rows`, gets\n * `undefined`, and learns that lanka is a foreign object.\n *\n * ## The read is the subscription, in both graphs at once\n *\n * A read goes through the access tracker, which records the key, AND through the\n * signal, which registers the surrounding computation with Solid. One access,\n * two graphs — the same alignment the Svelte binding gets from getters, and the\n * reason neither of them needs a diff.\n *\n * The signal holds a VERSION rather than the state. A tracked read hands back the\n * same proxy while the state object is unchanged, and Solid compares by identity,\n * so a signal holding the state would be a no-op exactly when the tracker did its\n * job — and a signal holding the state is also a SNAPSHOT, which is wrong for\n * something read from ordinary code at arbitrary moments. `store.load()` followed\n * by `store.rows` is the shape that settles it.\n *\n * ## What it is not\n *\n * Not `createStore`. Solid's store is a write path as well as a read one, and a\n * ViewModel's writes belong to its actions — `setStore` beside them would be a\n * second place state changes. This is the read half, which is the half a screen\n * has.\n */\nexport const toLankaSolidVM = <TState extends object>(\n\tviewModel: ILankaReadableVM<TState>,\n): TLankaSolidVM<TState> => {\n\tconst [version, setVersion] = createSignal(0);\n\n\tconst view = createLankaViewSubscription(viewModel, () => {\n\t\tsetVersion((seen) => seen + 1);\n\t});\n\n\t// An owner is a component or a `createRoot`. Outside one there is nothing to\n\t// attach to and `onCleanup` would warn, so the caller keeps `$stop`.\n\tif (getOwner()) onCleanup(view.stop);\n\n\tconst current = (): TState => {\n\t\t// Read for the DEPENDENCY, discard the number. A computation reading\n\t\t// `store.rows` must re-run when the version moves, and the version is the\n\t\t// only signal in here.\n\t\tvoid version();\n\n\t\treturn view.read();\n\t};\n\n\treturn new Proxy({} as TLankaSolidVM<TState>, readsTheViewModel(current, view.stop));\n};\n","import { createSignal, getOwner, onCleanup } from \"solid-js\";\nimport { createLankaAccessTracker } from \"lanka/extend\";\nimport type { Accessor } from \"solid-js\";\nimport type { ILankaReadableVM } from \"lanka/viewmodel\";\n\n/** A ViewModel read from Solid: an accessor, and a way to stop reading it. */\nexport type TLankaVMAccessor<TValue> = Accessor<TValue> & {\n\t/**\n\t * Releases the subscription.\n\t *\n\t * Called for you by `onCleanup` inside a component or a root. It is published\n\t * because a read made where there is no owner — module level, a test — has\n\t * nobody to call it, and Solid warns about that case rather than handling it.\n\t */\n\tstop: () => void;\n};\n\n/**\n * Reads a ViewModel from Solid.\n *\n * ```tsx\n * export const TodoScreen = () => {\n * \tconst state = useLankaVM(todoVM);\n *\n * \treturn <For each={state().todos}>{(todo) => <li>{todo.title}</li>}</For>;\n * };\n * ```\n *\n * Without a selector the accessor answers a Proxy that records which keys were\n * read, and the signal changes only when one of THOSE moves. With a selector the\n * selector decides and tracking is bypassed.\n *\n * ## Why tracking still earns its place here\n *\n * Solid already skips work a signal did not feed, so a coarse binding would be\n * less wrong here than elsewhere. It would still be wrong: without tracking every\n * change writes a new object into the signal, and every effect reading ANY part\n * of it re-runs. The tracker is what keeps the signal UNCHANGED when nothing a\n * reader looked at moved — and an unchanged signal is work Solid never starts.\n *\n * ## What \"a render\" means in a framework that has none\n *\n * A Solid component runs once; what updates is the DOM node that read the signal.\n * So there is nothing here that corresponds to a re-render, and the conformance\n * suite's `renders()` counts the reading effect's runs instead — which is the\n * closest question this framework can be asked.\n *\n * ## What this function does NOT contain\n *\n * The recording, the comparison and the blind-spot warning are in core. If this\n * file ever needs more than the port gives it, the port has the defect.\n */\nexport function useLankaVM<TState extends object>(\n\tviewModel: ILankaReadableVM<TState>,\n): TLankaVMAccessor<TState>;\n\nexport function useLankaVM<TState extends object, TSelected>(\n\tviewModel: ILankaReadableVM<TState>,\n\tselector: (state: TState) => TSelected,\n): TLankaVMAccessor<TSelected>;\n\nexport function useLankaVM<TState extends object, TSelected>(\n\tviewModel: ILankaReadableVM<TState>,\n\tselector?: (state: TState) => TSelected,\n): TLankaVMAccessor<TState | TSelected> {\n\tconst tracker = createLankaAccessTracker(viewModel);\n\tconst read = (): TState | TSelected =>\n\t\tselector ? selector(viewModel.getState()) : tracker.read();\n\n\t// `equals: false` because a tracked read hands back the SAME proxy while the\n\t// state object is unchanged, and Solid compares by identity — so setting it\n\t// would be a no-op exactly when the tracker did its job. What decides whether\n\t// anything happens is `shouldNotify` below, which is the framework's answer\n\t// rather than the signal's.\n\tconst [state, setState] = createSignal<TState | TSelected>(read(), { equals: false });\n\n\tconst stop = viewModel.subscribe((next, prev) => {\n\t\tif (selector) {\n\t\t\tconst picked = read();\n\n\t\t\t// Only when the SELECTION moved. The signal is `equals: false`, so\n\t\t\t// setting it always wakes — which is right for a tracked read and wrong\n\t\t\t// for a selected one, and is what the suite's selector scenes refuse.\n\t\t\tif (Object.is(picked, state())) return;\n\n\t\t\tsetState(() => picked);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!tracker.shouldNotify(next, prev)) {\n\t\t\t// No update will follow. If the changed key is linked to this reader\n\t\t\t// through a getter it read, the screen froze — and in development core\n\t\t\t// says so by name.\n\t\t\ttracker.reportSkipped(next, prev);\n\t\t\treturn;\n\t\t}\n\n\t\tsetState(() => read());\n\t});\n\tconst accessor = state as TLankaVMAccessor<TState | TSelected>;\n\taccessor.stop = stop;\n\n\t// Inside a component or a root, Solid owns the lifetime and the subscription\n\t// goes with it. Outside one there is no owner, and `onCleanup` would warn —\n\t// so the caller keeps `stop`.\n\tif (getOwner()) onCleanup(stop);\n\n\treturn accessor;\n}\n"],"mappings":";;;AAAA,SAAS,cAAc,UAAU,iBAAiB;AAClD,SAAS,mCAAmC;AA2B5C,IAAM,oBAAoB,CACzB,SACA,UAC2B;AAAA,EAC3B,KAAK,CAAC,SAAS,QAAS,QAAQ,UAAU,OAAO,QAAQ,IAAI,QAAQ,GAAG,GAAG;AAAA,EAE3E,KAAK,CAAC,SAAS,QAAQ,QAAQ,WAAW,OAAO,QAAQ;AAAA,EAEzD,SAAS,MAAM,QAAQ,QAAQ,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWxC,0BAA0B,CAAC,SAAS,QACnC,QAAQ,UACL,EAAE,OAAO,MAAM,cAAc,MAAM,YAAY,OAAO,UAAU,MAAM,IACtE,EAAE,GAAG,QAAQ,yBAAyB,QAAQ,GAAG,GAAG,GAAG,cAAc,KAAK;AAC/E;AAyCO,IAAM,iBAAiB,CAC7B,cAC2B;AAC3B,QAAM,CAAC,SAAS,UAAU,IAAI,aAAa,CAAC;AAE5C,QAAM,OAAO,4BAA4B,WAAW,MAAM;AACzD,eAAW,CAAC,SAAS,OAAO,CAAC;AAAA,EAC9B,CAAC;AAID,MAAI,SAAS,EAAG,WAAU,KAAK,IAAI;AAEnC,QAAM,UAAU,MAAc;AAI7B,SAAK,QAAQ;AAEb,WAAO,KAAK,KAAK;AAAA,EAClB;AAEA,SAAO,IAAI,MAAM,CAAC,GAA4B,kBAAkB,SAAS,KAAK,IAAI,CAAC;AACpF;;;ACnHA,SAAS,gBAAAA,eAAc,YAAAC,WAAU,aAAAC,kBAAiB;AAClD,SAAS,gCAAgC;AA4DlC,SAAS,WACf,WACA,UACuC;AACvC,QAAM,UAAU,yBAAyB,SAAS;AAClD,QAAM,OAAO,MACZ,WAAW,SAAS,UAAU,SAAS,CAAC,IAAI,QAAQ,KAAK;AAO1D,QAAM,CAAC,OAAO,QAAQ,IAAIF,cAAiC,KAAK,GAAG,EAAE,QAAQ,MAAM,CAAC;AAEpF,QAAM,OAAO,UAAU,UAAU,CAAC,MAAM,SAAS;AAChD,QAAI,UAAU;AACb,YAAM,SAAS,KAAK;AAKpB,UAAI,OAAO,GAAG,QAAQ,MAAM,CAAC,EAAG;AAEhC,eAAS,MAAM,MAAM;AAErB;AAAA,IACD;AAEA,QAAI,CAAC,QAAQ,aAAa,MAAM,IAAI,GAAG;AAItC,cAAQ,cAAc,MAAM,IAAI;AAChC;AAAA,IACD;AAEA,aAAS,MAAM,KAAK,CAAC;AAAA,EACtB,CAAC;AACD,QAAM,WAAW;AACjB,WAAS,OAAO;AAKhB,MAAIC,UAAS,EAAG,CAAAC,WAAU,IAAI;AAE9B,SAAO;AACR;","names":["createSignal","getOwner","onCleanup"]}
@@ -0,0 +1,46 @@
1
+ import { render } from '@solidjs/testing-library';
2
+ import { IPrepareLankaRenderOptions } from '@lankajs/tool-testing';
3
+ import { ILankaInstance } from 'lanka';
4
+
5
+ type TSolidRender = typeof render;
6
+ interface IRenderWithLankaOptions extends Omit<NonNullable<Parameters<TSolidRender>[1]>, "wrapper">, IPrepareLankaRenderOptions {
7
+ }
8
+ /**
9
+ * What a render with a bootstrapped framework ADDS to the library's own result.
10
+ *
11
+ * An interface over the addition rather than over the whole result, and the same
12
+ * in all five bindings: Svelte Testing Library's result carries a string index
13
+ * signature for its bound queries, so a named member added by extension has to
14
+ * satisfy it — and `lanka` is an instance, not a query. Describing only the
15
+ * addition is true of every library and needs no cast anywhere.
16
+ */
17
+ interface IRenderWithLankaResult {
18
+ /** The instance the render used. */
19
+ lanka: ILankaInstance;
20
+ }
21
+ /**
22
+ * Rendering a Solid tree with a bootstrapped framework.
23
+ *
24
+ * ## Why
25
+ *
26
+ * A component reading a ViewModel needs a live instance: without one the first
27
+ * scenario or locator access fails. Assembling bootstrap in every component test
28
+ * is twenty lines of preamble that diverge between files silently.
29
+ *
30
+ * ## What is here, and what is in the kit
31
+ *
32
+ * The five bindings publish this name and differ only in which `render` they
33
+ * call. Everything else — a fresh instance, the doubles, the caller's setup and
34
+ * the scenario layer brought up in that order — is `prepareLankaRender` in
35
+ * `@lankajs/tool-testing`, which is the one place all five already look.
36
+ *
37
+ * ## The option and result types are DERIVED, not named
38
+ *
39
+ * Solid Testing Library publishes no `RenderOptions` or `RenderResult` type to
40
+ * import — it exports functions and lets inference do the rest. Reading them off
41
+ * `render` itself is therefore the honest spelling, and it cannot drift from the
42
+ * library the way a hand-copied interface would.
43
+ */
44
+ declare const renderWithLanka: (ui: Parameters<TSolidRender>[0], options?: IRenderWithLankaOptions) => ReturnType<TSolidRender> & IRenderWithLankaResult;
45
+
46
+ export { type IRenderWithLankaOptions, type IRenderWithLankaResult, renderWithLanka };