Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
95db6ce
Updated CHANGELOG and package.json
hexplus Mar 28, 2026
56080d8
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 28, 2026
7eeec49
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 28, 2026
14a9cd4
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
9487727
ci: use npm install instead of npm ci
hexplus Mar 29, 2026
6b4bd83
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
0b9a0cc
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
0777184
trusted-publisher
hexplus Mar 29, 2026
4d46e82
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
bea9788
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
825a8dc
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
55c4436
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
0d2c7e0
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
8da81e8
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
325ce5d
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Mar 29, 2026
0cad329
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Apr 1, 2026
aea6787
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Apr 4, 2026
00e5e88
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Apr 7, 2026
b10a2c5
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Apr 7, 2026
639eae0
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Apr 9, 2026
405e4fe
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Apr 11, 2026
ee7cf48
Updated main
hexplus Apr 11, 2026
8c77fca
Merge branch 'main' of https://github.com/hexplus/SibuJS
hexplus Apr 11, 2026
35787c1
refactor(sibujs): remove duplicate reactive aliases (createSignal, cr…
hexplus Apr 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,54 @@ This project follows [Semantic Versioning](https://semver.org/).

---

## [1.4.0] — 2026-04-11

Cleanup release. Removes six public aliases that contradicted the SibuJS philosophy — plain verbs, no framework ceremony, no redundant synonyms for the same primitive. All of the removed APIs were either one-line forwards to an existing primitive or identity wrappers; every existing example can be rewritten by deleting the wrapper and calling the underlying primitive directly.

### Removed

- **`createSignal`** — was `return signal(value)`. Use `signal()` directly.
- **`createMemo`** — was `return derived(fn)`. Use `derived()` directly.
- **`createEffect`** — was `return effect(fn)`. Use `effect()` directly.
- **`memo`** — was `return derived(factory)`. Use `derived()` directly.
- **`memoFn`** — was `return derived(callback)`. Use `derived()` directly.
- **`composable`** — was `return setup` (identity function). Plain functions are already composables in SibuJS; just write one and call it.

The three removed files (`src/patterns/primitives.ts`, `src/core/signals/memo.ts`, `src/core/signals/memoFn.ts`) are currently empty stubs exporting nothing — they can be deleted from disk in a follow-up commit without further code changes.

### Migration

```ts
// before
import { createSignal, createMemo, createEffect, memo, memoFn, composable } from "sibujs";

const [count, setCount] = createSignal(0);
const doubled = createMemo(() => count() * 2);
const sorted = memo(() => items().slice().sort());
const handler = memoFn(() => (e: Event) => process(e));
createEffect(() => console.log(count()));
const useCounter = composable(() => { /* … */ });

// after
import { signal, derived, effect } from "sibujs";

const [count, setCount] = signal(0);
const doubled = derived(() => count() * 2);
const sorted = derived(() => items().slice().sort());
const handler = derived(() => (e: Event) => process(e));
effect(() => console.log(count()));
function useCounter() { /* … */ }
```

### Also updated

- `generateComponentMetadata`, `generateTypeStubs`, and the Vite/Webpack pure-annotation factory list in `sibujs/build` no longer mention the removed names.
- Lint rule `no-signals-in-conditionals` no longer checks `memo` / `memoFn` (they don't exist).
- `SignalNodeSnapshot.kind` comment updated to drop the `"memo"` tag.
- Test suite: `tests/primitives.test.ts`, `tests/memo.test.ts`, `tests/memoFn.test.ts` reduced to placeholder stubs; `tests/types.test.ts` and `tests/ide.test.ts` updated to assert the aliases are gone. Suite: **2105/2105 passing** (down from 2113 by exactly the 8 deleted alias-specific tests).

---

## [1.3.0] — 2026-04-11

Large minor release. Adds **27 new reactive/DOM primitives**, a full **SSR + OWASP security hardening pass** (A01, A02, A03, A10 + CWE-1321 prototype pollution), **10 ergonomic features** that stay inside the SibuJS philosophy (No VDOM, No JSX, No compilation, Zero dependencies, fine-grained reactivity), **typed tag factory overloads** for common elements, and a new **`tag(props, children)` positional shorthand** that removes the need for the `nodes:` key at every level of the tree. Test suite grew from **1875 → 2113** passing tests (+238, **0 regressions**).
Expand Down
2 changes: 0 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ export * from "./src/core/signals/derived";
export * from "./src/core/signals/watch";
export * from "./src/core/signals/store";
export * from "./src/core/signals/ref";
export * from "./src/core/signals/memo";
export * from "./src/core/signals/memoFn";
export * from "./src/core/signals/array";
export * from "./src/core/signals/deepSignal";
export * from "./src/core/signals/writable";
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sibujs",
"version": "1.3.0",
"version": "1.4.0",
"description": "A lightweight, function-based frontend framework that combines the best of React, Svelte, and Vue — with zero VDOM and maximum simplicity. Designed for developers who want fine-grained reactivity and full control without compilation or magic.",
"keywords": [
"frontend",
Expand Down
1 change: 0 additions & 1 deletion patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export * from "./src/patterns/persist";
export * from "./src/patterns/optimistic";
export * from "./src/patterns/timeTravel";
export * from "./src/patterns/globalStore";
export * from "./src/patterns/primitives";

// Component patterns
export * from "./src/patterns/hoc";
Expand Down
3 changes: 0 additions & 3 deletions src/build/analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,11 @@ export const moduleSizes: Record<string, number> = {
"core/watch": 300,
"core/store": 380,
"core/ref": 150,
"core/memo": 180,
"core/memoFn": 160,
"core/array": 420,
"core/deepSignal": 500,
"core/lifecycle": 300,
"core/context": 350,
"core/persist": 400,
"core/primitives": 200,
"core/hoc": 280,
"core/transition": 600,
"core/form": 750,
Expand Down
82 changes: 0 additions & 82 deletions src/build/ide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,31 +68,6 @@ export function getComponentMetadata(): ComponentMeta[] {
},
],
},
{
name: "memo",
description:
"Returns a memoized value that only recomputes when its reactive dependencies change. Alias for derived.",
props: [
{
name: "factory",
type: "() => T",
required: true,
description: "Function that computes the memoized value",
},
],
},
{
name: "memoFn",
description: "Returns a memoized callback that only updates when its reactive dependencies change.",
props: [
{
name: "callback",
type: "() => T",
required: true,
description: "The callback factory function to memoize",
},
],
},
{
name: "ref",
description:
Expand Down Expand Up @@ -140,44 +115,6 @@ export function getComponentMetadata(): ComponentMeta[] {
],
},

// ── SolidJS-style Primitives ─────────────────────────────────────
{
name: "createSignal",
description: "Creates a reactive signal. SolidJS-style alias for signal. Returns [getter, setter].",
props: [
{
name: "value",
type: "T",
required: true,
description: "Initial value",
},
],
},
{
name: "createMemo",
description: "Creates a derived/computed reactive value. SolidJS-style alias for derived.",
props: [
{
name: "fn",
type: "() => T",
required: true,
description: "Computation function that reads other signals",
},
],
},
{
name: "createEffect",
description: "Creates a reactive side effect. SolidJS-style alias for effect.",
props: [
{
name: "fn",
type: "() => void",
required: true,
description: "Effect function that reads reactive signals",
},
],
},

// ── Lifecycle ────────────────────────────────────────────────────
{
name: "onMount",
Expand Down Expand Up @@ -531,11 +468,6 @@ export function generateVSCodeSnippets(): Record<
],
description: "Create a reactive form with validation",
},
"SibuJS createSignal": {
prefix: "sibu-signal",
body: ["const [${1:value}, ${2:setValue}] = createSignal(${3:initialValue});"],
description: "Create a reactive signal (SolidJS-style alias for signal)",
},
};
}

