state.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import { State, StateObject, StateTree, Transformer } from 'mol-state';
  2. import { Task } from 'mol-task';
  3. import * as util from 'util';
  4. export type TypeClass = 'root' | 'shape' | 'prop'
  5. export interface ObjProps { label: string }
  6. export interface TypeInfo { name: string, class: TypeClass }
  7. const _obj = StateObject.factory<TypeInfo, ObjProps>()
  8. const _transform = Transformer.factory('test');
  9. export class Root extends _obj('root', { name: 'Root', class: 'root' }) { }
  10. export class Square extends _obj<{ a: number }>('square', { name: 'Square', class: 'shape' }) { }
  11. export class Circle extends _obj<{ r: number }>('circle', { name: 'Circle', class: 'shape' }) { }
  12. export class Area extends _obj<{ volume: number }>('volume', { name: 'Volume', class: 'prop' }) { }
  13. export const CreateSquare = _transform<Root, Square, { a: number }>({
  14. name: 'create-square',
  15. from: [Root],
  16. to: [Square],
  17. apply({ params: p }) {
  18. return new Square({ label: `Square a=${p.a}` }, p);
  19. },
  20. update({ b, newParams: p }) {
  21. b.props.label = `Square a=${p.a}`
  22. b.data.a = p.a;
  23. return Transformer.UpdateResult.Updated;
  24. }
  25. });
  26. export const CreateCircle = _transform<Root, Circle, { r: number }>({
  27. name: 'create-circle',
  28. from: [Root],
  29. to: [Square],
  30. apply({ params: p }) {
  31. return new Circle({ label: `Circle r=${p.r}` }, p);
  32. },
  33. update({ b, newParams: p }) {
  34. b.props.label = `Circle r=${p.r}`
  35. b.data.r = p.r;
  36. return Transformer.UpdateResult.Updated;
  37. }
  38. });
  39. export const CaclArea = _transform<Square | Circle, Area, {}>({
  40. name: 'calc-area',
  41. from: [Square, Circle],
  42. to: [Area],
  43. apply({ a }) {
  44. if (a instanceof Square) return new Area({ label: 'Area' }, { volume: a.data.a * a.data.a });
  45. else if (a instanceof Circle) return new Area({ label: 'Area' }, { volume: a.data.r * a.data.r * Math.PI });
  46. throw new Error('Unknown object type.');
  47. },
  48. update({ a, b }) {
  49. if (a instanceof Square) b.data.volume = a.data.a * a.data.a;
  50. else if (a instanceof Circle) b.data.volume = a.data.r * a.data.r * Math.PI;
  51. else throw new Error('Unknown object type.');
  52. return Transformer.UpdateResult.Updated;
  53. }
  54. });
  55. export async function runTask<A>(t: A | Task<A>): Promise<A> {
  56. if ((t as any).run) return await (t as Task<A>).run();
  57. return t as A;
  58. }
  59. function hookEvents(state: State) {
  60. state.context.events.object.created.subscribe(e => console.log('created:', e.ref));
  61. state.context.events.object.removed.subscribe(e => console.log('removed:', e.ref));
  62. state.context.events.object.replaced.subscribe(e => console.log('replaced:', e.ref));
  63. state.context.events.object.stateChanged.subscribe(e => console.log('stateChanged:', e.ref,
  64. StateObject.StateType[state.objects.get(e.ref)!.state]));
  65. state.context.events.object.updated.subscribe(e => console.log('updated:', e.ref));
  66. }
  67. export async function testState() {
  68. const state = State.create();
  69. hookEvents(state);
  70. const tree = state.tree;
  71. const builder = StateTree.build(tree);
  72. builder.toRoot<Root>()
  73. .apply(CreateSquare, { a: 10 }, { ref: 'square' })
  74. .apply(CaclArea);
  75. const tree1 = builder.getTree();
  76. printTTree(tree1);
  77. const tree2 = StateTree.updateParams<typeof CreateSquare>(tree1, 'square', { a: 15 });
  78. printTTree(tree1);
  79. printTTree(tree2);
  80. const state1 = await State.update(state, tree1).run();
  81. console.log('----------------');
  82. console.log(util.inspect(state1.objects, true, 3, true));
  83. console.log('----------------');
  84. const jsonString = JSON.stringify(StateTree.toJSON(tree2), null, 2);
  85. const jsonData = JSON.parse(jsonString);
  86. printTTree(tree2);
  87. console.log(jsonString);
  88. const treeFromJson = StateTree.fromJSON(jsonData);
  89. printTTree(treeFromJson);
  90. console.log('----------------');
  91. const state2 = await State.update(state1, treeFromJson).run();
  92. console.log(util.inspect(state2.objects, true, 3, true));
  93. }
  94. testState();
  95. //test();
  96. export function printTTree(tree: StateTree) {
  97. let lines: string[] = [];
  98. function print(offset: string, ref: any) {
  99. const t = tree.nodes.get(ref)!;
  100. const tr = t.value;
  101. const name = tr.transformer.id;
  102. lines.push(`${offset}|_ (${ref}) ${name} ${tr.params ? JSON.stringify(tr.params) : ''}, v${t.value.version}`);
  103. offset += ' ';
  104. t.children.forEach(c => print(offset, c!));
  105. }
  106. print('', tree.rootRef);
  107. console.log(lines.join('\n'));
  108. }