-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add createActorFromLogic, createActorWith
This adds two curried functions to help create actors
- Loading branch information
Showing
3 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { | ||
type Actor, | ||
type ActorOptions, | ||
type AnyActorLogic, | ||
createActor, | ||
type InputFrom, | ||
type IsNotNever, | ||
} from 'xstate'; | ||
|
||
export type RequiredOptions<TLogic extends AnyActorLogic> = | ||
undefined extends InputFrom<TLogic> ? never : 'input'; | ||
|
||
export type CreateActorOptions<TLogic extends AnyActorLogic> = | ||
IsNotNever<RequiredOptions<TLogic>> extends true | ||
? {input: ActorOptions<TLogic>['input']} & ActorOptions<TLogic> | ||
: ActorOptions<TLogic>; | ||
|
||
export type CurryCreateActorFromLogic = (() => CurryCreateActorFromLogic) & | ||
(<TLogic extends AnyActorLogic>( | ||
logic: TLogic, | ||
options: CreateActorOptions<TLogic>, | ||
) => Actor<TLogic>) & | ||
(<TLogic extends AnyActorLogic>( | ||
logic: TLogic, | ||
) => CurryCreateActorFromLogicP1<TLogic>); | ||
|
||
export type CurryCreateActorFromLogicP1<TLogic extends AnyActorLogic> = (( | ||
options: CreateActorOptions<TLogic>, | ||
) => Actor<TLogic>) & | ||
(() => CurryCreateActorFromLogicP1<TLogic>); | ||
|
||
export type CurryCreateActorWith = (() => CurryCreateActorWith) & | ||
(<TLogic extends AnyActorLogic>( | ||
options: CreateActorOptions<TLogic>, | ||
logic: TLogic, | ||
) => Actor<TLogic>) & | ||
(<TLogic extends AnyActorLogic>( | ||
options: CreateActorOptions<TLogic>, | ||
) => CurryCreateActorWithP1<TLogic>); | ||
|
||
export type CurryCreateActorWithP1<TLogic extends AnyActorLogic> = (( | ||
logic: TLogic, | ||
) => Actor<TLogic>) & | ||
(() => CurryCreateActorWithP1<TLogic>); | ||
|
||
export function createActorFromLogic(): typeof createActorFromLogic; | ||
|
||
export function createActorFromLogic<TLogic extends AnyActorLogic>( | ||
logic: TLogic, | ||
): CurryCreateActorFromLogicP1<TLogic>; | ||
|
||
export function createActorFromLogic<TLogic extends AnyActorLogic>( | ||
logic: TLogic, | ||
options: CreateActorOptions<TLogic>, | ||
): Actor<TLogic>; | ||
|
||
export function createActorFromLogic<TLogic extends AnyActorLogic>( | ||
logic?: TLogic, | ||
options?: CreateActorOptions<TLogic>, | ||
) { | ||
if (logic) { | ||
if (options) { | ||
return createActor(logic, options); | ||
} | ||
|
||
return ((options?: CreateActorOptions<TLogic>) => { | ||
return options | ||
? createActorFromLogic(logic, options) | ||
: createActorFromLogic(logic); | ||
}) as CurryCreateActorFromLogicP1<TLogic>; | ||
} | ||
|
||
return createActorFromLogic; | ||
} | ||
|
||
export function createActorWith(): typeof createActorWith; | ||
|
||
export function createActorWith<TLogic extends AnyActorLogic>( | ||
options: CreateActorOptions<TLogic>, | ||
): CurryCreateActorWithP1<TLogic>; | ||
|
||
export function createActorWith<TLogic extends AnyActorLogic>( | ||
options: CreateActorOptions<TLogic>, | ||
logic: TLogic, | ||
): Actor<TLogic>; | ||
|
||
export function createActorWith<TLogic extends AnyActorLogic>( | ||
options?: CreateActorOptions<TLogic>, | ||
logic?: TLogic, | ||
) { | ||
if (options) { | ||
if (logic) { | ||
return createActor(logic, options); | ||
} | ||
|
||
return ((logic?: TLogic) => { | ||
return logic ? createActorWith(options, logic) : createActorWith(options); | ||
}) as CurryCreateActorWithP1<TLogic>; | ||
} | ||
|
||
return createActorWith; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import {strict as assert} from 'node:assert'; | ||
import {afterEach, describe, it} from 'node:test'; | ||
import {Actor} from 'xstate'; | ||
|
||
import {createActorFromLogic, createActorWith} from '../src/create-actor.js'; | ||
import {dummyLogic} from './fixture.js'; | ||
|
||
describe('create-actor', () => { | ||
describe('createActorFromLogic()', () => { | ||
let actor: Actor<typeof dummyLogic>; | ||
|
||
afterEach(() => { | ||
if (actor) { | ||
actor.stop(); | ||
} | ||
}); | ||
|
||
describe('when called with logic and options', () => { | ||
it('should create an actor with the provided logic and options', () => { | ||
const options = {id: 'test-actor'}; | ||
|
||
actor = createActorFromLogic(dummyLogic, options); | ||
|
||
assert.ok(actor instanceof Actor); | ||
}); | ||
}); | ||
|
||
describe('when called with only logic', () => { | ||
it('should return a curried function that accepts options', () => { | ||
const curriedFn = createActorFromLogic(dummyLogic); | ||
|
||
assert.equal(typeof curriedFn, 'function'); | ||
|
||
const options = {id: 'test-actor'}; | ||
|
||
actor = curriedFn(options); | ||
|
||
assert.equal(actor.id, options.id); | ||
assert.equal(actor.logic, dummyLogic); | ||
}); | ||
}); | ||
|
||
describe('when called with no arguments', () => { | ||
it('should return itself', () => { | ||
const curriedFn = createActorFromLogic(); | ||
|
||
assert.equal(curriedFn, createActorFromLogic); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('createActorWith()', () => { | ||
let actor: Actor<typeof dummyLogic>; | ||
|
||
afterEach(() => { | ||
if (actor) { | ||
actor.stop(); | ||
} | ||
}); | ||
|
||
describe('when called with logic and options', () => { | ||
it('should create an actor with the provided logic and options', () => { | ||
const options = {id: 'test-actor'}; | ||
|
||
actor = createActorWith(options, dummyLogic); | ||
|
||
assert.ok(actor instanceof Actor); | ||
assert.equal(actor.id, options.id); | ||
assert.equal(actor.logic, dummyLogic); | ||
}); | ||
}); | ||
|
||
describe('when called with only options', () => { | ||
it('should return a curried function that accepts logic', () => { | ||
const options = {id: 'test-actor'}; | ||
|
||
const curriedFn = createActorWith<typeof dummyLogic>(options); | ||
|
||
assert.equal(typeof curriedFn, 'function'); | ||
|
||
actor = curriedFn(dummyLogic); | ||
|
||
assert.ok(actor instanceof Actor); | ||
assert.equal(actor.id, options.id); | ||
assert.equal(actor.logic, dummyLogic); | ||
}); | ||
}); | ||
|
||
describe('when called with no arguments', () => { | ||
it('should return itself', () => { | ||
const curriedFn = createActorWith(); | ||
|
||
assert.equal(curriedFn, createActorWith); | ||
}); | ||
}); | ||
}); | ||
}); |