/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal */ import { Task } from 'mol-task'; import { UUID } from 'mol-util'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { StateObject, StateObjectCell } from './object'; import { State } from './state'; import { StateTransformer } from './transformer'; import { StateTransform } from './transform'; export { StateAction }; interface StateAction { create(params: P): StateAction.Instance, readonly id: UUID, readonly definition: StateAction.Definition } namespace StateAction { export type Id = string & { '@type': 'transformer-id' } export type Params> = T extends StateAction ? P : unknown; export type ReType> = T extends StateAction ? T : unknown; export type ControlsFor = { [P in keyof Props]?: PD.Any } export interface Instance { action: StateAction, params: any } export interface ApplyParams { ref: string, cell: StateObjectCell, a: A, state: State, params: P } export interface DefinitionBase { /** * Apply an action that modifies the State specified in Params. */ run(params: ApplyParams, globalCtx: unknown): T | Task, /** Test if the transform can be applied to a given node */ isApplicable?(a: A, aTransform: StateTransform, globalCtx: unknown): boolean } export interface Definition extends DefinitionBase { readonly from: StateObject.Ctor[], readonly display: { readonly name: string, readonly description?: string }, params?(a: A, globalCtx: unknown): { [K in keyof P]: PD.Any } } export function create(definition: Definition): StateAction { const action: StateAction = { create(params) { return { action, params }; }, id: UUID.create22(), definition }; return action; } export function fromTransformer(transformer: T) { const def = transformer.definition; return create, void, StateTransformer.Params>({ from: def.from, display: def.display, params: def.params as StateTransformer.Definition, any, StateTransformer.Params>['params'], isApplicable: transformer.definition.isApplicable ? (a, t, ctx) => transformer.definition.isApplicable!(a, ctx) : void 0, run({ cell, state, params }) { const tree = state.build().to(cell.transform.ref).apply(transformer, params); return state.updateTree(tree) as Task; } }) } export namespace Builder { export interface Type { from?: A | A[], params?: PD.For

| ((a: StateObject.From, globalCtx: any) => PD.For

), display?: string | { name: string, description?: string }, isApplicable?: DefinitionBase, any, P>['isApplicable'] } export interface Root { (info: Type): Define, PD.Normalize

> } export interface Define { (def: DefinitionBase | DefinitionBase['run']): StateAction, } function root(info: Type): Define { return def => create({ from: info.from instanceof Array ? info.from : !!info.from ? [info.from] : [], display: typeof info.display === 'string' ? { name: info.display } : !!info.display ? info.display : { name: 'Unnamed State Action' }, params: typeof info.params === 'object' ? () => info.params as any : !!info.params ? info.params as any : void 0, isApplicable: info.isApplicable, ...(typeof def === 'function' ? { run: def } : def) }); } export const build: Root = (info: any) => root(info); } export const build = Builder.build; }