Expand Down Expand Up @@ -583,12 +515,6 @@ export function generateTypeStubs(): Record<string, string> {

derived: ["declare function derived<T>(getter: () => T): () => T;"].join("\n"),

memo: ["declare function memo<T>(factory: () => T): () => T;"].join("\n"),

memoFn: ["declare function memoFn<T extends (...args: unknown[]) => unknown>(callback: () => T): () => T;"].join(
"\n",
),

ref: [
"interface Ref<T> { current: T; }",
"declare function ref<T>(initial: T): Ref<T>;",
Expand All @@ -610,14 +536,6 @@ export function generateTypeStubs(): Record<string, string> {
"declare function store<T extends object>(initialState: T): [{ readonly [K in keyof T]: T[K] }, StoreActions<T>];",
].join("\n"),

createSignal: ["declare function createSignal<T>(value: T): [() => T, (next: T | ((prev: T) => T)) => void];"].join(
"\n",
),

createMemo: ["declare function createMemo<T>(fn: () => T): () => T;"].join("\n"),

createEffect: ["declare function createEffect(fn: () => void): () => void;"].join("\n"),

mount: [
"declare function mount(component: (() => HTMLElement) | HTMLElement | Node, container: HTMLElement | null): { node: Node; unmount: () => void };",
].join("\n"),
Expand Down
2 changes: 1 addition & 1 deletion src/build/linting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const lintRules = {
description: "Signal functions should not be called inside conditionals, loops, or nested functions",
check(source: string): LintViolation[] {
const violations: LintViolation[] = [];
const hookNames = ["signal", "effect", "derived", "memo", "memoFn", "ref", "watch", "store"];
const hookNames = ["signal", "effect", "derived", "ref", "watch", "store"];
const hookPattern = new RegExp(`\\b(${hookNames.join("|")})\\s*\\(`, "g");
const lines = source.split("\n");

Expand Down
1 change: 0 additions & 1 deletion src/build/vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ function injectPureAnnotations(code: string): string {
const sibuFactories = [
"tagFactory",
"context",
"composable",
"defineComponent",
"withProps",
"withDefaults",
Expand Down
1 change: 0 additions & 1 deletion src/build/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export interface SibuWebpackPluginOptions {
const PURE_FACTORIES = [
"tagFactory",
"context",
"composable",
"defineComponent",
"withProps",
"withDefaults",
Expand Down
20 changes: 4 additions & 16 deletions src/core/signals/memo.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
import { derived } from "./derived";
import type { Accessor } from "./signal";

/**
* memo returns a memoized value that only recomputes when its
* reactive dependencies change. This is semantically identical to
* derived but named for convenience.
*
* Use this to avoid expensive computations on every render cycle.
*
* @param factory Function that computes the memoized value
* @returns Getter function that returns the memoized value
*/
export function memo<T>(factory: () => T): Accessor<T> {
return derived(factory);
}
// Removed in 1.4.0: memo was a thin alias for derived. Use derived()
// directly. This file is kept as an empty stub and can be removed in a
// follow-up commit.
export {};
18 changes: 4 additions & 14 deletions src/core/signals/memoFn.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@
import { derived } from "./derived";
import type { Accessor } from "./signal";

/**
* memoFn returns a memoized callback function that only updates
* when its reactive dependencies change. This prevents unnecessary
* re-creations of callback functions passed to child components.
*
* @param callback The callback function to memoize
* @returns Getter that returns the current memoized callback
*/
export function memoFn<T extends (...args: any[]) => any>(callback: () => T): Accessor<T> {
return derived(callback);
}
// Removed in 1.4.0: memoFn was a thin alias for derived. Use derived()
// directly. This file is kept as an empty stub and can be removed in a
// follow-up commit.
export {};
2 changes: 1 addition & 1 deletion src/core/signals/signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { isDev } from "../dev";
declare const __accessor: unique symbol;

/**
* A reactive signal getter returned by signal(), derived(), memo(), and similar primitives.
* A reactive signal getter returned by signal(), derived(), and similar primitives.
*
* Pass an Accessor directly into reactive prop positions — never call it there:
* ```ts
Expand Down
2 changes: 1 addition & 1 deletion src/devtools/signalGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export interface SignalNodeSnapshot {
id: string;
/** Debug name, if the caller tagged the signal. */
name: string | null;
/** Runtime type tag: `"signal"`, `"derived"`, `"memo"`, `"effect"`. */
/** Runtime type tag: `"signal"`, `"derived"`, `"effect"`. */
kind: string;
/** Best-effort preview of the current value. */
value: string;
Expand Down
14 changes: 5 additions & 9 deletions src/patterns/composable.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
// ============================================================================
// COMPOSABLES & COMPONENT PATTERNS
// COMPONENT PATTERNS
// ============================================================================

/**
* composable wraps a setup function to create reusable stateful logic.
* Similar to Vue 3 composables — encapsulates reactive state and methods.
*/
export function composable<T>(setup: () => T): () => T {
return setup;
}
//
// Note: `composable()` was removed in 1.4.0 — it was an identity wrapper
// (`return setup`) that added nothing over calling the setup function
// directly. Plain functions are already composables in SibuJS.

/**
* RenderProp implements the render-prop pattern.
Expand Down
65 changes: 5 additions & 60 deletions src/patterns/primitives.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,5 @@
import { derived } from "../core/signals/derived";
import { effect } from "../core/signals/effect";
import { signal } from "../core/signals/signal";

/**
* SolidJS-style reactive primitives — standalone APIs that don't require
* being inside a component. These are thin wrappers around the signal system.
*/

/**
* Creates a reactive signal. Equivalent to signal but with SolidJS naming.
*
* @param value Initial value
* @returns Tuple [getter, setter]
*
* @example
* ```ts
* const [count, setCount] = createSignal(0);
* console.log(count()); // 0
* setCount(5);
* ```
*/
export function createSignal<T>(value: T): [() => T, (next: T | ((prev: T) => T)) => void] {
return signal(value);
}

/**
* Creates a derived/computed reactive value. Equivalent to derived.
*
* @param fn Computation function that reads other signals
* @returns Getter for the computed value
*
* @example
* ```ts
* const [count] = createSignal(5);
* const doubled = createMemo(() => count() * 2);
* console.log(doubled()); // 10
* ```
*/
export function createMemo<T>(fn: () => T): () => T {
return derived(fn);
}

/**
* Creates a reactive side effect. Equivalent to effect.
*
* @param fn Effect function that reads reactive signals
* @returns Cleanup/teardown function
*
* @example
* ```ts
* const [count] = createSignal(0);
* const cleanup = createEffect(() => {
* console.log("Count is:", count());
* });
* ```
*/
export function createEffect(fn: () => void): () => void {
return effect(fn);
}
// Removed in 1.4.0: createSignal / createMemo / createEffect were thin
// aliases for signal / derived / effect. Use the canonical primitives from
// "sibujs" instead. This file is kept as an empty stub to avoid a delete
// in this change set; it can be removed in a follow-up commit.
export {};
2 changes: 1 addition & 1 deletion src/plugins/ecosystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const bundlerMetadata = {
sideEffects: false as const,
modules: {
core: ["html", "mount", "each", "slots", "fragment", "catch", "portal", "directives"],
hooks: ["signal", "effect", "derived", "watch", "store", "ref", "memo", "memoFn", "array", "deepSignal"],
hooks: ["signal", "effect", "derived", "watch", "store", "ref", "array", "deepSignal"],
plugins: ["router", "i18n"],
components: ["ErrorBoundary", "Loading"],
ssr: ["ssr"],
Expand Down
Loading
Loading