Skip to content

Commit f200289

Browse files
Merge pull request #65 from zeixcom/feature/ci-workflow
Feature/ci workflow
2 parents c999f5c + 9a3f185 commit f200289

31 files changed

Lines changed: 273 additions & 283 deletions

.github/workflows/ci.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, next]
6+
pull_request:
7+
branches: [main, next]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout repository
14+
uses: actions/checkout@v4
15+
16+
- name: Setup Bun
17+
uses: oven-sh/setup-bun@v1
18+
with:
19+
bun-version: latest
20+
21+
- name: Install dependencies
22+
run: bun install --frozen-lockfile
23+
24+
- name: Typecheck
25+
run: bunx tsc --noEmit
26+
27+
- name: Lint and format
28+
run: bunx biome check .
29+
30+
- name: Unit tests
31+
run: bun run test
32+
33+
- name: Bundle size regression
34+
run: bun test test/regression-bundle.test.ts
35+
36+
- name: Build
37+
run: bun run build
38+
39+
performance:
40+
runs-on: ubuntu-latest
41+
continue-on-error: true # informational only — shared runners are too noisy for timing assertions
42+
steps:
43+
- name: Checkout repository
44+
uses: actions/checkout@v4
45+
46+
- name: Setup Bun
47+
uses: oven-sh/setup-bun@v1
48+
with:
49+
bun-version: latest
50+
51+
- name: Install dependencies
52+
run: bun install --frozen-lockfile
53+
54+
- name: Performance regression (informational)
55+
run: bun test test/regression-performance.test.ts

.github/workflows/npm-publish.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ jobs:
2222
- name: Install all dependencies (including devDependencies for build)
2323
run: bun install
2424

25+
- name: Typecheck, lint, test, and bundle regression
26+
run: bun run check
27+
2528
- name: Build package
2629
run: bun run build
2730

.zed/settings.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@
44
"language_servers": ["!eslint", "..."],
55
"code_actions_on_format": {
66
"source.fixAll.biome": true,
7-
"source.organizeImports.biome": true,
8-
},
7+
"source.organizeImports.biome": true
8+
}
99
},
1010
"JavaScript": {
1111
"language_servers": ["!eslint", "..."],
1212
"code_actions_on_format": {
1313
"source.fixAll.biome": true,
14-
"source.organizeImports.biome": true,
15-
},
14+
"source.organizeImports.biome": true
15+
}
1616
},
1717
"TSX": {
1818
"language_servers": ["!eslint", "..."],
1919
"code_actions_on_format": {
2020
"source.fixAll.biome": true,
21-
"source.organizeImports.biome": true,
22-
},
23-
},
24-
},
21+
"source.organizeImports.biome": true
22+
}
23+
}
24+
}
2525
}

bench/reactivity.bench.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,8 +648,7 @@ group('Collection: chain 5 derivations (100 items)', () => {
648648
bench('cause-effect', () => {
649649
const list = createList(Array.from({ length: 100 }, (_, i) => i + 1))
650650
let col = list.deriveCollection((v: number) => v * 2)
651-
for (let i = 1; i < 5; i++)
652-
col = col.deriveCollection((v: number) => v + 1)
651+
for (let i = 1; i < 5; i++) col = col.deriveCollection((v: number) => v + 1)
653652
col.get()
654653
})
655654
})

biome.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
},
2222
"javascript": {
2323
"formatter": {
24-
"quoteStyle": "double"
24+
"quoteStyle": "single",
25+
"semicolons": "asNeeded",
26+
"arrowParentheses": "asNeeded"
2527
}
2628
},
2729
"assist": {

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"bench": "bun run bench/reactivity.bench.ts",
3939
"test": "bun test --path-ignore-patterns=**/regression*",
4040
"regression": "bun test test/regression-performance.test.ts && bun test test/regression-bundle.test.ts",
41-
"lint": "bunx biome lint --write"
41+
"check": "bunx tsc --noEmit && bunx biome check . && bun run test && bun test test/regression-bundle.test.ts",
42+
"lint": "bunx biome check --write"
4243
}
4344
}

