Skip to content

Commit

Permalink
setup arch
Browse files Browse the repository at this point in the history
  • Loading branch information
devanshj committed Aug 26, 2020
1 parent d94d053 commit d7aadd7
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
/scxml-xsd
/node_modules
8 changes: 5 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"cSpell.words": [
"scxml"
]
"cSpell.words": ["scxml"],
"editor.rulers": [
120
],
"typescript.tsdk": "node_modules\\typescript\\lib"
}
123 changes: 123 additions & 0 deletions MachineDefinition.StateNode.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Machine } from ".";
import { Test } from "ts-toolbelt"

let test1 = Machine({
initial: "a",
states: { a: {} },
});
let diagnosis1 = Machine.dignose({
initial: "a",
states: { a: {} },
})
Test.checks([
Test.check<typeof diagnosis1, "All good!", Test.Pass>()
])


let test2 = Machine({
// @ts-expect-error
initial: "b",
states: { a: {} }
})
let diagnosis2 = Machine.dignose({
initial: "b",
states: { a: {} }
})
Test.checks([
Test.check<typeof diagnosis2, [{
error: ["state", "b", "is not defined in states"],
at: ["initial"]
}], Test.Pass>()
])


let test3 = Machine({
initial: "a",
states: {
a: {
// @ts-expect-error
initial: "x",
states: {
b: {}
}
}
}
})
let diagnosis3 = Machine.dignose({
initial: "a",
states: {
a: {
initial: "x",
states: {
b: {}
}
}
}
})
Test.checks([
Test.check<typeof diagnosis3, [{
error: ["state", "x", "is not defined in states"];
at: ["states", "a", "initial"];
}], Test.Pass>()
])

// @ts-expect-error
let test4 = Machine({
states: { a: {} }
})
let diagnosis4 = Machine.dignose({
states: { a: {} }
})
Test.checks([
Test.check<typeof diagnosis4, [{
error: "initial state is required";
at: "root";
}], Test.Pass>()
])


let test5 = Machine({
initial: 1,
// @ts-expect-error
states: { 1: {} }
})
let diagnosis5 = Machine.dignose({
// @ts-ignore weird
initial: 1,
states: { 1: {} }
})
Test.checks([
Test.check<typeof diagnosis5, [{
error: "state identifiers should be only strings";
at: ["states"];
}], Test.Pass>()
])


// @ts-expect-error
let test6 = Machine({
type: "atomic",
initial: "a",
states: { a: {} }
})
let diagnosis6 = Machine.dignose({
type: "atomic",
initial: "a",
states: { a: {} }
})
Test.checks([
Test.check<typeof diagnosis6, [{
error: "The state node is atomic meaning no nested states, so can't have an initial property";
at: ["initial"];
}, {
error: "The state node is atomic meaning no nested states, so can't have an states property";
at: ["states"];
}], Test.Pass>()
])


let test7 = Machine({})
let diagnosis7 = Machine.dignose({})
Test.checks([
Test.check<typeof diagnosis7, "All good!", Test.Pass>()
])
206 changes: 206 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { O, A, U, L, B } from "ts-toolbelt";
import { P } from "Object/_api";

export declare const Machine: {
<D extends MachineDefinition.Of<D, {}>>(definition: D): MachineHandle.Of<D, {}>
<D extends MachineDefinition.Of<D, I>, I extends MachineDefinition.Implementations.Of<D, I>>(
definition: D,
implementations: I
): MachineHandle.Of<D, I>

dignose:
<D extends OE.DeepReadonly<D>>(defintion: D) => D.Show<MachineDefinition.Dignostics.Of<A.Cast<D, object>, {}>>
}

