action.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { Task } from 'mol-task';
  7. import { UUID } from 'mol-util';
  8. import { ParamDefinition as PD } from 'mol-util/param-definition';
  9. import { StateObject, StateObjectCell } from './object';
  10. import { State } from './state';
  11. import { StateTransformer } from './transformer';
  12. import { StateTransform } from './transform';
  13. export { StateAction };
  14. interface StateAction<A extends StateObject = StateObject, T = any, P extends {} = {}> {
  15. create(params: P): StateAction.Instance,
  16. readonly id: UUID,
  17. readonly definition: StateAction.Definition<A, T, P>
  18. }
  19. namespace StateAction {
  20. export type Id = string & { '@type': 'transformer-id' }
  21. export type Params<T extends StateAction<any, any, any>> = T extends StateAction<any, any, infer P> ? P : unknown;
  22. export type ReType<T extends StateAction<any, any, any>> = T extends StateAction<any, infer T, any> ? T : unknown;
  23. export type ControlsFor<Props> = { [P in keyof Props]?: PD.Any }
  24. export interface Instance {
  25. action: StateAction,
  26. params: any
  27. }
  28. export interface ApplyParams<A extends StateObject = StateObject, P extends {} = {}> {
  29. ref: string,
  30. cell: StateObjectCell,
  31. a: A,
  32. state: State,
  33. params: P
  34. }
  35. export interface DefinitionBase<A extends StateObject = StateObject, T = any, P extends {} = {}> {
  36. /**
  37. * Apply an action that modifies the State specified in Params.
  38. */
  39. run(params: ApplyParams<A, P>, globalCtx: unknown): T | Task<T>,
  40. /** Test if the transform can be applied to a given node */
  41. isApplicable?(a: A, aTransform: StateTransform<any, A, any>, globalCtx: unknown): boolean
  42. }
  43. export interface Definition<A extends StateObject = StateObject, T = any, P extends {} = {}> extends DefinitionBase<A, T, P> {
  44. readonly from: StateObject.Ctor[],
  45. readonly display: { readonly name: string, readonly description?: string },
  46. params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any }
  47. }
  48. export function create<A extends StateObject, T, P extends {} = {}>(definition: Definition<A, T, P>): StateAction<A, T, P> {
  49. const action: StateAction<A, T, P> = {
  50. create(params) { return { action, params }; },
  51. id: UUID.create22(),
  52. definition
  53. };
  54. return action;
  55. }
  56. export function fromTransformer<T extends StateTransformer>(transformer: T) {
  57. const def = transformer.definition;
  58. return create<StateTransformer.From<T>, void, StateTransformer.Params<T>>({
  59. from: def.from,
  60. display: def.display,
  61. params: def.params as StateTransformer.Definition<StateTransformer.From<T>, any, StateTransformer.Params<T>>['params'],
  62. isApplicable: transformer.definition.isApplicable
  63. ? (a, t, ctx) => transformer.definition.isApplicable!(a, ctx)
  64. : void 0,
  65. run({ cell, state, params }) {
  66. const tree = state.build().to(cell.transform.ref).apply(transformer, params);
  67. return state.updateTree(tree) as Task<void>;
  68. }
  69. })
  70. }
  71. export namespace Builder {
  72. export interface Type<A extends StateObject.Ctor, P extends { }> {
  73. from?: A | A[],
  74. params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>),
  75. display?: string | { name: string, description?: string },
  76. isApplicable?: DefinitionBase<StateObject.From<A>, any, P>['isApplicable']
  77. }
  78. export interface Root {
  79. <A extends StateObject.Ctor, P extends { }>(info: Type<A, P>): Define<StateObject.From<A>, PD.Normalize<P>>
  80. }
  81. export interface Define<A extends StateObject, P> {
  82. <T>(def: DefinitionBase<A, T, P> | DefinitionBase<A, T, P>['run']): StateAction<A, T, P>,
  83. }
  84. function root(info: Type<any, any>): Define<any, any> {
  85. return def => create({
  86. from: info.from instanceof Array
  87. ? info.from
  88. : !!info.from ? [info.from] : [],
  89. display: typeof info.display === 'string'
  90. ? { name: info.display }
  91. : !!info.display
  92. ? info.display
  93. : { name: 'Unnamed State Action' },
  94. params: typeof info.params === 'object'
  95. ? () => info.params as any
  96. : !!info.params
  97. ? info.params as any
  98. : void 0,
  99. isApplicable: info.isApplicable,
  100. ...(typeof def === 'function'
  101. ? { run: def }
  102. : def)
  103. });
  104. }
  105. export const build: Root = (info: any) => root(info);
  106. }
  107. export const build = Builder.build;
  108. }