src/errors.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,7 @@ class InvalidStoreMutationError extends TypeError {
173173
* @param prop - The property name that was directly mutated.
174174
* @param action - The kind of mutation attempted (`'assign to'`, `'delete'`, or `'define'`).
175175
*/
176-
constructor(
177-
prop: string,
178-
action: 'assign to' | 'delete' | 'define',
179-
) {
176+
constructor(prop: string, action: 'assign to' | 'delete' | 'define') {
180177
const guidance =
181178
action === 'delete'
182179
? `use store.remove(${JSON.stringify(prop)})`

src/graph.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,7 @@ const deepEqualInner = (
236236
): boolean => {
237237
if (Object.is(a, b)) return true
238238
if (typeof a !== typeof b) return false
239-
if (
240-
a == null ||
241-
typeof a !== 'object' ||
242-
b == null ||
243-
typeof b !== 'object'
244-
)
239+
if (a == null || typeof a !== 'object' || b == null || typeof b !== 'object')
245240
return false
246241

247242
// Cycle guard: if `a` is already on the current recursion path, treat this
@@ -406,8 +401,7 @@ function propagate(node: SinkNode, newFlag = FLAG_DIRTY): void {
406401
}
407402

408403
// Propagate Check to sinks
409-
for (let e = node.sinks; e; e = e.nextSink)
410-
propagate(e.sink, FLAG_CHECK)
404+
for (let e = node.sinks; e; e = e.nextSink) propagate(e.sink, FLAG_CHECK)
411405
} else {
412406
if ((flags & (FLAG_DIRTY | FLAG_CHECK)) >= newFlag) return
413407

@@ -520,8 +514,7 @@ function recomputeTask(node: TaskNode<unknown & {}>): void {
520514
if (node.error || !node.equals(next, node.value)) {
521515
node.value = next
522516
node.error = undefined
523-
for (let e = node.sinks; e; e = e.nextSink)
524-
propagate(e.sink)
517+
for (let e = node.sinks; e; e = e.nextSink) propagate(e.sink)
525518
}
526519
setState(node.pendingNode, false)
527520
})
@@ -539,8 +532,7 @@ function recomputeTask(node: TaskNode<unknown & {}>): void {
539532
) {
540533
// We don't clear old value on errors
541534
node.error = error
542-
for (let e = node.sinks; e; e = e.nextSink)
543-
propagate(e.sink)
535+
for (let e = node.sinks; e; e = e.nextSink) propagate(e.sink)
544536
}
545537
setState(node.pendingNode, false)
546538
})
@@ -580,11 +572,7 @@ function refresh(node: SinkNode): void {
580572

581573
if (node.flags & FLAG_RUNNING) {
582574
throw new CircularDependencyError(
583-
'controller' in node
584-
? TYPE_TASK
585-
: 'value' in node
586-
? TYPE_MEMO
587-
: 'Effect',
575+
'controller' in node ? TYPE_TASK : 'value' in node ? TYPE_MEMO : 'Effect',
588576
)
589577
}
590578

src/nodes/collection.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ type Collection<T extends {}, S extends Signal<T> = Signal<T>> = {
6161
byKey(key: string): S | undefined
6262
keyAt(index: number): string | undefined
6363
indexOfKey(key: string): number
64-
deriveCollection<R extends {}>(
65-
callback: (sourceValue: T) => R,
66-
): Collection<R>
64+
deriveCollection<R extends {}>(callback: (sourceValue: T) => R): Collection<R>
6765
deriveCollection<R extends {}>(
6866
callback: (sourceValue: T, abort: AbortSignal) => Promise<R>,
6967
): Collection<R>
@@ -154,10 +152,7 @@ function deriveCollection<T extends {}, U extends {}>(
154152
const sourceValue = itemSignal.get() as U
155153
if (sourceValue == null) return prev as T
156154
return (
157-
callback as (
158-
sourceValue: U,
159-
abort: AbortSignal,
160-
) => Promise<T>
155+
callback as (sourceValue: U, abort: AbortSignal) => Promise<T>
161156
)(sourceValue, abort)
162157
})
163158
: createMemo(() => {

src/nodes/effect.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import {
1414
registerCleanup,
1515
runCleanup,
1616
runEffect,
17-
scheduleEffect,
1817
type Signal,
18+
scheduleEffect,
1919
trimSources,
2020
} from '../graph'
2121
import { isTask } from './task'
@@ -32,9 +32,11 @@ type MaybePromise<T> = T | Promise<T>
3232
*/
3333
type MatchHandlers<T extends readonly Signal<unknown & {}>[]> = {
3434
/** Called when all signals have a value. Receives a tuple of resolved values. */
35-
ok: (values: {
36-
[K in keyof T]: T[K] extends Signal<infer V> ? V : never
37-
}) => MaybePromise<MaybeCleanup>
35+
ok: (
36+
values: {
37+
[K in keyof T]: T[K] extends Signal<infer V> ? V : never
38+
},
39+
) => MaybePromise<MaybeCleanup>
3840
/** Called when one or more signals hold an error. Defaults to `console.error`. */
3941
err?: (errors: readonly Error[]) => MaybePromise<MaybeCleanup>
4042
/** Called when one or more signals are unset (pending). */
@@ -221,12 +223,14 @@ function match(
221223
const owner = activeOwner
222224
const controller = new AbortController()
223225
registerCleanup(owner, () => controller.abort())
224-
out.then(cleanup => {
225-
if (!controller.signal.aborted && typeof cleanup === 'function')
226-
registerCleanup(owner, cleanup)
227-
}).catch(e => {
228-
err([e instanceof Error ? e : new Error(String(e))])
229-
})
226+
out
227+
.then(cleanup => {
228+
if (!controller.signal.aborted && typeof cleanup === 'function')
229+
registerCleanup(owner, cleanup)
230+
})
231+
.catch(e => {
232+
err([e instanceof Error ? e : new Error(String(e))])
233+
})
230234
}
231235
}
232236

0 commit comments

Comments
 (0)