formily/next/src/shared.ts (102 lines of code) (raw):

import { TreeNode, Engine } from '@designable/core' export type ComponentNameMatcher = | string | string[] | ((name: string, node: TreeNode, context?: any) => boolean) export const matchComponent = ( node: TreeNode, name: ComponentNameMatcher, context?: any ) => { if (name === '*') return true const componentName = node?.props?.['x-component'] if (typeof name === 'function') return name(componentName || '', node, context) if (Array.isArray(name)) return name.includes(componentName) return componentName === name } export const matchChildComponent = ( node: TreeNode, name: ComponentNameMatcher, context?: any ) => { if (name === '*') return true const componentName = node?.props?.['x-component'] if (!componentName) return false if (typeof name === 'function') return name(componentName || '', node, context) if (Array.isArray(name)) return name.includes(componentName) return componentName.indexOf(`${name}.`) > -1 } export const includesComponent = ( node: TreeNode, names: ComponentNameMatcher[], target?: TreeNode ) => { return names.some((name) => matchComponent(node, name, target)) } export const queryNodesByComponentPath = ( node: TreeNode, path: ComponentNameMatcher[] ): TreeNode[] => { if (path?.length === 0) return [] if (path?.length === 1) { if (matchComponent(node, path[0])) { return [node] } } return matchComponent(node, path[0]) ? node.children.reduce((buf, child) => { return buf.concat(queryNodesByComponentPath(child, path.slice(1))) }, []) : [] } export const findNodeByComponentPath = ( node: TreeNode, path: ComponentNameMatcher[] ): TreeNode => { if (path?.length === 0) return if (path?.length === 1) { if (matchComponent(node, path[0])) { return node } } if (matchComponent(node, path[0])) { for (let i = 0; i < node.children.length; i++) { const next = findNodeByComponentPath(node.children[i], path.slice(1)) if (next) { return next } } } } export const hasNodeByComponentPath = ( node: TreeNode, path: ComponentNameMatcher[] ) => !!findNodeByComponentPath(node, path) export const matchArrayItemsNode = (node: TreeNode) => { return ( node?.parent?.props?.type === 'array' && node?.parent?.children?.[0] === node ) } export const createNodeId = (designer: Engine, id: string) => { return { [designer.props.nodeIdAttrName]: id, } } export const createEnsureTypeItemsNode = (type: string) => (node: TreeNode) => { const objectNode = node.children.find((child) => child.props['type'] === type) if (objectNode) { return objectNode } else { const newObjectNode = new TreeNode({ componentName: 'Field', props: { type, }, }) node.prepend(newObjectNode) return newObjectNode } }