action.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. /** create a fresh copy of the params which can be edited in place */
  19. createDefaultParams(a: A, globalCtx: unknown): P
  20. }
  21. namespace StateAction {
  22. export type Id = string & { '@type': 'transformer-id' }
  23. export type Params<T extends StateAction<any, any, any>> = T extends StateAction<any, any, infer P> ? P : unknown;
  24. export type ReType<T extends StateAction<any, any, any>> = T extends StateAction<any, infer T, any> ? T : unknown;
  25. export type ControlsFor<Props> = { [P in keyof Props]?: PD.Any }
  26. export interface Instance {
  27. action: StateAction,
  28. params: any
  29. }
  30. export interface ApplyParams<A extends StateObject = StateObject, P extends {} = {}> {
  31. ref: string,
  32. cell: StateObjectCell,
  33. a: A,
  34. state: State,
  35. params: P
  36. }
  37. export interface DefinitionBase<A extends StateObject = StateObject, T = any, P extends {} = {}> {
  38. /**
  39. * Apply an action that modifies the State specified in Params.
  40. */
  41. run(params: ApplyParams<A, P>, globalCtx: unknown): T | Task<T>,
  42. /** Test if the transform can be applied to a given node */
  43. isApplicable?(a: A, aTransform: StateTransform<StateTransformer<any, A, any>>, globalCtx: unknown): boolean
  44. }
  45. export interface Definition<A extends StateObject = StateObject, T = any, P extends {} = {}> extends DefinitionBase<A, T, P> {
  46. readonly from: StateObject.Ctor[],
  47. readonly display: { readonly name: string, readonly description?: string },
  48. params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any }
  49. }
  50. export function create<A extends StateObject, T, P extends {} = {}>(definition: Definition<A, T, P>): StateAction<A, T, P> {
  51. const action: StateAction<A, T, P> = {
  52. create(params) { return { action, params }; },
  53. id: UUID.create22(),
  54. definition,
  55. createDefaultParams(a, globalCtx) { return definition.params ? PD.getDefaultValues(definition.params(a, globalCtx)) : {} as any; }
  56. };
  57. return action;
  58. }
  59. export function fromTransformer<T extends StateTransformer>(transformer: T) {
  60. const def = transformer.definition;
  61. return create<StateTransformer.From<T>, void, StateTransformer.Params<T>>({
  62. from: def.from,
  63. display: def.display,
  64. params: def.params as StateTransformer.Definition<StateTransformer.From<T>, any, StateTransformer.Params<T>>['params'],
  65. isApplicable: transformer.definition.isApplicable
  66. ? (a, t, ctx) => transformer.definition.isApplicable!(a, ctx)
  67. : void 0,
  68. run({ cell, state, params }) {
  69. const tree = state.build().to(cell.transform.ref).apply(transformer, params);
  70. return state.updateTree(tree) as unknown as Task<void>;
  71. }
  72. });
  73. }
  74. export namespace Builder {
  75. export interface Type<A extends StateObject.Ctor, P extends {}> {
  76. from?: A | A[],
  77. params?: PD.For<P> | ((a: StateObject.From<A>, globalCtx: any) => PD.For<P>),
  78. display?: string | { name: string, description?: string },
  79. isApplicable?: DefinitionBase<StateObject.From<A>, any, P>['isApplicable']
  80. }
  81. export interface Root {
  82. <A extends StateObject.Ctor, P extends { }>(info: Type<A, P>): Define<StateObject.From<A>, PD.Normalize<P>>
  83. }
  84. export interface Define<A extends StateObject, P extends {}> {
  85. <T>(def: DefinitionBase<A, T, P> | DefinitionBase<A, T, P>['run']): StateAction<A, T, P>,
  86. }
  87. function root(info: Type<any, any>): Define<any, any> {
  88. return def => create({
  89. from: info.from instanceof Array
  90. ? info.from
  91. : !!info.from ? [info.from] : [],
  92. display: typeof info.display === 'string'
  93. ? { name: info.display }
  94. : !!info.display
  95. ? info.display
  96. : { name: 'Unnamed State Action' },
  97. params: typeof info.params === 'object'
  98. ? () => info.params as any
  99. : !!info.params
  100. ? info.params as any
  101. : void 0,
  102. isApplicable: info.isApplicable,
  103. ...(typeof def === 'function'
  104. ? { run: def }
  105. : def)
  106. });
  107. }
  108. export const build: Root = (info: any) => root(info);
  109. }
  110. export const build = Builder.build;
  111. }