namespace MachineDefinition {
export type Of<Definition extends object, Implementations extends object> =
& StateNode.Of<Definition, Implementations, []>
& { context?: "TODO" };


export namespace Dignostics {
export type Of<Definition extends object, Implementations extends object> =
StateNode.Dignostics.Of<Definition, Implementations, []>
}

export namespace StateNode {
export type Of<
Definition extends object,
Implementations extends object,
Path extends string[],
Self extends object = A.Cast<O.Path<Definition, Path>, object>,
Initial = OE.At<Self, "initial">,
States = OE.At<Self, "states">,
Type = OE.At<Self, "type", "compound">,
Id = O.At<Self, "id">
> =
& (
| & { type?:
| "compound"
| "parallel"
| "final"
| "history"
, states?:
& { [StateIdentifier in U.Intersect<keyof O.At<Self, "states">, string>]:
StateNode.Of<Definition, Implementations, L.Concat<Path, ["states", StateIdentifier]>>
}
& { [_ in U.Filter<keyof O.At<Self, "states">, string>]?: never } // disallow non-string keys
}
& (B.Not<A.Equals<States, undefined>> extends B.True ? { initial: keyof States } : {})
| { type: "atomic"
, initial?: never
, states?: never
}
)
& { id?: string
}

export namespace Dignostics {
export type Of<
Definition extends object,
Implementations extends object,
Path extends PropertyKey[],
Self extends object = A.Cast<O.Path<Definition, Path>, object>
> =
[
...Initial<Definition, Implementations, Path>,
...(O.Has<Self, "states"> extends B.True
? States<Definition, Implementations, Path>
: []
)
];

export type Initial<
Definition extends object,
Implementations extends object,
Path extends PropertyKey[],
StateNode extends object = A.Cast<O.Path<Definition, Path>, object>,
Initial = OE.At<StateNode, "initial">,
States = OE.At<StateNode, "states">,
Type = OE.At<StateNode, "type", "compound">
> =
B.And<A.Equals<Initial, undefined>, B.Not<A.Equals<States, undefined>>> extends B.True
? [D.WithPath<Path, "initial state is required">] :
A.Equals<Initial, undefined> extends B.True
? [] :
A.Equals<Type, "atomic"> extends B.True
? [ D.WithPath<L.Append<Path, "initial">
, "The state node is atomic meaning no nested states, so can't have an initial property"> ] :
A.Equals<States, undefined> extends B.True
? [ D.WithPath<L.Append<Path, "initial">
, "There are no states defined hence can't have an initial state">] :
A.Contains<keyof States, number | symbol> extends B.True
? [] :
B.Not<A.Contains<Initial, keyof States>> extends B.True
? [ D.WithPath<L.Append<Path, "initial">
, ["state", O.At<StateNode, "initial">, "is not defined in states"]>] :
[];

export type States<
Definition extends object,
Implementations extends object,
Path extends PropertyKey[],
StateNode extends object = A.Cast<O.Path<Definition, Path>, object>,
States = OE.At<StateNode, "states">,
Type = OE.At<StateNode, "type", "compound">
> =
A.Equals<States, undefined> extends B.True ? [] :
A.Equals<States, {}> extends B.True ? [] :
[
...(
A.Contains<keyof States, number | symbol> extends B.True
? [D.WithPath<L.Append<Path, "states">, "state identifiers should be only strings">]
: []
),
...(
B.And<A.Equals<Type, "atomic">, B.Not<A.Equals<States, undefined>>> extends B.True
? [ D.WithPath<L.Append<Path, "states">
, "The state node is atomic meaning no nested states, so can't have an states property">]
: []
),
...(
A.Equals<States, {}> extends B.True
? []
: L.Flatten<U.ListOf<{
[S in keyof States]:
Of_<Definition, Implementations, A.Cast<L.Concat<Path, ["states", S]>, PropertyKey[]>>
}[keyof States]>>
),
];

export type Of_<
Definition extends object,
Implementations extends object,
Path extends PropertyKey[],
Self extends object = A.Cast<O.Path<Definition, Path>, object>
> =
[
...Initial<Definition, Implementations, Path>,
...(O.Has<Self, "states"> extends B.True
? States_<Definition, Implementations, Path>
: []
)
];

export type States_<
Definition extends object,
Implementations extends object,
Path extends PropertyKey[],
StateNode extends object = A.Cast<O.Path<Definition, Path>, object>,
States = OE.At<StateNode, "states">,
Type = OE.At<StateNode, "type", "compound">
> =
A.Equals<States, undefined> extends B.True ? [] :
A.Equals<States, {}> extends B.True ? [] :
[
...(
A.Contains<keyof States, number | symbol> extends B.True
? [D.WithPath<L.Append<Path, "states">, "state identifiers should be only strings">]
: []
),
...(
B.And<A.Equals<Type, "atomic">, B.Not<A.Equals<States, undefined>>> extends B.True
? [ D.WithPath<L.Append<Path, "states">
, "The state node is atomic meaning no nested states, so can't have an states property">]
: []
)
];
}
}

export namespace Implementations {
export type Of<Definition extends object, Implementations extends object> =
{} // TODO;
}
}

namespace D {
export type WithPath<P extends PropertyKey[], M> =
{ error: M, at: A.Equals<P, []> extends B.True ? "root" : P }

export type Show<T> =
A.Is<T, []> extends B.True
? "All good!"
: { [I in keyof T]:
T[I] extends { error: infer M, at: infer P }
? { error: M, at: P }
: never
};
}

namespace MachineHandle {
export type Of<D, I> = {} // TODO;
}

namespace OE {
export type At<T, K, F = undefined> =
K extends keyof T
? A.Equals<T[K], undefined> extends B.True
? F
: T[K]
: F;

export type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : string
}
}
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"devDependencies": {
"ts-toolbelt": "^8.0.3",
"typescript": "^4.0.0-beta"
}
}
9 changes: 9 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
}
}
13 changes: 13 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


ts-toolbelt@^8.0.3:
version "8.0.3"
resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-8.0.3.tgz#d4136466dfb731e8ad1f890303dae176beb27710"
integrity sha512-gxgyIVxf5B1ToZfA4cojFS3h2jPSxYWjvKehkuCVejMdnATeBdxY0tqCSr3okkwfSA3V5TBoWeYGVfLpMBfSMA==

typescript@^4.0.0-beta:
version "4.0.0-beta"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.0-beta.tgz#a6a65e430562131de69496a3ef5484346bc0cdd2"
integrity sha512-d3s/CogGtB2uPZ2Z8ts6eoUxxyB9PH3R27/UrzvpthuOvpCg4FWWnBbBiqJ0K4eu6eTlgmLiqQkh2dquReJweA==

0 comments on commit d7aadd7

Please sign in to comment.