├── .editorconfig ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── docs └── the-foundation.md ├── package.json ├── publish.js ├── src ├── Behavior │ └── index.ts ├── Machine │ └── index.ts ├── MachineDefinition │ ├── MachineDefinition.StateNode.spec.ts │ ├── MachineDefinition.Transition.Actions.spec.ts │ ├── MachineDefinition.Transition.ParallelTargets.test.ts │ ├── MachineDefinition.Transition.Target.spec.ts │ ├── MachineDefintion.Entry.spec.ts │ └── index.ts ├── MachineImplementations │ ├── MachineImplemetations.spec.ts │ └── index.ts ├── extras.ts ├── index.ts └── universal.ts ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = space 3 | indent_size = 2 4 | insert_final_newline = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /updates-stuff 3 | /temp.js 4 | /dist 5 | /publish 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "origintype", 4 | "scxml", 5 | "sendid", 6 | "invokeid" 7 | ], 8 | "editor.rulers": [ 9 | 180 10 | ], 11 | "typescript.tsdk": "node_modules\\typescript\\lib" 12 | } 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Devansh Jethmalani 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # txstate 2 | 3 | An effort to statically type xstate ([more here](https://twitter.com/devanshj__/status/1297939517853196288)), ~in kinda r&d stage right now. Everything is gonna change here all the time.~ enough of that time to get to work :P 4 | 5 | UPDATE: See the list of all features [here](https://github.com/davidkpiano/xstate/discussions/2323#discussioncomment-899642). 6 | 7 | UPDATE 2: The work has been stalled long ago but you can try it using the `txstate` package (doesn't have any runtime code, just for trying out the types). 8 | -------------------------------------------------------------------------------- /docs/the-foundation.md: -------------------------------------------------------------------------------- 1 | # The foundation 2 | 3 | If you've read some bits of the code, you'll notice this pattern... 4 | 5 | ```typescript 6 | type Of< 7 | Definition extends A.Object, 8 | Implementations extends A.Object, 9 | Path extends A.ReadonlyTuple, 10 | Cache extends A.Object, 11 | Self = O.Path 12 | > 13 | ``` 14 | 15 | This is the beginning of pretty much all types. Even if you understand let's see how did it even get to this. 16 | 17 | It started with this [stackoverflow answer](https://stackoverflow.com/a/54666233/9591609) to David's question. 18 | 19 | ```typescript 20 | declare const createMachine: (config: { initial: K, states: S }) => void 21 | ``` 22 | 23 | Now it may seem trivial to you but the mental model here is "Write the type as you wish it to be, use generics to fill gaps or fill places you want to infer". I have to tell you it works really well, we do it all the time like... 24 | 25 | ```typescript 26 | declare const useState: (v: T) => [T, (v: T) => void] 27 | ``` 28 | 29 | See? not bad huh? As a matter of fact this is even how xstate types work, a bunch of generics `TContext`, `TEvent`, `TAction`, etc in place where you want to fill gaps. 30 | 31 | I was like huh, let's try. And it ended up like [this](https://github.com/devanshj/txstate/commit/a1eeb03cb2845339612bcaefc8a549719c646f91#diff-b7708c13e1ab73fb37cefab331ab7fae98a97e0979fea3dc71213d9f83193d53). This is the first commit of txstate, how naive isn't it? I don't even know if it works btw xD 32 | 33 | Well it didn't seem stupid as such at that time I was ready to experiment with what works. I said to myself "Well yeah you need so many generics coz there are so many gaps to fill, duh. We're doing some complex shit here it's gonna look ugly" 34 | 35 | I don't remember exactly why but this idea just miserably failed, like even writing so many generics didn't work. I went back to the piece of code that started it... 36 | 37 | ```typescript 38 | declare const createMachine: (config: { initial: K, states: S }) => void 39 | ``` 40 | 41 | I don't remember what went through my head but I was like what if we write it like this... 42 | 43 | ```typescript 44 | declare const createMachine: (config: C) => void 45 | ``` 46 | 47 | I caught something and I rewrote to make it apparent... 48 | 49 | ```typescript 50 | declare const createMachine: >(config: C) => void 51 | type Config = { initial: keyof Prop, states: Prop } 52 | 53 | type Prop = K extends keyof T ? T[K] : never; 54 | ``` 55 | 56 | `C extends Config` caught my eye... It was something weirdly special, like even you see it right? a type constraint by a derivative of itself how in the world does that even work. I wrote a little more... 57 | 58 | ```typescript 59 | declare const createMachine: >(config: C) => void 60 | type StateNode = { 61 | initial: keyof Prop, 62 | states: { 63 | [S in keyof Prop>]: StateNode, S> 64 | } 65 | } 66 | 67 | type Prop = K extends keyof T ? T[K] : never; 68 | ``` 69 | 70 | At this point I was like whoa... this is weirdly recursive and it works! A little more rewrite... 71 | 72 | ```typescript 73 | declare const createMachine: >(config: C) => void 74 | type StateNode = { 75 | initial: keyof Prop, 76 | states: States> 77 | } 78 | type States = { 79 | [K in keyof S]: Node 80 | } 81 | 82 | type Prop = K extends keyof T ? T[K] : never; 83 | ``` 84 | 85 | Can you see something here? Let me show you... 86 | 87 | ```typescript 88 | declare const createMachine: >(config: C) => void 89 | type StateNode = { 90 | initial: keyof Prop, 91 | states: States> 92 | } 93 | type States = { 94 | [K in keyof Self]: StateNode 95 | } 96 | 97 | type Prop = K extends keyof T ? T[K] : never; 98 | ``` 99 | 100 | Each piece receives it's own "self" and reconstructs it with constraints... I tried to make this pattern work for initial too but... 101 | 102 | ```typescript 103 | declare const createMachine: >(config: C) => void 104 | type StateNode = { 105 | initial: Initial>, 106 | states: States> 107 | } 108 | type Initial = ??? // how to get keyof states here? 109 | type States = { 110 | [K in keyof Self]: StateNode 111 | } 112 | 113 | type Prop = K extends keyof T ? T[K] : never; 114 | ``` 115 | 116 | I realized this shortcoming of this technique... Then I don't remember what happened but I came up with this... Also btw let me tell you the journey was not so simple or linear at all, heck I don't even remember how it was, so what I'm saying is probably 60% of how it happened but nonetheless I think it's working for the story telling xD... Okay yeah back to what I came up with... 117 | 118 | ```typescript 119 | declare const createMachine: >(config: N) => void 120 | 121 | type StateNode> = 122 | { initial: Initial> 123 | , states: States> 124 | } 125 | 126 | type Initial> = 127 | keyof OPath, "states">> 128 | 129 | type States> = 130 | { [K in keyof Self]: StateNode> } 131 | 132 | type OPath = P extends [] ? O : OPath>, LShifted

