Open todd opened 6 years ago
@todd Thanks for being patient! :-) I'd definitely be up for a TypeScript declaration file PR. I'm familiar (ish) with TypeScript from a distance, but haven't ever put a declaration file together, so this is new territory for me. I'd likely reach out to folks who are more familiar (like yourself) for help especially when/if big changes happen in the API. But if this can help folks during dev time, it's a win!
Newbie attempt, based on reading the docs.
machina.d.ts
declare module 'machina' {
interface Fsm {
// static methods
extend: ({}) => Fsm
// instance members
initialState: string
eventListeners: {}
states: {}
inputQueue: []
namespace: string
targetReplayState: string
state: string
priorState: string
priorAction: string
currentAction: string
currentActionArgs: string
initialize: () => void
// prototype members
emit: (eventName: string, data: any) => void
handle: (eventName: string, data: any) => void
transition: (state: string) => void
processQueue: (type: 'transition' | 'handler') => void
clearQueue: (type?: 'transition' | 'handler', stateName?: string) => void
deferUntilTransition: (stateName?: string) => void
deferAndTransition: (stateName?: string) => void
compositeState: () => string
on: (eventName: string, callback: (data: any) => void) => void
off: (eventName: string, callback: (data: any) => void) => void
}
interface BehavioralFsm {
// static methods
extend: ({}) => BehavioralFsm
// instance members
initialState: string
eventListeners: {}
states: {}
inputQueue: []
namespace: string
// prototype members
initialize: () => void
emit: (eventName: string, data: any) => void
handle: (client: Fsm, inputType: string, data: any) => void
transition: (client: Fsm, state: string) => void
processQueue: (client: Fsm) => void
clearQueue: (client: Fsm, stateName?: string) => void
deferUntilTransition: (client: Fsm, stateName?: string) => void
deferAndTransition: (client: Fsm, stateName?: string) => void
compositeState: (client: Fsm) => string
on: (eventName: string, callback: (data: any) => void) => void
off: (eventName?: string, callback?: (data: any) => void) => void
// property to track machina-related metadata
__machina__: {
targetReplayState: string
state: string
priorState: string
priorAction: string
currentAction: string
currentActionArgs: any[]
initialize: () => void
inputQueue: any[]
inExitHandler: boolean
}
}
type DefaultOptions = {
initialState: string
eventListeners: {}
states: {}
namespace: string
useSafeEmit: boolean
hierarchy: {}
pendingDelegations: {}
}
type DefaultClientMeta = {
inputQueue: any[]
targetReplayState: string
state: string
priorState: string
priorAction: string
currentAction: string
currentActionArgs: any[]
inExitHandler: boolean
}
type Subscription = {
off: () => void
}
interface machina {
Fsm: Fsm,
BehavioralFsm: BehavioralFsm,
utils: {
makeFsmNamespace: () => string
listenToChild: (fsm: Fsm, child: Fsm) => Subscription
getLeaklessArgs: () => any[]
getDefaultOptions: () => DefaultOptions
getDefaultClientMeta: () => DefaultClientMeta
createUUID: () => string
},
eventListeners: {}
emit: (eventName: string, data: any) => void
on: (eventName: string, callback: (data: any) => void) => Subscription
off: (eventName: string, callback: (data: any) => void) => Subscription
}
const machina: machina
export = machina
}
It doesn't support multiple arguments for event payloads, but then the docs strongly recommend using only a single argument.
Did this ever get done? I'd love to be able to use it in my Node typescript workflow app.
I started working on them over the holidays, but obviously got a little side-tracked ;-)
I'll try to clean up what I have so far and open a work-in-progress PR so other folks can potentially contribute.
I expanded a bit on the declaration of my earlier comment -- it's still based on the Wiki docs though.
declare module 'machina' {
type EventCallback = (data: any) => void
interface Fsm {
// static methods
extend: ({}) => Fsm
// instance members
initialState: string
eventListeners: {}
states: {}
inputQueue: []
namespace: string
targetReplayState: string
state: string
priorState: string
priorAction: string
currentAction: string
currentActionArgs: string
initialize: () => void
// prototype members
emit: (eventName: string, data?: any) => void
handle: (eventName: string, data: any) => void
transition: (state: string) => void
processQueue: (type: 'transition' | 'handler') => void
clearQueue: (type?: 'transition' | 'handler', stateName?: string) => void
deferUntilTransition: (stateName?: string) => void
deferAndTransition: (stateName?: string) => void
compositeState: () => string
on: (eventName: string, callback: EventCallback) => void
off: (eventName: string, callback: EventCallback) => void
}
interface BehavioralFsm {
// static methods
extend: ({}) => BehavioralFsm
// instance members
initialState: string
eventListeners: {}
states: {}
inputQueue: []
namespace: string
// prototype members
initialize: () => void
emit: (eventName: string, data?: any) => void
handle: (client: Fsm, inputType: string, data: any) => void
transition: (client: Fsm, state: string) => void
processQueue: (client: Fsm) => void
clearQueue: (client: Fsm, stateName?: string) => void
deferUntilTransition: (client: Fsm, stateName?: string) => void
deferAndTransition: (client: Fsm, stateName?: string) => void
compositeState: (client: Fsm) => string
on: (eventName: string, callback: (data?: any) => void) => void
off: (eventName?: string, callback?: (data?: any) => void) => void
// property to track machina-related metadata
__machina__: {
targetReplayState: string
state: string
priorState: string
priorAction: string
currentAction: string
currentActionArgs: any[]
initialize: () => void
inputQueue: any[]
inExitHandler: boolean
}
}
const eventListeners: {}
function emit(eventName: string, data?: any): void
function on(eventName: string, callback: EventCallback): Subscription
function off(eventName: string, callback: EventCallback): Subscription
namespace utils {
function makeFsmNamespace(): string
function listenToChild(fsm: Fsm, child: Fsm): Subscription
function getLeaklessArgs(): any[]
function getDefaultOptions(): DefaultOptions
function getDefaultClientMeta(): DefaultClientMeta
function createUUID(): string
}
type DefaultOptions = {
initialState: string
eventListeners: {}
states: {}
namespace: string
useSafeEmit: boolean
hierarchy: {}
pendingDelegations: {}
}
type DefaultClientMeta = {
inputQueue: any[]
targetReplayState: string
state: string
priorState: string
priorAction: string
currentAction: string
currentActionArgs: any[]
inExitHandler: boolean
}
interface Subscription {
off: () => void
}
type TransitionEventData = {
client?: string // only applicable in BehavioralFsm instances
fromState: string
action: string
toState: string
namespace: string
}
type HandlingEventData = {
client?: string // only applicable in BehavioralFsm instances
inputType: string
delegated: boolean // only applicable in hierarchical scenarios
ticket: undefined // only applicable in hierarchical scenarios
namespace: string
}
type HandledEventData = {
client?: string // only applicable in BehavioralFsm instances
inputType: string
delegated: boolean // only applicable in hierarchical scenarios
ticket: undefined // only applicable in hierarchical scenarios
namespace: string
}
type NohandlerEventData = {
client?: string // only applicable in BehavioralFsm instances
inputType: string
delegated: boolean // only applicable in hierarchical scenarios
ticket: undefined // only applicable in hierarchical scenarios
namespace: string
args: any[]
}
type InvalidstateEventData = {
client?: string // only applicable in BehavioralFsm instances
namespace: string
state: string
attemptedState: string
}
type QueuedArgs = {
inputType: string
delegated: boolean // only applicable in hierarchical scenarios
ticket: undefined // only applicable in hierarchical scenarios
}
type DeferredEventData = {
client?: string // only applicable in BehavioralFsm instances
state: string,
namespace: string,
queuedArgs: {
args: QueuedArgs[]
type: 'transition' // currently this is the only possible value
untilState: string
}
}
}
It may actually be easier to maintain to port this module to use typescript. Then type definitions come along with the package install.
@joeandaverde I've considered rolling my own version written in TS based on the comments I left in #165. Given the inactivity on that PR, I may submit what little I've got at the moment to DefinitelyTyped and let folks contribute from there as a stopgap.
@todd long-time no... you know. I thought I'd see if there'd been any progress on type definitions for this since... when was that, 2016? And found myself here. From what I can tell, there are a couple of attempts above, and there's your WIT PR, and that's about where things have gotten to?
I did notice someone mentioning along the way that the documentation was a little sparse and I remember us looking at the code to figure-out how various things work, so I will first offer-up the following, which I only found today, and does provided a-lot of that documentation we thought we were missing (or maybe that was only me): https://github.com/ifandelse/machina.js/wiki/API
That said, are you still working on this PR? I haven't looked at it yet, but I might like to either assist in rounding it out and getting it added to DefinitelyTyped, or create my own PR based on this one if you're no longer working on it.
I guess I'm asking you were this work is being done if it's still being done (here in this PR, a PR on DT, a TS rewrite of machina - wherever) and then see if maybe I can assist.
:wave: Hey there, @sfrooster! Hope you're well, friend.
I got the ball rolling in #165, but, as you can probably tell, I haven't touched it in a while. Progress stalled out with a lack of feedback from @ifandelse and I got busy with a bunch of other things. At this point, landing some type definitions in DefinitelyTyped might be the path of least resistance to get something usable out. I did start playing around with the idea of doing a TypeScript-native project inspired by machina, but never got farther than the experimenting stage.
Happy to get you collaborator access to my machina fork if you wanna riff on these defs a bit more. Unfortunately, I'm probably unlikely to have the capacity to come back to this any time soon.
Quick question for @ifandelse - would you accept a PR that lands a TypeScript declaration file in this library? I've been using Machina in quite a few of my TypeScript projects and type information has been a major want of mine when using it in that stack.
The alternative would be to land the declaration file in DefinitelyTyped, but, generally speaking, the developer experience is a lot better if library authors include them in their packages.
However, including the type information in the library would necessitate a long-term commitment to keep that file up to date with API changes. Machina's API seems fairly stable, so I'm not sure this is a huge problem, but it has bitten some people in the past (see: https://github.com/moment/moment/pull/3280).
Regardless, I'm probably going to create these typings when I have a free moment. Just need to know if I should open the PR against this repo or DefinitelyTyped.
Thanks!