> 133 | type LHead = L extends [infer H, ...any[]] ? H : never; 134 | type LShifted = L extends [any, ...infer Shifted] ? Shifted : never; 135 | type LPopped = L extends [...infer Popped, any] ? Popped : never; 136 | type LAppend = [...Cast, X]; 137 | type Cast = T extends U ? T : U; 138 | type Prop = K extends keyof T ? T[K] : never; 139 | ``` 140 | 141 | Got it? Yep, instead of passing `Self` we pass the `Root` and `Path` to `Self`. In this way, the type can access itself, can access anything in the whole tree and anything relative to itself. 142 | 143 | This struck a chord so hard, I decided this is it, there's no way things get any better than this. [I deleted everything](https://github.com/devanshj/txstate/commit/d94d05336db080c2f356ef2ff9c30de9253ccf1e), [built a foundation on this](https://github.com/devanshj/txstate/commit/d7aadd7ef800888fc91efb65ad33b78b41f26503) and [updated the readme that txstate is no longer in R&D, enough experimentation now it was time to work](https://github.com/devanshj/txstate/commit/412c3b260c7339549e2988b37e8f146cbc57bf22). 144 | 145 | If you've seen the recent updates of txstate, you might think running the machine on type level, computing entry types must be the hardest. But you know what that's literally the easiest part in the whole journey of txstate. I'm not even exaggerating, I took me an hour or two to come up with those sophisticated entry types but a full month for the code above. 146 | 147 | As a matter of fact after this foundation was led, the work after that was really boring that's probably the reason I took so long as I was avoiding it because it was mundane xD Finally the after getting the machine to run on type-level, things are still not a really challenge for me but at least they result into some mind-blowing things. 148 | 149 | Look I know I didn't dig too much into the codebase but I hope you have some context on how things work and at least can make a little more sense of it. I wanted to write an "overview" but got so indulged into this storytelling that dived way too less into the code and renamed this to "foundation" xD 150 | 151 | But hey, I want you to take away some wisdom. You know why it took a month just get to this foundation? Well, a variety of reasons, of which this is one - "Write the type as you wish it to be, use generics to fill gaps or fill places you want to infer" 152 | 153 | Yep, that's a lie. What's good is it works for 95% time, so it's a good lie. But do you want one which works 100% of times? It's something like this "Make what is generic _in principal_, generic". 154 | 155 | Look I had no intentions to have just one generic on `createMachine` but the developments just organically led me to that. You know why? Because it's principally correct, we truly have just one generic - the whole machine definition - because well it's "generic" it's up to the user what they write, isn't it? 156 | 157 | When you stumble upon something great, it probably has an even greater foundation. 158 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "txstate", 3 | "version": "0.2.1", 4 | "devDependencies": { 5 | "readline-sync": "^1.4.10", 6 | "shelljs": "^0.8.4", 7 | "typescript": "^4.4.0-beta" 8 | }, 9 | "repository": "https://github.com/devanshj/txstate", 10 | "author": "Devansh Jethmalani", 11 | "license": "MIT" 12 | } 13 | -------------------------------------------------------------------------------- /publish.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const sh = require("shelljs") 3 | const rl = require("readline-sync"); 4 | 5 | if (!rl.keyInYNStrict("you sure?")) process.exit(); 6 | 7 | sh.ls().includes("dist") && sh.rm("-r", "dist"); 8 | sh.exec("yarn tsc") 9 | sh.cp("LICENSE", "dist/LICENSE") 10 | sh.cp("README.md", "dist/README.md"); 11 | sh.cp("package.json", "dist/package.json"); 12 | sh.cd("dist"); 13 | sh.echo([ 14 | "*.spec.js", 15 | "*.spec.d.ts", 16 | "*.test.js", 17 | "*.test.d.ts" 18 | ].join("\n")).to(".npmignore") 19 | sh.exec("npm publish") 20 | sh.exec(`git tag ${ 21 | sh.cat("package.json") 22 | .grep("version") 23 | .sed(/.*"version": "(.*)".*/, "v$1") 24 | .toString() 25 | }`) 26 | sh.cd("..") 27 | sh.rm("-r", "dist") 28 | -------------------------------------------------------------------------------- /src/Behavior/index.ts: -------------------------------------------------------------------------------- 1 | import { SCXML, UnknownEvent } from ".."; 2 | 3 | export interface Behavior 4 | { transition 5 | ( state: T 6 | , event: E | LifecycleSignal 7 | , context: ActorContext 8 | ): T 9 | , initialState: T 10 | , start(actorContext: ActorContext): T 11 | , subscribe(observer: Observer): Subscription | undefined 12 | } 13 | 14 | export interface UnknownBehavior 15 | extends Behavior {} 16 | 17 | const testVariance: UnknownBehavior = {} as Behavior 18 | 19 | export type LifecycleSignal = StartSignal | StopSignal 20 | export interface StartSignal { type: typeof startSignalType } 21 | declare const startSignalType: unique symbol 22 | export interface StopSignal { type: typeof stopSignalType } 23 | declare const stopSignalType: unique symbol 24 | 25 | export interface ActorContext 26 | { parent?: UnknownActorRef 27 | , self: ActorRef 28 | , name: string 29 | , observers: Set> 30 | , _event: SCXML.Event 31 | } 32 | 33 | export interface ActorRef 34 | extends Subscribable 35 | { name: string 36 | , send(event: E): void 37 | , start?(): void 38 | , getSnapshot(): T | undefined 39 | , stop?(): void 40 | , toJSON?(): unknown 41 | } 42 | 43 | export interface UnknownActorRef 44 | extends ActorRef {} 45 | 46 | export interface Subscribable 47 | { subscribe: 48 | { ( observer: Observer 49 | ): Subscription; 50 | 51 | ( next: (value: T) => void 52 | , error?: (error: unknown) => void 53 | , complete?: () => void 54 | ): Subscription; 55 | } 56 | } 57 | 58 | export interface Observer 59 | { next?(value: T): void 60 | , error?(err: any): void 61 | , complete?(): void 62 | } 63 | 64 | export interface Subscription 65 | { unsubscribe(): void 66 | } 67 | -------------------------------------------------------------------------------- /src/Machine/index.ts: -------------------------------------------------------------------------------- 1 | import { A, U, L, S, F } from "../extras"; 2 | import MachineDefinition from "../MachineDefinition"; 3 | import { ReferencePathString } from "../universal"; 4 | 5 | export default Machine; 6 | namespace Machine { 7 | export type Of< 8 | Global 9 | > = 10 | { config: A.Get 11 | , options: A.Get 12 | } 13 | 14 | 15 | export namespace Event { 16 | export type Of< 17 | Global, 18 | Flags = never, 19 | EventSchema = Schema.Of 20 | > = 21 | EventSchema extends undefined 22 | ? WithRoot> 23 | : EventSchema 24 | 25 | type WithRoot = 26 | | ( [keyof A.Get] extends [never] ? never : 27 | keyof A.Get extends infer E 28 | ? E extends any ? { type: E } : never 29 | : never 30 | ) 31 | | ( [keyof A.Get] extends [never] ? never : 32 | { [S in keyof A.Get]: 33 | WithRoot[S]> 34 | }[keyof A.Get] 35 | ) 36 | 37 | export namespace Schema { 38 | export type Of> = 39 | "UseInferForSchema" extends Flags 40 | ? Definition extends { schema?: { events?: infer E } } ? E : undefined 41 | // TODO: return undefined if E is error message 42 | : A.Get 43 | } 44 | 45 | export namespace ForEntry { 46 | export type OfWithStateNodePath< 47 | Global, 48 | StateNodePath, 49 | 50 | > = 51 | WithRootPath 52 | 53 | type WithRootPath< 54 | _Global, 55 | StateNodePath, 56 | RootPath, 57 | 58 | Global = MachineDefinition.Global.Resolved<_Global>, 59 | DesugaredDefinition = MachineDefinition.Precomputed.FromGlobal, 60 | Root = A.Get, 61 | StateNodeReferencePathString = ReferencePathString.FromDefinitionPath, 62 | RootReferencePathString = ReferencePathString.FromDefinitionPath, 63 | On = A.Get, 64 | Always = A.Get, 65 | States = A.Get, 66 | EventSchema = Schema.Of, 67 | InitialState = MachineDefinition.Precomputed.FromGlobal 68 | > = 69 | | { [E in keyof On]: 70 | A.Get extends infer T 71 | ? [T] extends [never] ? never : 72 | T extends any 73 | ? ( L.IncludesSubtype< 74 | ReferencePathString.Tuple.Unresolved.ResolveWithStateNode< 75 | Global, A.Get, RootReferencePathString 76 | >, 77 | | StateNodeReferencePathString 78 | | ( A.Get extends false 79 | ? ReferencePathString.Child 80 | : never 81 | ) 82 | > extends true 83 | ? EventSchema extends undefined ? { type: E } : 84 | U.Extract 85 | : never 86 | ) 87 | : never 88 | : never 89 | }[keyof On] 90 | | ( A.Get extends infer T 91 | ? [T] extends [never] ? never : 92 | T extends any 93 | ? L.IncludesSubtype< 94 | ReferencePathString.Tuple.Unresolved.ResolveWithStateNode< 95 | Global, A.Get, RootReferencePathString 96 | >, 97 | | StateNodeReferencePathString 98 | | ( A.Get extends false 99 | ? ReferencePathString.Child 100 | : never 101 | ) 102 | > extends true 103 | ? OfWithStateNodePath 104 | : never 105 | : never 106 | : never 107 | ) 108 | | ( [keyof States] extends [never] ? never : 109 | { [C in keyof States]: 110 | WithRootPath< 111 | Global, StateNodePath, 112 | L.Concat 113 | > 114 | }[keyof States] 115 | ) 116 | | ( StateNodeReferencePathString extends InitialState 117 | ? { type: "xstate.init" } 118 | : never 119 | ) 120 | } 121 | 122 | export namespace ForExit { 123 | export type OfWithStateNodePath< 124 | Global, 125 | StateNodePath 126 | > = 127 | // TODO 128 | Machine.Event.Of 129 | } 130 | 131 | export namespace ForDone { 132 | export type OfWithStateNodePath< 133 | Global, 134 | StateNodePath, 135 | Definition = A.Get, 136 | Data = A.Get> 137 | > = 138 | & Machine.Event.Of // TODO 139 | & { data: 140 | Data extends undefined ? undefined : 141 | Data extends A.Function ? F.Called : 142 | { [K in keyof Data]: 143 | Data[K] extends A.Function 144 | ? F.Called 145 | : Data[K] 146 | } 147 | , toString: () => string 148 | } 149 | } 150 | 151 | } 152 | 153 | export namespace InitialStateNodeReferencePathString { 154 | export type Of = 155 | WithRoot; 156 | 157 | type WithRoot, 159 | Node = ReferencePathString.ToNode, 160 | Initial = A.Get, 161 | ChildState = keyof A.Get, 162 | Always = MachineDefinition.Transition.Desugar> 163 | > = 164 | | ( Initial extends A.String 165 | ? | ReferencePathString.Append 166 | | WithRoot> 167 | : [ChildState] extends [never] ? never : 168 | ChildState extends any 169 | ? | ReferencePathString.Append 170 | | WithRoot> 171 | : never 172 | ) 173 | | { [I in keyof Always]: 174 | A.Get, Root 176 | >, number> extends infer T 177 | ? [T] extends [never] ? never : 178 | T extends any 179 | ? WithRoot 180 | : never 181 | : never 182 | }[keyof Always] 183 | } 184 | 185 | export namespace XstateAction { 186 | export namespace InferralHint { 187 | export type OfWithAdjacentAction< 188 | Global, 189 | Action, 190 | PrecedingParameters = F.Parameters 191 | > = 192 | { ( context: A.Get 193 | , event: A.Get 194 | , meta: A.Get 195 | , __inferralHint: MachineDefinition.Internal<{ 196 | "Machine.Event": Machine.Event.Of 197 | }> 198 | ): void 199 | , type?: 200 | | "xstate.assign" 201 | | "xstate.send" 202 | } 203 | } 204 | } 205 | 206 | export namespace AssignAction { 207 | export type Creator = 208 | { < C 209 | , E 210 | , A extends (context: C, event: E) => { [K in keyof C]?: C[K] } 211 | > 212 | ( assignment: A 213 | ): 214 | { (context: C, event: E, meta: unknown, __inferralHint: unknown): void 215 | , type: "xstate.assign" 216 | , assignment: A 217 | } 218 | 219 | < C 220 | , E 221 | , A extends { [K in keyof C]?: (context: C[K], event: E) => C[K] } 222 | > 223 | ( assignment: A 224 | ): 225 | { (context: C, event: E, meta: unknown, __inferralHint: unknown): void 226 | , type: "xstate.assign" 227 | , assignment: A 228 | } 229 | } 230 | } 231 | 232 | export namespace SendAction { 233 | export type Creator = 234 | < InferralHint 235 | , Event extends EventWithInferralHint 236 | > (event: Event) => 237 | { (context: unknown, event: unknown, meta: unknown, __inferralHint: InferralHint): void 238 | , type: "xstate.send" 239 | , event: Event extends A.String ? { type: Event } : Event 240 | } 241 | 242 | 243 | type EventWithInferralHint< 244 | Self, 245 | InferralHint, 246 | SpecEvent = A.Get, 247 | SpecEventType = 248 | SpecEvent extends any 249 | ? { type: A.Get } extends SpecEvent 250 | ? A.Get 251 | : never 252 | : never 253 | > = 254 | | ( SpecEventType extends any 255 | ? S.InferNarrowest 256 | : never 257 | ) 258 | | ( { type: 259 | S.IsLiteral> extends true 260 | ? A.Get extends A.Get 261 | ? S.InferNarrowest> 262 | : S.InferNarrowest> 263 | : S.InferNarrowest> 264 | } 265 | & ( U.Extract }> extends infer E 266 | ? [E] extends [never] ? {} : 267 | E extends any 268 | ? { [K in keyof E as U.Exclude]: E[K] } 269 | : never 270 | : never 271 | ) 272 | ) 273 | } 274 | 275 | 276 | 277 | export namespace Context { 278 | export type Of< 279 | Global, 280 | Flags = never, 281 | Definition = A.Get, 282 | ContextSchema = Schema.Of, 283 | > = 284 | ContextSchema extends undefined 285 | ? A.Get 286 | : ContextSchema 287 | 288 | export namespace Schema { 289 | export type Of> = 290 | "UseInferForSchema" extends Flags 291 | ? Definition extends { schema?: { context?: infer C } } ? C : undefined 292 | : A.Get 293 | } 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /src/MachineDefinition/MachineDefinition.StateNode.spec.ts: -------------------------------------------------------------------------------- 1 | import { createMachine, createSchema } from ".."; 2 | import { A } from "../extras"; 3 | 4 | createMachine({ 5 | initial: "a", 6 | context: {}, 7 | states: { a: {} } 8 | }); 9 | 10 | 11 | createMachine({ 12 | // @ts-expect-error 13 | initial: "b", 14 | context: {}, 15 | states: { a: {} } 16 | }) 17 | 18 | 19 | createMachine({ 20 | initial: "a", 21 | context: {}, 22 | states: { 23 | a: { 24 | // @ts-expect-error 25 | initial: "x", 26 | states: { 27 | b: {} 28 | } 29 | } 30 | } 31 | }) 32 | 33 | 34 | // @ts-expect-error 35 | createMachine({ 36 | context: {}, 37 | states: { a: {} } 38 | }) 39 | 40 | 41 | createMachine({ 42 | // @ts-expect-error 43 | initial: 1, 44 | context: {}, 45 | // @ts-expect-error 46 | states: { 1: {} } 47 | }) 48 | 49 | 50 | createMachine({ 51 | type: "atomic", 52 | // @ts-expect-error 53 | initial: "a", 54 | context: {}, 55 | // @ts-expect-error 56 | states: { a: {} } 57 | }) 58 | 59 | 60 | createMachine({ 61 | context: {} 62 | }) 63 | 64 | createMachine({ 65 | type: "parallel", 66 | // @ts-expect-error 67 | initial: "a", 68 | context: {}, 69 | states: { a: {}, b: {} } 70 | }) 71 | 72 | createMachine({ 73 | context: {}, 74 | states: { 75 | // @ts-expect-error 76 | "a.b": {} 77 | } 78 | }) 79 | 80 | createMachine({ 81 | schema: { 82 | // @ts-expect-error 83 | context: "" 84 | } 85 | }) 86 | 87 | createMachine({ 88 | schema: { 89 | context: createSchema<{ foo: number }>() 90 | }, 91 | context: { 92 | // @ts-expect-error 93 | foo: "" 94 | } 95 | }) 96 | 97 | 98 | createMachine({ 99 | schema: { 100 | context: createSchema<{ foo: number }>() 101 | }, 102 | // @ts-expect-error 103 | context: () => ({ foo: "" }) 104 | }) 105 | 106 | createMachine({ 107 | schema: { 108 | context: createSchema<{ foo: number }>() 109 | }, 110 | context: { foo: 1 } 111 | }) 112 | 113 | createMachine({ 114 | schema: { 115 | context: createSchema<{ foo: number }>() 116 | }, 117 | context: () => ({ foo: 1 }) 118 | }) 119 | 120 | createMachine({ 121 | // @ts-expect-error 122 | context: "" 123 | }) 124 | 125 | createMachine({ 126 | // @ts-expect-error 127 | context: () => "" 128 | }) 129 | 130 | createMachine({ 131 | context: { foo: 1 } 132 | }) 133 | 134 | createMachine({ 135 | context: () => ({ foo: 1 }) 136 | }) 137 | 138 | let t0 = createMachine({ 139 | context: { foo: 1 }, 140 | initial: "a", 141 | states: { 142 | a: { 143 | type: "final", 144 | on: { 145 | X: "b" 146 | }, 147 | data: (c, e) => { 148 | A.tests([ 149 | A.areEqual(), 150 | A.areEqual() 151 | ]) 152 | return "foo" as const 153 | } 154 | }, 155 | b: { 156 | type: "final", 157 | data: { 158 | bar: (c, e) => { 159 | A.tests([ 160 | A.areEqual(), 161 | A.areEqual() 162 | ]) 163 | return c.foo + 2 164 | }, 165 | x: 100 166 | } 167 | } 168 | } 169 | }) 170 | /* TODO 4.4.0 regression 171 | A.tests([ 172 | A.areEqual< 173 | typeof t0.config.states.a.data, 174 | (c: { foo: number }, e: { type: "X" }) => "foo" 175 | >(), 176 | A.areEqual< 177 | typeof t0.config.states.b.data, 178 | { bar: (c: { foo: number }, e: { type: "X" }) => number 179 | , x: number 180 | } 181 | >() 182 | ]) 183 | */ 184 | 185 | createMachine({ 186 | context: { foo: 1 }, 187 | initial: "a", 188 | states: { 189 | a: { 190 | // @ts-expect-error 191 | data: { x: 100 } 192 | } 193 | } 194 | }) 195 | 196 | let t1 = createMachine({ 197 | context: {}, 198 | initial: "a", 199 | states: { 200 | a: { 201 | tags: ["foo", "bar"] 202 | } 203 | } 204 | }) 205 | A.test(A.areEqual< 206 | typeof t1.config.states.a.tags, 207 | ["foo", "bar"] 208 | >()) 209 | 210 | let t2 = createMachine({ 211 | context: { foo: 1 }, 212 | initial: "a", 213 | states: { 214 | a: { 215 | after: [ 216 | { target: "a", delay: 100 }, 217 | { // @ts-ignore TODO unexpected error 218 | target: "a", 219 | delay: (c, e) => { 220 | A.tests([ 221 | A.areEqual(), 222 | A.areEqual() 223 | ]) 224 | return 100 225 | } 226 | }, 227 | { 228 | target: "a", 229 | // @ts-expect-error 230 | delay: () => {} 231 | } 232 | ], 233 | on: { 234 | X: "a" 235 | } 236 | }, 237 | b: { 238 | after: { 239 | 100: { target: "a" }, 240 | 200: { 241 | target: "b", 242 | // @ts-expect-error 243 | delay: 10 244 | } 245 | } 246 | }, 247 | c: { after: ["a"] }, 248 | d: { after: { target: "a" } } 249 | } 250 | }) 251 | 252 | let t3 = createMachine({ 253 | context: {}, 254 | initial: "a", 255 | states: { 256 | a: { 257 | _: null, 258 | invoke: [ 259 | { 260 | src: "foo", 261 | onDone: { 262 | target: "a" 263 | } 264 | } 265 | ] 266 | } 267 | } 268 | }) 269 | A.test(A.areEqual()) 270 | A.test(A.areEqual()) 271 | 272 | createMachine({ 273 | context: { foo: 1 }, 274 | initial: "a", 275 | states: { 276 | a: { 277 | _: null, 278 | invoke: [ 279 | { src: "foo" }, 280 | // @ts-expect-error 281 | (c, e) => { 282 | A.tests([ 283 | A.areEqual(), 284 | A.areEqual() 285 | ]) 286 | } 287 | ], 288 | on: { 289 | X: "a" 290 | } 291 | } 292 | } 293 | }) 294 | -------------------------------------------------------------------------------- /src/MachineDefinition/MachineDefinition.Transition.Actions.spec.ts: -------------------------------------------------------------------------------- 1 | import { assign, createMachine, createSchema, send } from ".." 2 | import { A, U } from "../extras" 3 | 4 | let t0 = createMachine({ 5 | schema: { 6 | events: createSchema< 7 | | { type: "A", foo: number } 8 | | { type: "B", foo: number } 9 | | { type: "C", foo: number } 10 | | { type: "D", bar: number } 11 | >() 12 | }, 13 | context: {}, 14 | initial: "a", 15 | states: { 16 | a: { 17 | on: { 18 | A: { 19 | target: "a", 20 | actions: [{ 21 | type: "foo", 22 | exec: (c, e, m) => { 23 | A.tests([ 24 | A.areEqual(), 25 | A.areEqual() 26 | ]) 27 | return "A.actions.Called" as const 28 | }, 29 | bar: 10 30 | }, "ha"] 31 | }, 32 | B: { 33 | target: "a", 34 | actions: "foo" 35 | }, 36 | C: { 37 | target: "a", 38 | actions: (c, e, m) => { 39 | A.tests([ 40 | A.areEqual(), 41 | A.areEqual() 42 | ]) 43 | return { fooBarBaz: 100 } 44 | } 45 | }, 46 | D: { 47 | target: "a", 48 | actions: { 49 | type: "foo", 50 | exec: (c, e, m) => { 51 | A.tests([ 52 | A.areEqual(), 53 | A.areEqual() 54 | ]) 55 | }, 56 | bar: 10 57 | } 58 | } 59 | } 60 | } 61 | } 62 | }) 63 | 64 | A.tests([ 65 | A.areEqual(), 66 | 67 | A.areEqual< 68 | typeof t0.config.states.a.on.A.actions[0]["exec"], 69 | (c: {}, e: { type: "A", foo: number }, m: "TODO") => "A.actions.Called" 70 | >(), 71 | 72 | A.areEqual< 73 | typeof t0.config.states.a.on.A.actions[0]["bar"], 74 | number 75 | >(), 76 | 77 | A.areEqual< 78 | typeof t0.config.states.a.on.A.actions[1], 79 | "ha" 80 | >(), 81 | 82 | A.areEqual< 83 | typeof t0.config.states.a.on.B.actions, 84 | "foo" 85 | >(), 86 | 87 | A.areEqual< 88 | typeof t0.config.states.a.on.C.actions, 89 | (c: {}, e: { type: "C", foo: number }, m: "TODO") => { fooBarBaz: number } 90 | >(), 91 | 92 | A.areEqual< 93 | typeof t0.config.states.a.on.D.actions.type, 94 | "foo" 95 | >(), 96 | 97 | A.areEqual< 98 | typeof t0.config.states.a.on.D.actions.exec, 99 | (c: {}, e: { type: "D", bar: number }, m: "TODO") => void 100 | >(), 101 | 102 | A.areEqual< 103 | typeof t0.config.states.a.on.D.actions.bar, 104 | number 105 | >() 106 | ]) 107 | 108 | createMachine({ 109 | initial: "a", 110 | states: { 111 | a: { 112 | on: { 113 | E: { 114 | target: "a", 115 | // @ts-expect-error TODO: better error 116 | actions: { type: 1 } 117 | }, 118 | F: { 119 | target: "a", 120 | // TODO @\ts-expect-error 121 | actions: {} 122 | }, 123 | G: { 124 | target: "a", 125 | // @ts-expect-error TODO: better error 126 | actions: [{ type: 1 }] 127 | } 128 | } 129 | } 130 | } 131 | }) 132 | 133 | let t4 = createMachine({ 134 | schema: { 135 | events: createSchema< 136 | | { type: "X" } 137 | | { type: "Y", bar: number } 138 | | { type: "Z" } 139 | | { type: "W" } 140 | >() 141 | }, 142 | context: {}, 143 | initial: "a", 144 | states: { 145 | a: { 146 | on: { 147 | X: { 148 | target: "a", 149 | actions: send("X") 150 | }, 151 | Y: { 152 | target: "a", 153 | actions: send({ type: "Y", bar: 10 }) 154 | }, 155 | Z: { 156 | target: "a", 157 | actions: [send("X"), "ha"] 158 | }, 159 | W: { 160 | target: "a", 161 | actions: [send("X")] 162 | } 163 | } 164 | } 165 | } 166 | }) 167 | 168 | A.tests([ 169 | A.areEqual(), 170 | A.areEqual(), 171 | A.areEqual(), 172 | A.areEqual(), 173 | A.areEqual() 174 | ]) 175 | 176 | 177 | createMachine({ 178 | schema: { 179 | events: createSchema< 180 | | { type: "X" } 181 | | { type: "Y", bar: number } 182 | | { type: "Z" } 183 | >() 184 | }, 185 | context: {}, 186 | initial: "a", 187 | states: { 188 | a: { 189 | on: { 190 | X: { 191 | target: "a", 192 | actions: send( 193 | // @ts-expect-error 194 | "Y" 195 | ) 196 | }, 197 | Y: { 198 | target: "a", 199 | actions: send( 200 | // @ts-expect-error 201 | { type: "Y" } 202 | ) 203 | }, 204 | Z: { 205 | target: "a", 206 | actions: [send({ 207 | type: "Y", 208 | // @ts-expect-error 209 | bar: "hello" 210 | })] 211 | } 212 | } 213 | } 214 | } 215 | }) 216 | 217 | createMachine({ 218 | context: {}, 219 | initial: "a", 220 | states: { 221 | a: { 222 | type: "final", 223 | data: { bar: () => 10 }, 224 | onDone: { 225 | target: "a", 226 | actions: (c, e) => { 227 | A.tests([ 228 | A.areEqual< 229 | typeof e.data, 230 | { bar: number } 231 | >() 232 | ]) 233 | let x: string = e.toString() 234 | } 235 | }, 236 | on: { 237 | X: "a" 238 | } 239 | } 240 | } 241 | }) 242 | 243 | createMachine({ 244 | schema: { 245 | events: {} as { type: "X" } | { type: "Y" } 246 | }, 247 | context: { foo: 1 }, 248 | initial: "a", 249 | states: { 250 | a: { 251 | on: { 252 | X: { 253 | target: "a", 254 | actions: [assign({ 255 | foo: (x, e) => { 256 | A.tests([ 257 | A.areEqual(), 258 | A.areEqual(), 259 | ]) 260 | return x + 1 261 | } 262 | }), 263 | assign( 264 | // @ts-expect-error 265 | (c, e) => { 266 | A.tests([ 267 | A.areEqual(), 268 | A.areEqual(), 269 | ]) 270 | 271 | return ""; 272 | } 273 | ) 274 | ] 275 | } 276 | } 277 | } 278 | } 279 | }) 280 | 281 | createMachine({ 282 | context: { 283 | activations: 0, 284 | reactivations: 0 285 | }, 286 | initial: "inactive", 287 | states: { 288 | inactive: { 289 | on: { 290 | ACTIVATE: "active" 291 | } 292 | }, 293 | active: { 294 | on: { 295 | DEACTIVATE: "inactive", 296 | REACTIVATE: "active" 297 | }, 298 | entry: assign({ 299 | activations: (x, e) => e.type === "ACTIVATE" ? x + 1 : x, 300 | reactivations: (x, e) => e.type === "REACTIVATE" ? x + 1 : x 301 | }) 302 | } 303 | } 304 | }) 305 | -------------------------------------------------------------------------------- /src/MachineDefinition/MachineDefinition.Transition.ParallelTargets.test.ts: -------------------------------------------------------------------------------- 1 | import { createMachine } from ".."; 2 | 3 | createMachine({ 4 | id: "settings", 5 | type: "parallel", 6 | context: {}, 7 | states: { 8 | mode: { 9 | initial: "active", 10 | states: { 11 | inactive: { 12 | id: "lol" 13 | }, 14 | pending: { 15 | id: "xyz" 16 | }, 17 | active: {} 18 | } 19 | }, 20 | status: { 21 | initial: "enabled", 22 | states: { 23 | disabled: {}, 24 | enabled: {} 25 | }, 26 | always: { target: [ 27 | // @ts-expect-error 28 | "mode", 29 | // @ts-expect-error 30 | "#lol" 31 | ] } 32 | } 33 | }, 34 | always: [ 35 | { target: [ 36 | // @ts-expect-error 37 | ".mode", 38 | // @ts-expect-error 39 | "#lol" 40 | ] }, 41 | { target: [ 42 | // @ts-expect-error 43 | "#lol", 44 | // @ts-expect-error 45 | "#xyz" 46 | ] }, 47 | { target: [".mode.active", ".status.enabled"] }, 48 | { target: [ 49 | // @ts-expect-error 50 | "foobar" 51 | ] } 52 | ], 53 | on: { 54 | DEACTIVATE: [ 55 | // @ts-expect-error 56 | ".mode", 57 | // @ts-expect-error 58 | "#lol" 59 | ], 60 | A: { target: [ 61 | // @ts-expect-error 62 | ".mode", 63 | // @ts-expect-error 64 | "#lol" 65 | ] }, 66 | Z: [ 67 | // @ts-expect-error 68 | "#lol", 69 | // @ts-expect-error 70 | "#xyz" 71 | ], 72 | Y: [ 73 | // @ts-expect-error 74 | "foobar" 75 | ], 76 | ACTIVATE: [".mode.active", ".status.enabled"], 77 | X: [ 78 | { target: [ 79 | // @ts-expect-error 80 | ".mode", 81 | // @ts-expect-error 82 | "#lol" 83 | ] }, 84 | { target: [ 85 | // @ts-expect-error 86 | "#lol", 87 | // @ts-expect-error 88 | "#xyz" 89 | ] }, 90 | { target: [".mode.active", ".status.enabled"] }, 91 | { target: [ 92 | // @ts-expect-error 93 | "foobar" 94 | ] } 95 | ], 96 | FOO: { 97 | target: [ 98 | // @ts-expect-error 99 | ".mode", 100 | // @ts-expect-error 101 | "#lol" 102 | ] 103 | }, 104 | BAR: { target: [".mode.active", ".status.enabled"] }, 105 | } 106 | }) 107 | -------------------------------------------------------------------------------- /src/MachineDefinition/MachineDefinition.Transition.Target.spec.ts: -------------------------------------------------------------------------------- 1 | import { createMachine } from ".."; 2 | 3 | createMachine({ 4 | initial: "a", 5 | context: {}, 6 | id: "bar", 7 | on: { 8 | A: "#foo", 9 | B: ".b.b2", 10 | C: "#bar.a.a2", 11 | D: [ 12 | { target: "#baz.b2" }, 13 | { target: "b.b1" }, 14 | // @ts-expect-error 15 | { target: "xyz" } 16 | ], 17 | E: "a", 18 | F: "b.b1", 19 | // @ts-expect-error 20 | Z: "", 21 | // @ts-expect-error 22 | W: "bogus" 23 | }, 24 | states: { 25 | a: { 26 | initial: "a1", 27 | states: { 28 | a1: { 29 | id: "foo", 30 | always: [ 31 | { target: "#baz" }, 32 | // @ts-expect-error 33 | { target: "zzz" } 34 | ] 35 | }, 36 | a2: {} 37 | } 38 | }, 39 | b: { 40 | id: "baz", 41 | initial: "b1", 42 | states: { 43 | b1: {}, 44 | b2: {} 45 | }, 46 | // delimiter: "/", TODO 47 | on: { 48 | A: ".b2", 49 | B: "a.a2", 50 | C: { 51 | target: "#bar.a.a2", 52 | // TODO @\ts-expect-error enforce internal: false 53 | internal: true 54 | }, 55 | // @ts-expect-error 56 | Z: "" 57 | } 58 | } 59 | } 60 | }) 61 | 62 | createMachine({ 63 | initial: "a", 64 | // @ts-expect-error 65 | id: "bar", 66 | states: { 67 | a: { 68 | // @ts-expect-error 69 | id: "bar" 70 | }, 71 | b: { 72 | // @ts-expect-error 73 | id: "foo" 74 | }, 75 | c: { 76 | // @ts-expect-error 77 | id: "foo" 78 | } 79 | } 80 | }) 81 | 82 | createMachine({ 83 | // @ts-expect-error 84 | id: 1, 85 | }) 86 | 87 | let t0 = createMachine({ 88 | initial: "a", 89 | context: {}, 90 | states: { a: {} } 91 | }) 92 | 93 | t0.config.initial === "a" 94 | // @ts-expect-error 95 | t0.config.initial === ".a" 96 | 97 | createMachine({ 98 | initial: { target: "a" }, 99 | context: {}, 100 | states: { a: {} } 101 | }) 102 | 103 | createMachine({ 104 | context: {}, 105 | initial: { 106 | // @ts-expect-error 107 | target: "x" 108 | }, 109 | states: { a: {} } 110 | }) 111 | 112 | createMachine({ 113 | initial: [ 114 | // @ts-expect-error 115 | ".a", 116 | // @ts-expect-error 117 | ".c.c1" 118 | ], 119 | states: { 120 | a: { on: { FOO: "c" } }, 121 | c: { 122 | initial: "c1", 123 | states: { 124 | c1: {} 125 | } 126 | } 127 | } 128 | }) 129 | 130 | createMachine({ 131 | context: {}, 132 | initial: "a", 133 | states: { 134 | a: { 135 | initial: "p", 136 | states: { 137 | p: { on: { X: "q" } }, 138 | q: {} 139 | } 140 | } 141 | }, 142 | // @ts-expect-error 143 | on: { X: "states" } 144 | }) 145 | -------------------------------------------------------------------------------- /src/MachineDefinition/MachineDefintion.Entry.spec.ts: -------------------------------------------------------------------------------- 1 | import { createSchema, createMachine } from ".."; 2 | import { A } from "../extras"; 3 | 4 | createMachine({ 5 | initial: "a", 6 | context: {}, 7 | schema: { 8 | events: createSchema< 9 | | { type: "FOO", x: number } 10 | | { type: "BAR" } 11 | >() 12 | }, 13 | states: { 14 | a: { 15 | on: { 16 | FOO: "b.b1", 17 | BAR: "c", 18 | // @ts-expect-error 19 | BAZ: "a" 20 | }, 21 | always: { 22 | target: "b.b2" 23 | } 24 | }, 25 | b: { 26 | initial: "b1", 27 | states: { 28 | b1: {}, 29 | b2: {} 30 | }, 31 | entry: (_, event) => { 32 | A.test(A.areEqual< 33 | typeof event, 34 | | { type: "FOO", x: number } 35 | | { type: "xstate.init" } 36 | >()) 37 | } 38 | }, 39 | c: {} 40 | } 41 | }) 42 | 43 | createMachine({ 44 | initial: "a", 45 | context: {}, 46 | schema: { 47 | // @ts-expect-error 48 | events: createSchema< 49 | | { noType: "" } 50 | >() 51 | }, 52 | states: { 53 | a: { } 54 | } 55 | }) 56 | 57 | createMachine({ 58 | initial: "a", 59 | context: {}, 60 | states: { 61 | a: { 62 | on: { FOO: "b" } 63 | }, 64 | b: { 65 | always: { target: "c" }, 66 | on: { BAR: "a" } 67 | }, 68 | c: { 69 | entry: (_, event) => { 70 | A.tests([ 71 | A.areEqual() 72 | ]) 73 | } 74 | } 75 | } 76 | }) 77 | 78 | 79 | createMachine({ 80 | initial: "a", 81 | context: {}, 82 | states: { 83 | a: {} 84 | }, 85 | on: { 86 | X: { target: ".a" } 87 | }, 88 | entry: [(_, event) => { 89 | A.test(A.areEqual()) 90 | }, "a"] 91 | }) 92 | 93 | createMachine({ 94 | initial: "a", 95 | context: {}, 96 | states: { 97 | a: {} 98 | }, 99 | on: { 100 | X: { target: ".a", internal: false } 101 | }, 102 | entry: (_, event) => { 103 | A.test(A.areEqual()) 104 | } 105 | }) 106 | 107 | createMachine({ 108 | initial: "a", 109 | context: {}, 110 | states: { 111 | a: { 112 | _: null, 113 | entry: (_, event) => { 114 | A.tests([ 115 | A.areEqual() 116 | ]) 117 | } 118 | }, 119 | b: { 120 | entry: (_, event) => { 121 | A.tests([ 122 | A.areEqual() 123 | ]) 124 | } 125 | }, 126 | c: { 127 | // @\ts-expect-error TODO 128 | entry: {} 129 | } 130 | }, 131 | on: { 132 | X: [ 133 | { target: ".a" }, 134 | { target: ".b" } 135 | ] 136 | }, 137 | }) 138 | 139 | 140 | let testA = createMachine({ 141 | initial: "a", 142 | context: {}, 143 | states: { 144 | a: { 145 | on: { FOO: "b" }, 146 | entry: [(_, event) => { 147 | A.test(A.areEqual()) 148 | }] 149 | }, 150 | b: { 151 | entry: (_, event) => { 152 | A.test(A.areEqual()) 153 | } 154 | }, 155 | c: { entry: "a" }, 156 | d: { entry: [] } 157 | }, 158 | entry: [(_, event) => { 159 | A.tests([ 160 | A.areEqual() 161 | ]) 162 | }, "a"] 163 | }) 164 | /* 165 | TODO: TS 4.4.0 regression 166 | testA.config.entry[0]({} as any, { 167 | type: "FOO" 168 | }) 169 | testA.config.entry[0]({} as any, { 170 | // @ts-expect-error 171 | type: "" 172 | }) 173 | 174 | testA.config.states.a.entry[0]({} as any, { 175 | type: "xstate.init" 176 | }) 177 | testA.config.states.a.entry[0]({} as any, { 178 | // @ts-expect-error 179 | type: "" 180 | }) 181 | 182 | testA.config.entry[1] === "a" 183 | // @ts-expect-error 184 | testA.config.entry[1] === "" 185 | 186 | testA.config.states.c.entry === "a"; 187 | // @ts-expect-error 188 | testA.config.states.c.entry === ""; 189 | */ 190 | -------------------------------------------------------------------------------- /src/MachineDefinition/index.ts: -------------------------------------------------------------------------------- 1 | import { UnknownBehavior } from "../Behavior"; 2 | import { O, A, U, L, B, S, F } from "../extras"; 3 | import Machine from "../Machine"; 4 | import { ReferencePathString } from "../universal"; 5 | 6 | export default MachineDefinition; 7 | namespace MachineDefinition { 8 | export type Of< 9 | Global, 10 | Definition = A.Get, 11 | ContextSchema = A.Get, 12 | Context = A.Get 13 | > = 14 | & StateNode.Of 15 | & { schema?: 16 | { events?: 17 | A.Get extends { type: string } 18 | ? A.Get 19 | : `Error: The type you provided does not extends { type: string }` 20 | , context?: 21 | A.IsPlainObject> extends true 22 | ? A.Get 23 | : `Error: The type you is not an object` 24 | } 25 | } 26 | & { context: 27 | ContextSchema extends undefined 28 | ? Context extends A.Function 29 | ? A.IsPlainObject> extends true 30 | ? Context 31 | : () => `Error: context should be an object` 32 | : A.IsPlainObject extends true 33 | ? Context 34 | : `Error: context should be an object` 35 | : A.Get extends A.Function 36 | ? () => A.Get 37 | : A.Get 38 | } 39 | & { [$$Self]?: Definition } 40 | 41 | 42 | export declare const $$Self: unique symbol; 43 | export type $$Self = typeof $$Self; 44 | export declare const $$Internal: unique symbol; 45 | export type $$Internal = typeof $$Internal; 46 | export type Internal = { [$$Internal]: T } 47 | 48 | export namespace Global { 49 | export type Resolved extends { [MachineDefinition.$$Self]?: infer X } 52 | ? X 53 | : undefined 54 | > = 55 | Self extends undefined 56 | ? Global 57 | : { Definition: Self 58 | , Precomputed: Precomputed.Of 59 | } 60 | } 61 | 62 | export type Desugar = 63 | & StateNode.Desugar 64 | & { [K in U.Extract]: D[K] } 65 | 66 | export namespace Precomputed { 67 | export type FromGlobal< 68 | Global, 69 | Key extends 70 | | "ReferencePathString.OfId" 71 | | "ReferencePathString" 72 | | "IdMap" 73 | | "DesugaredDefinition" 74 | | "InitialStateNodeReferencePathString" 75 | > = 76 | A.Get 77 | 78 | export type Of = 79 | { "ReferencePathString.OfId": ReferencePathString.Unresolved.OfIdWithRoot 80 | , "ReferencePathString": ReferencePathString.WithRoot 81 | , "IdMap": IdMap.WithRoot 82 | , "DesugaredDefinition": MachineDefinition.Desugar 83 | } extends infer P 84 | ? & P 85 | & { "InitialStateNodeReferencePathString": 86 | Machine.InitialStateNodeReferencePathString.Of<{ Definition: Definition, Precomputed: P }> 87 | } 88 | : never 89 | } 90 | 91 | export namespace StateNode { 92 | export type Of< 93 | Global, 94 | Path, 95 | 96 | Definition = A.Get, 97 | Self = A.Get, 98 | States = A.Get, 99 | Type = A.Get, 100 | On = A.Get, 101 | EventIdentifierSpec = A.Get, 102 | IsAfterRecord = A.DoesExtend, undefined>, 103 | Context = Machine.Context.Of, 104 | Event = Machine.Event.Of 105 | > = 106 | & { type?: 107 | | "compound" 108 | | "parallel" 109 | | "final" 110 | | "history" 111 | | "atomic" 112 | } 113 | & ( Type extends "atomic" ? 114 | { initial?: "Error: atomic state node can't have initial property" } : 115 | [keyof States] extends [never] ? 116 | { initial?: "Error: no states defined" } : 117 | Type extends "parallel" ? 118 | { initial?: undefined } : 119 | { initial: 120 | Transition.OfWithStateNodePathContextEvent< 121 | Global, L.Pushed, 122 | Path, Context, Event 123 | > 124 | } 125 | ) 126 | & { states?: 127 | Type extends "atomic" 128 | ? "Error: atomic state node can't have states property" 129 | : { [StateIdentifier in keyof States]: 130 | StateIdentifier extends A.String 131 | ? S.DoesContain extends B.True 132 | ? `Error: identifiers can't have '.' as it's use as a path delimiter` 133 | : StateNode.Of> 134 | : `Error: only string identifiers allowed` 135 | } 136 | , on?: 137 | { [EventIdentifier in keyof On]: 138 | EventIdentifier extends A.String 139 | ? L.Some< 140 | [ A.DoesExtend<[EventIdentifierSpec], [never]> 141 | , A.DoesExtend 142 | ]> extends true 143 | ? Transition.OfWithStateNodePathContextEvent< 144 | Global, L.Concat, 145 | Path, Context, U.Extract 146 | > 147 | : `Error: ${EventIdentifier} is not included in schema.event` 148 | : "Error: only string identifier allowed" 149 | } 150 | , always?: 151 | Transition.OfWithStateNodePathContextEvent< 152 | Global, L.Pushed, 153 | Path, Context, Event 154 | > 155 | , after?: 156 | | ( IsAfterRecord extends true ? never : 157 | Transition.OfWithStateNodePathContextEvent< 158 | Global, L.Pushed, 159 | Path, Context, Event 160 | > 161 | ) 162 | | { [N in keyof A.Get]: 163 | Transition.OfWithStateNodePathContextEvent< 164 | Global, L.Concat, 165 | Path, Context, Event 166 | > 167 | } 168 | , onDone?: 169 | Transition.OfWithStateNodePathContextEvent< 170 | Global, L.Pushed, 171 | Path, Context, Machine.Event.ForDone.OfWithStateNodePath 172 | > 173 | , _?: null 174 | , entry?: 175 | Execable.OfWithContextEvent< 176 | Global, L.Pushed, 177 | Context, Machine.Event.ForEntry.OfWithStateNodePath, "IsAction" 178 | > 179 | , exit?: 180 | Execable.OfWithContextEvent< 181 | Global, L.Pushed, 182 | Context, Machine.Event.ForExit.OfWithStateNodePath, "IsAction" 183 | > 184 | , invoke?: Invocation.OfWithStateNodePath, Path> 185 | , id?: Id.Of> 186 | , order?: number 187 | , meta?: unknown 188 | , strict?: boolean 189 | , history?: 190 | Type extends "history" 191 | ? "shallow" | "deep" | boolean 192 | : "Error: history can be only set for history nodes" 193 | , target?: 194 | Type extends "history" 195 | ? Transition.TargetWithStateNodePath, Path> 196 | : "Error: target can be only set for history nodes" 197 | , data?: 198 | A.DoesExtend extends false 199 | ? "Error: data can be only set for final nodes" : 200 | | (( context: Machine.Context.Of 201 | , event: Machine.Event.Of 202 | ) => unknown) 203 | | { [K in A.String]: 204 | | ( ( context: Machine.Context.Of 205 | , event: Machine.Event.Of 206 | ) => unknown 207 | ) 208 | | U.Exclude 209 | } 210 | , tags?: 211 | A.TupleOrUnitOfStringLiteral> 212 | } 213 | 214 | export type Desugar = 215 | { type: A.Get] extends [never] ? "atomic" : 217 | keyof A.Get extends undefined ? "parallel" : 218 | "compound" 219 | > 220 | , initial: Transition.Desugar> 221 | , states: A.Get extends infer States 222 | ? { [S in keyof States]: Desugar> } 223 | : never 224 | , on: A.Get extends infer On 225 | ? { [K in keyof On]: Transition.Desugar 226 | } 227 | : never 228 | , always: Transition.Desugar> 229 | , after: 230 | A.Get extends infer After 231 | ? After extends A.Tuple 232 | ? Transition.Desugar 233 | : { [K in keyof After]: 234 | Transition.Desugar 235 | } 236 | : never 237 | , onDone: Transition.Desugar> 238 | , entry: Execable.Desugar, "entry"> 239 | , exit: Execable.Desugar, "exit"> 240 | , invoke: Invocation.Desugar> 241 | , id: A.Get 242 | , order: A.Get 243 | , meta: A.Get 244 | , strict: A.Get 245 | , history: A.Get extends "history" ? A.Get : undefined 246 | , target: A.Get 247 | , data: A.Get 248 | , tags: A.Get 249 | } 250 | } 251 | 252 | export namespace Transition { 253 | export type OfWithStateNodePathContextEvent< 254 | Global, 255 | Path, 256 | StateNodePath, 257 | Context, 258 | Event, 259 | Flags = never, 260 | Definition = A.Get, 261 | Self = A.Get, 262 | IsInitial = A.DoesExtend, "initial"> 263 | > = 264 | IsInitial extends true 265 | ? | TargetWithStateNodePath 266 | | TargetAndExtrasWithStateNodePathContextEvent< 267 | Global, Path, 268 | StateNodePath, Context, Event 269 | > : 270 | | TargetAndExtrasWithStateNodePathContextEvent< 271 | Global, Path, 272 | StateNodePath, Context, Event, Flags 273 | > 274 | | ( Self extends { target: any } ? never : 275 | | TargetWithStateNodePath 276 | | ( Self extends A.Tuple 277 | ? { [K in keyof Self]: 278 | TargetAndExtrasWithStateNodePathContextEvent< 279 | Global, L.Pushed, 280 | StateNodePath, Context, Event, Flags 281 | > 282 | } 283 | : A.Tuple, 285 | StateNodePath, Context, Event, "NoChecks" | Flags 286 | >> 287 | ) 288 | ) 289 | 290 | export type TargetAndExtrasWithStateNodePathContextEvent< 291 | Global, 292 | Path, 293 | StateNodePath, 294 | Context, 295 | Event, 296 | Flags = never, 297 | Definition = A.Get, 298 | IsAfter = 299 | L.Some< 300 | [ A.DoesExtend, "after"> 301 | , A.DoesExtend, "after"> 302 | ]>, 303 | IsAfterRecord = 304 | A.DoesExtend, "length">>, undefined> 305 | > = 306 | { target: 307 | TargetWithStateNodePath< 308 | Global, 309 | L.Pushed, 310 | StateNodePath, 311 | Flags 312 | > 313 | , guard?: Execable.OfWithContextEvent< 314 | Global, L.Pushed, 315 | Context, Event, "IsGuard" 316 | > 317 | , actions?: Execable.OfWithContextEvent< 318 | Global, L.Pushed, 319 | Context, Event, "IsAction" 320 | > 321 | , internal?: boolean 322 | , delay?: 323 | IsAfter extends true 324 | ? IsAfterRecord extends true 325 | ? `Error: delay is already set as ${A.Cast, A.Number | A.String>}` 326 | : | ( ( context: Machine.Context.Of 327 | , event: Machine.Event.Of 328 | ) => A.Number 329 | ) 330 | | A.String 331 | | A.Number 332 | : "Error: `delay` can be set only for `after` transitions" 333 | } 334 | 335 | export type TargetWithStateNodePath< 336 | Global, 337 | Path, 338 | StateNodePath, 339 | Flags = never, 340 | 341 | Definition = A.Get, 342 | StateNode = A.Get, 343 | Self = A.Get extends infer X ? X : never, 344 | IsRoot = A.Get extends 0 ? true : false, 345 | SiblingIdentifier = IsRoot extends true ? never : keyof A.Get>, 346 | TargetPathString = 347 | | ( ReferencePathString.WithRoot extends infer X ? S.Assert : never ) 348 | | ( ReferencePathString.WithRoot extends infer X ? S.Assert : never ) 349 | | ( Precomputed.FromGlobal extends infer X ? S.Assert : never ) 350 | | ( [SiblingIdentifier] extends [never] 351 | ? never 352 | : SiblingIdentifier extends any 353 | ? ReferencePathString.WithRoot< 354 | A.Get, SiblingIdentifier]>, 355 | SiblingIdentifier, 356 | 2 357 | > extends infer X ? S.Assert : never 358 | : never 359 | ) 360 | > = 361 | | ( "NoChecks" extends Flags ? TargetPathString : 362 | Self extends A.String 363 | ? TargetPathString 364 | : never 365 | ) 366 | | ( "NoChecks" extends Flags ? A.Tuple : 367 | Self extends A.Tuple 368 | ? ParallelTargetPathStrings.OfWithStateNodePath< 369 | Global, 370 | Path, 371 | StateNodePath 372 | > 373 | : A.Tuple 374 | ) 375 | 376 | export type Desugar = 377 | ( T extends A.Object[] ? T : 378 | T extends A.Object ? [T] : 379 | T extends A.String | A.Tuple ? [{ target: T }] : 380 | T extends undefined ? [] : 381 | never 382 | ) extends infer Ts 383 | ? { [K in keyof Ts]: 384 | { target: 385 | A.Get extends infer T 386 | ? T extends A.Tuple ? T : [T] 387 | : never 388 | , internal: A.Get 389 | , guard: Execable.Desugar, "guard"> 390 | , actions: Execable.Desugar, "actions"> 391 | , delay: A.Get 392 | } extends infer Target 393 | ? O.Update]: 395 | A.Get[I] extends infer T 396 | ? S.DoesStartWith extends true ? A.Get : 397 | T extends undefined ? A.Get : 398 | false 399 | : never 400 | }> 401 | }> 402 | : false 403 | } 404 | : never 405 | } 406 | 407 | export namespace ParallelTargetPathStrings { 408 | 409 | /* 410 | const regionRoot = node => 411 | !node.parent ? node : 412 | node.parent.type === "parallel" ? node : 413 | regionRoot(node.parent) 414 | 415 | const isParallelTargetValid = targets => 416 | targets.some(i => target.some(j => isAncestor(i, j))) ? false : 417 | (roots => roots.length !== deduplicated(roots).length)(targets.map(regionRoot)) ? false : 418 | true 419 | */ 420 | 421 | export type OfWithStateNodePath< 422 | Global, 423 | Path, 424 | StateNodePath, 425 | 426 | Definition = A.Get, 427 | Self = A.Get, 428 | StateReferencePathString = ReferencePathString.FromDefinitionPath, 429 | SelfResolved = 430 | { [I in keyof Self]: 431 | ReferencePathString.Unresolved.ResolveWithStateNode< 432 | Global, 433 | Self[I], 434 | StateReferencePathString 435 | > 436 | }, 437 | RegionRootOf = 438 | { [I in keyof SelfResolved]: 439 | ReferencePathString.RegionRoot 440 | } 441 | > = 442 | { [I in keyof Self]: 443 | [ 444 | | ({ [J in keyof Self]: 445 | J extends I ? never : 446 | ReferencePathString.IsDescendant< 447 | A.Get, 448 | A.Get 449 | > extends B.True 450 | ? Self[J] 451 | : never 452 | }[number & keyof Self] extends infer Ancestors 453 | ? [Ancestors] extends [never] 454 | ? never 455 | : `Error: ${S.Assert} is descendant of ${S.Commas>}` 456 | : never) 457 | | ({ [J in keyof Self]: 458 | J extends I ? never : 459 | ReferencePathString.IsAncestor< 460 | S.Assert>, 461 | S.Assert> 462 | > extends B.True 463 | ? Self[J] 464 | : never 465 | }[number & keyof Self] extends infer Descendants 466 | ? [Descendants] extends [never] 467 | ? never 468 | : `Error: ${S.Assert} is ancestor of ${S.Commas>}` 469 | : never) 470 | , { [J in keyof Self]: 471 | J extends I ? never : 472 | A.Get extends A.Get ? Self[J] : 473 | never 474 | }[number & keyof Self] extends infer NodesWithCommonRegionRoot 475 | ? [NodesWithCommonRegionRoot] extends [never] 476 | ? never 477 | : `Error: ${S.Assert} has region root same as that of ${ 478 | S.Commas 479 | }` 480 | : never 481 | ] extends [infer AncestryError, infer RegionRootError] 482 | ? [AncestryError] extends [never] 483 | ? [RegionRootError] extends [never] 484 | ? Self[I] 485 | : RegionRootError 486 | : AncestryError 487 | : never 488 | } 489 | } 490 | 491 | export namespace IdMap { 492 | export type WithRoot = 493 | O.Mergify>>> 494 | 495 | type _WithRoot< 496 | StateNode, 497 | PathString = "", 498 | 499 | Id = A.Get, 500 | States = A.Get 501 | > = 502 | | ( Id extends undefined ? {} : { [_ in S.Assert]: Id } ) 503 | | { [S in keyof States]: 504 | _WithRoot, ReferencePathString.Append>> 505 | }[keyof States] 506 | 507 | A.tests([ 508 | A.areEqual< 509 | IdMap.WithRoot<{ id: "root", states: { 510 | a: { states: { a1: {}, a2: {} } }, 511 | b: { states: { b1: {}, b2: { id: "bar" } } } 512 | } }>, 513 | { "": "root", "b.b2": "bar" } 514 | >() 515 | ]) 516 | } 517 | 518 | export namespace Id { 519 | export type Of< 520 | Global, 521 | Path, 522 | Definition = A.Get, 523 | 524 | Self = A.Get, 525 | IdMap = Precomputed.FromGlobal 526 | > = 527 | Self extends A.String 528 | ? U.IsUnit> extends B.True 529 | ? Self 530 | : `Ids should be unique, '${Self}' is already used` 531 | : "Ids should be strings" 532 | } 533 | 534 | export namespace Execable { 535 | export type OfWithContextEvent< 536 | Global, 537 | Path, 538 | Context, 539 | Event, 540 | Flags = never, 541 | Definition = A.Get, 542 | Self = A.Get 543 | > = 544 | | ( "IsImplementation" extends Flags ? never : 545 | ( "IsGuard" extends Flags ? never : 546 | | [ Unit< 547 | Global, L.Pushed, 548 | Context, Event, "IsTupleElement" | Flags 549 | > 550 | ] 551 | | ( Self extends { type: unknown } | [{ type: unknown }] ? never : 552 | { [K in keyof Self]: 553 | Unit< 554 | Global, L.Pushed, 555 | Context, Event, "IsTupleElement" | Flags 556 | > 557 | } 558 | ) 559 | ) 560 | ) 561 | | Unit 562 | 563 | type Unit< 564 | Global, Path, 565 | Context, Event, 566 | Flags = never, 567 | Definition = A.Get, 568 | Self = A.Get 569 | > = 570 | | ( "IsImplementation" extends Flags ? never : S.InferNarrowest ) 571 | | ( "IsAction" extends Flags 572 | ? Machine.XstateAction.InferralHint.OfWithAdjacentAction< 573 | Global, 574 | ( ( context: Context 575 | , event: Event 576 | , meta: "TODO" 577 | ) => unknown 578 | ) 579 | > : 580 | "IsGuard" extends Flags 581 | ? (context: Context, event: Event, meta: "TODO") => boolean : 582 | (context: Context, event: Event, meta: "TODO") => unknown 583 | ) 584 | | ( { type: 585 | "IsImplementation" extends Flags 586 | ? A.String 587 | : S.InferNarrowest> 588 | , exec?: 589 | ( context: Context 590 | , event: Event 591 | , meta: "TODO" 592 | ) => unknown 593 | } 594 | & ( "IsTupleElement" extends Flags 595 | ? { [_ in A.String]: unknown } 596 | : { [_ in U.Exclude]: unknown } 597 | ) 598 | ) 599 | 600 | export type Desugar = 601 | A extends undefined ? [] : 602 | (A extends any[] ? A : [A]) extends infer A 603 | ? { [I in keyof A]: 604 | A[I] extends A.String ? { type: A[I] } : 605 | A[I] extends A.Function ? { 606 | type: 607 | A[I] extends { name: infer X } 608 | ? string extends X ? DefaultType : X 609 | : DefaultType, 610 | exec: A[I] 611 | } : 612 | A[I] 613 | } 614 | : never 615 | } 616 | 617 | export namespace Invocation { 618 | export type OfWithStateNodePath< 619 | Global, 620 | Path, 621 | StateNodePath, 622 | Flags = never, 623 | Definition = A.Get, 624 | Self = A.Get 625 | > = 626 | | [ Unit, StateNodePath> ] 627 | | ( Self extends A.Tuple 628 | ? { [K in keyof Self]: Unit, StateNodePath> } 629 | : never 630 | ) 631 | | Unit 632 | 633 | type Unit< 634 | Global, 635 | Path, 636 | StateNodePath, 637 | Definition = A.Get, 638 | Self = A.Get, 639 | Context = Machine.Context.Of, 640 | Event = Machine.Event.ForEntry.OfWithStateNodePath 641 | > = 642 | | S.InferNarrowest 643 | | ( ( context: Context 644 | , event: Event 645 | ) => UnknownBehavior 646 | ) 647 | | { src?: 648 | | S.InferNarrowest> 649 | | ( { type: S.InferNarrowest> } 650 | & { [_ in A.String]: unknown } 651 | ) 652 | | ( ( context: Context 653 | , event: Event 654 | , meta: "TODO" 655 | ) => UnknownBehavior 656 | ) 657 | , id?: S.InferNarrowest> 658 | , autoForward?: boolean 659 | , data?: // TODO 660 | | ( ( context: Context 661 | , event: Event 662 | ) => unknown 663 | ) 664 | | { [K in A.Key]: 665 | ( context: Context 666 | , event: Event 667 | ) => unknown 668 | } 669 | , onDone?: // TODO 670 | Transition.OfWithStateNodePathContextEvent< 671 | Global, L.Pushed, 672 | StateNodePath, Context, Event 673 | > 674 | , onError?: // TODO 675 | Transition.OfWithStateNodePathContextEvent< 676 | Global, L.Pushed, 677 | StateNodePath, Context, Event 678 | > 679 | } 680 | 681 | export type Desugar = 682 | ( Is extends undefined ? [] : 683 | Is extends A.Tuple ? Is : [Is] 684 | ) extends infer Is 685 | ? { [K in keyof Is]: 686 | ( Is[K] extends A.String ? { src: { type: Is[K] } } : 687 | Is[K] extends A.Function ? { src: Is[K] } : 688 | Is[K] 689 | ) extends infer I 690 | ? { src: 691 | A.Get extends infer Src 692 | ? Src extends A.String ? { type: Src } : 693 | Src 694 | : never 695 | , id: A.Get 696 | , autoForward: A.Get 697 | , data: A.Get 698 | , onDone: Transition.Desugar> 699 | , onError: Transition.Desugar> 700 | } 701 | : never 702 | } 703 | : never 704 | } 705 | } 706 | -------------------------------------------------------------------------------- /src/MachineImplementations/MachineImplemetations.spec.ts: -------------------------------------------------------------------------------- 1 | import { createMachine, createSchema, send, createBehaviorFrom } from ".."; 2 | import { A } from "../extras"; 3 | 4 | type User = { name: string }; 5 | declare const logInFromCookie: () => Promise 6 | 7 | createMachine({ 8 | schema: { 9 | context: createSchema<{ user: null } | { user: User }>(), 10 | events: createSchema< 11 | | { type: "LOGIN", user: User } 12 | | { type: "LOGOUT" } 13 | >() 14 | }, 15 | context: { user: null }, 16 | initial: "loggedOut", 17 | states: { 18 | loggedOut: { 19 | on: { 20 | LOGIN: { target: "loggedIn", actions: "sendLogInAnalytics" } 21 | }, 22 | initial: "tryingToLoginFromCookie", 23 | states: { 24 | idle: {}, 25 | tryingToLoginFromCookie: { 26 | invoke: { 27 | src: "tryLoggingInFromCookie" 28 | } 29 | } 30 | } 31 | }, 32 | loggedIn: { 33 | on: { 34 | LOGOUT: { target: "loggedOut.idle", actions: ["foo", "bar"] } 35 | } 36 | } 37 | } 38 | }, { 39 | actions: { 40 | sendLogInAnalytics: (c, e) => { 41 | A.tests([ 42 | A.areEqual(), 43 | A.areEqual() 44 | ]) 45 | }, 46 | foo: send( 47 | // @ts-expect-error 48 | "" 49 | ), 50 | bar: send("LOGIN") 51 | }, 52 | behaviors: { 53 | tryLoggingInFromCookie: (c, e) => { 54 | A.tests([ 55 | A.areEqual(), 56 | A.areEqual() 57 | ]) 58 | 59 | return createBehaviorFrom(logInFromCookie()) 60 | } 61 | } 62 | }) 63 | -------------------------------------------------------------------------------- /src/MachineImplementations/index.ts: -------------------------------------------------------------------------------- 1 | import { UnknownBehavior } from "../Behavior"; 2 | import { A, U, S, L, O } from "../extras"; 3 | import Machine from "../Machine"; 4 | import MachineDefinition from "../MachineDefinition"; 5 | 6 | export default MachineImplementations; 7 | namespace MachineImplementations { 8 | export type Of< 9 | _Global, 10 | Global = MachineDefinition.Global.Resolved<_Global>, 11 | _I = U.ToIntersection>, 12 | I = U.ToIntersection< 13 | { [K in keyof _I]: 14 | [keyof _I[K]] extends [never] 15 | ? { [_ in K]?: _I[K] } 16 | : { [_ in K]: _I[K] } 17 | }[keyof _I] 18 | > 19 | > = 20 | { [T in keyof I]: { [K in keyof I[T]]: I[T][K] } } 21 | 22 | 23 | type WithRoot< 24 | Global, 25 | RootNodePath, 26 | Definition = A.Get, 27 | Root = A.Get, 28 | Context = Machine.Context.Of, 29 | UniversalEvent = Machine.Event.Of, 30 | EntryEvent = Machine.Event.ForEntry.OfWithStateNodePath, 31 | States = A.Get, 32 | On = A.Get, 33 | Entry = A.Get 34 | > = 35 | | O.Value<{ [ExecableType in "action" | "guard"]: 36 | [keyof On] extends [never] ? { actions: {} } | { guards: {} } : 37 | O.Value<{ [E in keyof On]: 38 | A.Get< 39 | MachineDefinition.Transition.Desugar, 40 | [ number 41 | , ExecableType extends "action" ? "actions" : 42 | ExecableType extends "guard" ? "guard" : 43 | never 44 | , ExecableType extends "action" ? number : 45 | ExecableType extends "guard" ? A.Get.Identity : 46 | never 47 | , "type" 48 | ] 49 | > extends infer I ? 50 | S.IsLiteral extends false ? {} : // TODO: don't capture defaultActionType 51 | I extends any ? 52 | { [_ in `${S.Assert}s`]: 53 | { [_ in S.Assert]: 54 | MachineDefinition.Execable.OfWithContextEvent< 55 | Global, 56 | L.Concat, 61 | Context, 62 | U.Extract, 63 | | ( ExecableType extends "action" ? "IsAction" : 64 | ExecableType extends "guard" ? "IsGuard" : 65 | never 66 | ) 67 | | "IsImplementation" 68 | > 69 | } 70 | } 71 | : never 72 | : never 73 | }> 74 | }> 75 | | ( A.Get, [number, "type"]> extends infer I 76 | ? S.IsLiteral extends false ? {} : 77 | { actions: 78 | { [_ in S.Assert]: 79 | MachineDefinition.Execable.OfWithContextEvent< 80 | Global, 81 | L.Concat, 82 | Context, 83 | EntryEvent, 84 | "IsAction" | "IsImplementation" 85 | > 86 | } 87 | } 88 | : never 89 | ) 90 | | ( A.Get< 91 | MachineDefinition.Invocation.Desugar>, 92 | [number, "src", "type"] 93 | > extends infer I 94 | ? S.IsLiteral extends false ? { behaviors: {} } : 95 | I extends any 96 | ? { behaviors: 97 | { [_ in S.Assert]: 98 | ( context: Context 99 | , event: EntryEvent 100 | , meta: "TODO" 101 | ) => UnknownBehavior 102 | } 103 | } 104 | : never 105 | : never 106 | ) 107 | | ( [keyof States] extends [never] ? never : 108 | O.Value<{ [S in keyof States]: 109 | WithRoot> 110 | }> 111 | ) 112 | } 113 | -------------------------------------------------------------------------------- /src/extras.ts: -------------------------------------------------------------------------------- 1 | export namespace O { 2 | export type Assert = A.Cast; 3 | 4 | export type KeyWithValue = 5 | { [K in keyof O]: O[K] extends V ? K : never }[keyof O] 6 | 7 | export type Mergify = 8 | { [K in keyof T]: T[K] } 9 | 10 | export type Update = 11 | & { [K in U.Exclude]: A[K] } 12 | & { [K in keyof B]: B[K] } 13 | 14 | export type Omit = 15 | { [P in U.Exclude]: T[P] } 16 | 17 | export type Value = 18 | T[keyof T] 19 | } 20 | 21 | export namespace L { 22 | export type Assert = A.Cast; 23 | 24 | export type Concat = 25 | [...L.Assert, ...L.Assert] 26 | 27 | export type Pushed = 28 | [...L.Assert, X]; 29 | 30 | export type Popped = 31 | A extends [] ? [] : 32 | A extends [...infer Popped, any] ? Popped : never 33 | 34 | export type Pop = 35 | A extends [] ? undefined : 36 | A extends [...L.Popped, infer X] ? X : never; 37 | 38 | export type Shifted = 39 | A extends [] ? [] : 40 | A extends [any, ...infer Shifted] ? Shifted : never 41 | 42 | export type Shift = 43 | A extends [] ? undefined : 44 | A extends [infer X, ...infer _] ? X : never; 45 | 46 | export type Unshift = 47 | [X, ...L.Assert] 48 | 49 | export type ConcatAll = 50 | Ls extends [] ? [] : 51 | Ls extends [infer A] ? A : 52 | Ls extends [infer A, infer B, ...infer X] ? ConcatAll<[L.Concat, ...X]> : 53 | never 54 | 55 | export type Join = 56 | L extends [] ? "" : 57 | L extends [infer H, ...infer T] 58 | ? T extends [] ? H : `${S.Assert}${S.Assert}${Join}` : 59 | string; 60 | 61 | export type Includes = 62 | A extends [] ? false : 63 | X extends A.Get ? true : false; 64 | 65 | export type IncludesSubtype = 66 | A extends [] ? false : 67 | A.Get extends X ? true : false; 68 | 69 | export type Every = 70 | A extends [] ? true : 71 | A.AreEqual>, true> 72 | 73 | export type Some = 74 | B.Not, false>> 75 | 76 | export type Filter = 77 | L extends [] ? [] : 78 | L extends [infer H, ...infer T] 79 | ? H extends X 80 | ? Filter 81 | : [H, ...Filter] 82 | : never 83 | export namespace Filter { 84 | declare const Out: unique symbol; 85 | export type Out = typeof Out; 86 | } 87 | 88 | export type Get = 89 | N.IsWhole extends true 90 | ? A.Get 91 | : A.Get>> 92 | } 93 | 94 | export namespace A { 95 | export type Cast = T extends U ? T : U; 96 | export type Function = (...args: any[]) => any; 97 | export type Tuple = T[] | [T]; 98 | export type TupleOrUnit = T | Tuple; 99 | 100 | export type TupleOrUnitOfStringLiteral = 101 | | [S.InferNarrowest>] 102 | | { [K in keyof Self]: S.InferNarrowest } 103 | | (S.InferNarrowest) 104 | 105 | export type Object = object; 106 | export type String = string; 107 | export type Number = number; 108 | export type Universal = 109 | | string | number | boolean | undefined | null | bigint 110 | | object | ((...a: any[]) => any) 111 | export type Key = keyof any; 112 | 113 | 114 | export type Get = 115 | P extends any[] 116 | ? P extends [] ? 117 | T extends undefined ? F : T : 118 | P extends [infer K1, ...infer Kr] ? 119 | K1 extends Get.Parameters ? 120 | F.Parameters : 121 | K1 extends Get.Called ? 122 | F.Called : 123 | K1 extends Get.Identity ? 124 | Get : 125 | K1 extends keyof T ? 126 | Get extends infer X ? A.Cast : never : 127 | F : 128 | never 129 | : Get 130 | 131 | export namespace Get { 132 | declare const Parameters: unique symbol; 133 | export type Parameters = typeof Parameters; 134 | 135 | declare const Called: unique symbol; 136 | export type Called = typeof Called; 137 | 138 | declare const Identity: unique symbol; 139 | export type Identity = typeof Identity; 140 | } 141 | 142 | export type InferNarrowest = 143 | T extends any 144 | ? ( T extends A.Function ? T : 145 | T extends A.Object ? InferNarrowestObject : 146 | T 147 | ) 148 | : never 149 | 150 | export type InferNarrowestObject = 151 | { readonly [K in keyof T]: InferNarrowest } 152 | 153 | export type NoInfer = 154 | [T][T extends any ? 0 : never] 155 | 156 | export type AreEqual = 157 | (() => T extends B ? 1 : 0) extends (() => T extends A ? 1 : 0) 158 | ? true 159 | : false; 160 | 161 | export type DoesExtend = A extends B ? true : false; 162 | export type IsPlainObject = 163 | B.And< 164 | A.DoesExtend, 165 | B.Not> 166 | > 167 | 168 | export declare const test: (o: true) => void; 169 | export declare const tests: 170 | (ts: 171 | [ true?, true?, true?, true?, true?, 172 | true?, true?, true?, true?, true?, 173 | true?, true?, true?, true?, true?, 174 | ]) => void 175 | export declare const areEqual: (f?: (b?: A) => void) => A.AreEqual; 176 | 177 | } 178 | 179 | export namespace U { 180 | export type IsUnit = [U.Popped] extends [never] ? B.True : B.False 181 | export type Popped = U.Exclude> 182 | export type Exclude = A extends B ? never : A; 183 | export type Extract = A extends B ? A : never; 184 | 185 | export type Pop = 186 | ToIntersection void : never> extends (x: infer P) => void ? P : never 187 | 188 | export type ToIntersection = 189 | (T extends unknown ? (k: T) => void : never) extends ((k: infer I) => void) ? I : never; 190 | 191 | export type ToList = 192 | [T] extends [never] 193 | ? [] 194 | : [...U.ToList>, U.Pop] 195 | } 196 | 197 | export namespace B { 198 | export type True = true; 199 | export type False = false; 200 | export type Not = B extends true ? false : true; 201 | export type And = L.Every<[A, B]> 202 | } 203 | 204 | export namespace F { 205 | export type Called = T extends (...args: any[]) => infer R ? R : F; 206 | export type Parameters = T extends (...args: infer A) => any ? A : F; 207 | } 208 | 209 | export namespace S { 210 | export type String = string; 211 | export type Assert = A.Cast 212 | export type InferNarrowest = T extends string ? T : string 213 | export type IsLiteral = 214 | T extends A.String 215 | ? A.String extends T 216 | ? false 217 | : true 218 | : false; 219 | 220 | export type DoesStartWith = 221 | S extends X ? B.True : 222 | S extends `${S.Assert}${infer _}` ? B.True : 223 | B.False 224 | 225 | export type DoesContain = 226 | S extends X ? B.True : 227 | S extends `${infer _}${S.Assert}${infer __}` ? B.True : 228 | B.False 229 | 230 | export type Split = 231 | S extends `${infer H}${S.Assert}${infer T}` ? [H, ...Split] : [S] 232 | 233 | export type Commas> = 234 | A.Get extends 0 ? "" : 235 | A.Get extends 1 ? S.Assert> : 236 | `${L.Join, ",">} & ${S.Assert>}` 237 | 238 | export type Shifted = S extends `${infer _}${infer T}` ? T : ""; 239 | 240 | export type Replace = 241 | S extends `${infer P}${S.Assert}${infer S}` 242 | ? `${P}${S.Assert}${Replace}` 243 | : S; 244 | } 245 | 246 | export namespace N { 247 | export type Assert = A.Cast; 248 | export type PositiveIntegers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; 249 | export type NegativeIntegers = [-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20] 250 | export type PositiveIntegersUnshifted = L.Unshift 251 | export type PositiveIntegersUnshiftedTwice = L.Unshift 252 | export type NegativeIntegersUnshifted = L.Unshift 253 | export type NegativeIntegersUnshiftedTwice = L.Unshift 254 | 255 | export type IsWhole = B.Not> 256 | export type IsNegative = S.DoesStartWith, "-"> 257 | export type Negate = 258 | N extends 0 ? 0 : 259 | IsNegative extends true 260 | ? N.FromString>> 261 | : N.FromString<`-${N.Assert}`>; 262 | 263 | export type ToString = `${N.Assert}` 264 | export type FromString = 265 | S extends "0" ? 0 : 266 | S.DoesStartWith extends false 267 | ? { [I in keyof PositiveIntegersUnshifted]: 268 | I extends S ? PositiveIntegersUnshifted[I] : never 269 | }[keyof PositiveIntegersUnshifted] 270 | : { [I in keyof NegativeIntegersUnshifted]: 271 | `-${N.Assert}` extends S ? NegativeIntegersUnshifted[I] : never 272 | }[keyof NegativeIntegersUnshifted] 273 | 274 | 275 | export type Increment = 276 | IsNegative extends false 277 | ? A.Get 278 | : A.Get> 279 | 280 | export type Decrement = 281 | IsNegative extends false 282 | ? A.Get 283 | : A.Get> 284 | 285 | export type Add = 286 | B extends 0 ? A : 287 | A extends 0 ? B : 288 | [ IsNegative extends true ? "-" : "+" 289 | , IsNegative extends true ? "-" : "+" 290 | ] extends infer X 291 | ? X extends ["+", "+"] ? Add, Decrement> : 292 | X extends ["-", "-"] ? Add, Decrement> : 293 | X extends ["+", "-"] ? Add, Increment> : 294 | X extends ["-", "+"] ? Add, Decrement> : 295 | never : 296 | never 297 | 298 | export type Subtract = 299 | Add>; 300 | 301 | export type IsLessThan = 302 | [A, B] extends [0, 0] ? false : 303 | A extends 0 ? B.Not> : 304 | B extends 0 ? IsNegative : 305 | IsLessThan, 0> 306 | 307 | export type IsGreaterThanOrEqual = 308 | B.Not> 309 | 310 | export type IsGreaterThan = 311 | A extends B ? false : 312 | IsGreaterThanOrEqual 313 | } 314 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Behavior, UnknownActorRef } from "./Behavior"; 2 | import { A } from "./extras"; 3 | import Machine from "./Machine"; 4 | import MachineDefinition from "./MachineDefinition"; 5 | import MachineImplementations from "./MachineImplementations"; 6 | 7 | export declare const createMachine: { 8 | < D extends 9 | MachineDefinition.Of<{ 10 | Definition: D, 11 | Precomputed: P 12 | }> 13 | , P = MachineDefinition.Precomputed.Of 14 | > 15 | (definition: A.InferNarrowestObject): 16 | Machine.Of<{ Definition: D, Precomputed: P }> 17 | 18 | < D extends 19 | MachineDefinition.Of<{ 20 | Definition: D, 21 | Precomputed: P 22 | }> 23 | , I extends 24 | MachineImplementations.Of<{ 25 | Definition: D, 26 | Precomputed: P 27 | }> 28 | , P = MachineDefinition.Precomputed.Of 29 | > 30 | ( definition: A.InferNarrowestObject 31 | , implementations: I 32 | ): 33 | Machine.Of<{ Definition: D, Precomputed: P }> 34 | } 35 | 36 | 37 | export declare const createSchema: () => T 38 | export declare const send: Machine.SendAction.Creator; 39 | export declare const assign: Machine.AssignAction.Creator; 40 | 41 | export interface UnknownEvent 42 | { type: string 43 | } 44 | 45 | export declare namespace SCXML { 46 | export interface Event 47 | { name: string 48 | , type: "platform" | "internal" | "external" 49 | , sendid?: string 50 | , origin?: UnknownActorRef 51 | , origintype?: string 52 | , invokeid?: string 53 | , data: E 54 | , $$type: "scxml" 55 | } 56 | } 57 | 58 | export declare const createBehaviorFrom: { 59 | (x: PromiseLike): Behavior 60 | } 61 | -------------------------------------------------------------------------------- /src/universal.ts: -------------------------------------------------------------------------------- 1 | import { A, O, L, B, S, N } from "./extras"; 2 | import MachineDefinition from "./MachineDefinition"; 3 | 4 | export namespace ReferencePathString { 5 | 6 | export type RegionRoot< 7 | ReferencePathString, 8 | RootNode, 9 | 10 | NodePath = ReferencePathString.ToDefinitionPath, 11 | ParentNodePath = L.Popped>, 12 | ParentNode = A.Get, 13 | ParentReferencePathString = ReferencePathString.FromDefinitionPath 14 | > = 15 | A.Get extends "parallel" ? NodePath : 16 | A.Get extends 0 ? [] : 17 | RegionRoot 18 | 19 | /** is B descendant of A */ 20 | export type IsDescendant = 21 | A extends B ? false : 22 | S.DoesStartWith 23 | 24 | /** is B ancestor of A */ 25 | export type IsAncestor = 26 | A extends B ? false : 27 | IsDescendant 28 | 29 | export type Parent = 30 | [A] extends [never] ? never : 31 | A extends "" ? never : 32 | L.Join>, "."> 33 | 34 | export type Child, C = keyof A.Get> = 35 | [C] extends [never] ? never : 36 | C extends any ? Append : never 37 | 38 | export type FromDefinitionPath = 39 | A.Get extends 0 ? "" : 40 | S.Replace, "states.", ""> 41 | 42 | A.tests([ 43 | A.areEqual, "">(), 44 | A.areEqual, "a">(), 45 | A.areEqual, "a.b">() 46 | ]) 47 | 48 | export type ToDefinitionPath = 49 | ReferencePathString extends "" ? [] : 50 | ["states", ...S.Split, ".">] 51 | 52 | A.tests([ 53 | A.areEqual, []>(), 54 | A.areEqual, ["states", "a"]>(), 55 | A.areEqual, ["states", "a", "states", "b"]>(), 56 | ]) 57 | 58 | export type ToNode = 59 | A.Get> 60 | 61 | export namespace Tuple { 62 | export type MapToDefinitionPath = 63 | { [K in keyof T]: ToDefinitionPath> } 64 | 65 | export namespace Unresolved { 66 | export type ResolveWithStateNode< 67 | Global, 68 | TargetPathStringTuple, 69 | StateReferencePathString 70 | > = { 71 | [I in keyof TargetPathStringTuple]: 72 | ReferencePathString.Unresolved.ResolveWithStateNode< 73 | Global, 74 | TargetPathStringTuple[I], 75 | StateReferencePathString 76 | > 77 | } 78 | } 79 | } 80 | 81 | export namespace Unresolved { 82 | export type ResolveWithStateNode< 83 | Global, 84 | TargetPathString, 85 | StateReferencePathString, 86 | ParentStateReferencePathString = Parent, 87 | 88 | Definition = A.Get, 89 | SiblingStateIdentifier = 90 | StateReferencePathString extends "" ? never : 91 | keyof A.Get, "states">, 92 | ChildStateIdentifier = 93 | keyof A.Get, "states"> 94 | > = 95 | S.Assert< 96 | // id 97 | S.DoesStartWith extends B.True 98 | ? S.DoesContain extends B.True 99 | ? TargetPathString extends `#${infer Id}.${infer RestPath}` 100 | ? O.KeyWithValue< 101 | O.Assert>, 102 | Id 103 | > extends infer IdNodePath 104 | ? ReferencePathString.Append 105 | : never 106 | : never 107 | : O.KeyWithValue< 108 | O.Assert>, 109 | S.Shifted 110 | > : 111 | // relative children 112 | S.DoesStartWith extends B.True 113 | ? StateReferencePathString extends "" 114 | ? S.Shifted 115 | : `${S.Assert}${S.Assert}` : 116 | // children 117 | [ S.DoesStartWith 118 | , [ChildStateIdentifier] extends [never] ? B.False : B.True 119 | ] extends [B.True, B.True] 120 | ? ReferencePathString.Append : 121 | // sibling 122 | [ S.DoesStartWith 123 | , [SiblingStateIdentifier] extends [never] ? B.False : B.True 124 | ] extends [B.True, B.True] 125 | ? ReferencePathString.Append : 126 | never 127 | > 128 | 129 | export type OfIdWithRoot< 130 | StateNode, 131 | 132 | Id = A.Get, 133 | States = A.Get, 134 | IdPathString = `#${S.Assert}` 135 | > = 136 | | ( Id extends undefined ? never : 137 | | IdPathString 138 | | ReferencePathString.WithRoot 139 | ) 140 | | { [S in keyof States]: 141 | ReferencePathString.Unresolved.OfIdWithRoot 142 | }[keyof States] 143 | 144 | A.tests([ 145 | A.areEqual< 146 | ReferencePathString.Unresolved.OfIdWithRoot<{ id: "root", states: { 147 | a: { states: { a1: {}, a2: {} } }, 148 | b: { id: "b", states: { b1: {}, b2: {} } } 149 | } }> 150 | , | "#root" 151 | | "#root.a" 152 | | "#root.a.a1" 153 | | "#root.a.a2" 154 | | "#root.b" 155 | | "#root.b.b1" 156 | | "#root.b.b2" 157 | | "#b" 158 | | "#b.b1" 159 | | "#b.b2" 160 | >() 161 | ]) 162 | } 163 | 164 | 165 | 166 | export type WithRoot< 167 | StateNode, 168 | StateReferencePathString = "", 169 | Depth = 20, 170 | 171 | States = A.Get 172 | > = 173 | | ( StateReferencePathString extends "" ? never : 174 | StateReferencePathString extends "." ? never : 175 | StateReferencePathString 176 | ) 177 | | ( Depth extends 0 178 | ? never 179 | : { [S in keyof States]: 180 | WithRoot< 181 | States[S], 182 | ReferencePathString.Append, 183 | N.Decrement 184 | > 185 | }[keyof States] 186 | ) 187 | 188 | A.tests([ 189 | A.areEqual< 190 | ReferencePathString.WithRoot<{ states: { 191 | a: { states: { a1: {}, a2: {} } }, 192 | b: { states: { b1: {}, b2: {} } } 193 | } }> 194 | , | "a" 195 | | "a.a1" 196 | | "a.a2" 197 | | "b" 198 | | "b.b1" 199 | | "b.b2" 200 | >() 201 | ]) 202 | 203 | export type Append = 204 | A extends "" ? B : 205 | A extends "." ? `.${S.Assert}` : 206 | `${S.Assert}.${S.Assert}` 207 | } 208 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*"], 3 | "compilerOptions": { 4 | "target": "esnext", 5 | "module": "commonjs", 6 | "strict": true, 7 | "noImplicitAny": true, 8 | "esModuleInterop": true, 9 | "skipLibCheck": true, 10 | "outDir": "dist", 11 | "declaration": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | balanced-match@^1.0.0: 6 | version "1.0.2" 7 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 8 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 9 | 10 | brace-expansion@^1.1.7: 11 | version "1.1.11" 12 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 13 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 14 | dependencies: 15 | balanced-match "^1.0.0" 16 | concat-map "0.0.1" 17 | 18 | concat-map@0.0.1: 19 | version "0.0.1" 20 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 21 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 22 | 23 | fs.realpath@^1.0.0: 24 | version "1.0.0" 25 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 26 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 27 | 28 | function-bind@^1.1.1: 29 | version "1.1.1" 30 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 31 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 32 | 33 | glob@^7.0.0: 34 | version "7.1.7" 35 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" 36 | integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== 37 | dependencies: 38 | fs.realpath "^1.0.0" 39 | inflight "^1.0.4" 40 | inherits "2" 41 | minimatch "^3.0.4" 42 | once "^1.3.0" 43 | path-is-absolute "^1.0.0" 44 | 45 | has@^1.0.3: 46 | version "1.0.3" 47 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 48 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 49 | dependencies: 50 | function-bind "^1.1.1" 51 | 52 | inflight@^1.0.4: 53 | version "1.0.6" 54 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 55 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 56 | dependencies: 57 | once "^1.3.0" 58 | wrappy "1" 59 | 60 | inherits@2: 61 | version "2.0.4" 62 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 63 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 64 | 65 | interpret@^1.0.0: 66 | version "1.4.0" 67 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" 68 | integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== 69 | 70 | is-core-module@^2.2.0: 71 | version "2.6.0" 72 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" 73 | integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== 74 | dependencies: 75 | has "^1.0.3" 76 | 77 | minimatch@^3.0.4: 78 | version "3.0.4" 79 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 80 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 81 | dependencies: 82 | brace-expansion "^1.1.7" 83 | 84 | once@^1.3.0: 85 | version "1.4.0" 86 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 87 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 88 | dependencies: 89 | wrappy "1" 90 | 91 | path-is-absolute@^1.0.0: 92 | version "1.0.1" 93 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 94 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 95 | 96 | path-parse@^1.0.6: 97 | version "1.0.7" 98 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 99 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 100 | 101 | readline-sync@^1.4.10: 102 | version "1.4.10" 103 | resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" 104 | integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== 105 | 106 | rechoir@^0.6.2: 107 | version "0.6.2" 108 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" 109 | integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= 110 | dependencies: 111 | resolve "^1.1.6" 112 | 113 | resolve@^1.1.6: 114 | version "1.20.0" 115 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" 116 | integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== 117 | dependencies: 118 | is-core-module "^2.2.0" 119 | path-parse "^1.0.6" 120 | 121 | shelljs@^0.8.4: 122 | version "0.8.4" 123 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" 124 | integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== 125 | dependencies: 126 | glob "^7.0.0" 127 | interpret "^1.0.0" 128 | rechoir "^0.6.2" 129 | 130 | typescript@^4.4.0-beta: 131 | version "4.4.0-beta" 132 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.0-beta.tgz#a5b8a3a0d260fa5ce84daa3ab58f7102ad19a655" 133 | integrity sha512-qMxA8NzN3igwX8Mii7MXGNW+YeFAkUKyKg+x4F1CCFsO36LqISf1EXXSOLDuRIdGjdVvV53grRxfHjOW65YfMA== 134 | 135 | wrappy@1: 136 | version "1.0.2" 137 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 138 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 139 | --------------------------------------------------------------------------------