import * as React from 'react'; import AskPicklist from './AskPicklist'; import AskString, { AskStringType } from './AskString'; import Parser from './Parser'; import { AskerOptions, AskerParameter, Element, Xml, } from './types'; export const modifyXml = (xml: any, id: string[], modifier: (xml: Element) => any): Xml => { if (id.length > 1) { const idClone = id.slice(0); const first = idClone.splice(0, 1); xml[first[0]] = modifyXml(xml[first[0]], idClone, modifier); return xml; } xml[id[0]] = modifier(xml[id[0]]); return xml; }; const modifyElement = (xml: Xml, id: string[], modifier: (xml: Element[], arrayIndex: number) => Element[]) => { const idClone = id.slice(0); const arrayIndex = parseInt(idClone.splice(-1, 1)[0], 10); if (!isNaN(arrayIndex)) { return modifyXml(xml, idClone, (parent) => { if (Array.isArray(parent)) { return modifier(parent, arrayIndex); } throw new Error(`Failed to find node: ${id}`); }); } throw new Error(`Invalid id: ${id}`); }; export const getXmlNode = (xml: any, id: string[]): any => { if (id.length > 1) { const idClone = id.slice(0); const first = idClone.splice(0, 1); return getXmlNode(xml[first[0]], idClone); } return xml[id[0]]; }; export const deleteNode = (xml: Xml, id: string[]) => { const idClone = id.slice(0); const nodeKey = idClone.splice(-1, 1); return modifyXml(xml, idClone, (parent) => { if (Array.isArray(parent)) { parent.splice(parseInt(nodeKey[0], 10), 1); } else { delete (parent as any)[nodeKey[0]]; } return parent; }); }; export const updateNode = (xml: Xml, id: string[], value: string | boolean) => { return modifyXml(xml, id, () => { return value; }); }; export const newElementChild = (parameter: string) => async (xml: Xml, id: string[]): Promise => { const parser = new Parser(); const child = await parser.parseString(parameter); return modifyXml(xml, id, (parent) => { if (!parent.$$) { parent.$$ = []; } parent.$$.push(child[Object.keys(child)[0]]); return parent; }); }; export const newTextChild = (parameter: string) => async (xml: Xml, id: string[]): Promise => { return modifyXml(xml, id, (parent) => { if (!parent.$$) { parent.$$ = []; } parent.$$.push({ '#name': '__text__', _: parameter, }); return parent; }); }; const newElementSibling = async (xml: Xml, id: string[], sibling: string, indexDelta: number) => { const parser = new Parser(); const element = await parser.parseString(sibling); return modifyElement(xml, id, (parent, arrayIndex) => { parent.splice(arrayIndex + indexDelta, 0, element[Object.keys(element)[0]]); return parent; }); }; export const newElementBefore = (parameter: string) => (xml: Xml, id: string[]) => newElementSibling(xml, id, parameter, 0); export const newElementAfter = (parameter: string) => (xml: Xml, id: string[]) => newElementSibling(xml, id, parameter, 1); export const duplicateElement = (xml: Xml, id: string[]) => modifyElement(xml, id, (parent: Element[], arrayIndex: number) => { parent.splice(arrayIndex + 1, 0, Object.assign({}, parent[arrayIndex])); return parent; }); const swap = (arr: Element[], index1: number, index2: number) => { const temp = arr[index1]; arr[index1] = arr[index2]; arr[index2] = temp; }; export const moveElementUp = (xml: Xml, id: string[]) => modifyElement(xml, id, (parent: Element[], arrayIndex) => { if (arrayIndex > 0) { swap(parent, arrayIndex - 1, arrayIndex); } return parent; }); export const canMoveElementUp = (xml: Xml, id: string[]): boolean => { if (id.length > 0) { return parseInt(id[id.length - 1], 10) > 0; } return false; }; export const canMoveElementDown = (xml: Xml, id: string[]): boolean => { const idClone = id.slice(0); idClone.splice(-1, 1); const parent = getXmlNode(xml, idClone); return Array.isArray(parent) && id.length > 0 && parent.length - 1 > parseInt(id[id.length - 1], 10); }; export const moveElementDown = (xml: Xml, id: string[]) => modifyElement(xml, id, (parent: Element[], arrayIndex) => { if (arrayIndex < parent.length - 1) { swap(parent, arrayIndex + 1, arrayIndex); } return parent; }); export const newAttribute = (parameter: { name: string; value: string }) => (xml: Xml, id: string[]) => modifyXml(xml, id, (parent) => { if (!parent.$) { parent.$ = {}; } parent.$[parameter.name] = parameter.value; return parent; }); export const deleteElement = (xml: Xml, id: string[]) => { return deleteNode(xml, id); }; export const deleteAttribute = (xml: Xml, id: string[]) => deleteNode(xml, id); export const push = (arr: string[], ...newValues: string[]): string[] => { const clone = arr.slice(0); clone.push(...newValues); return clone; }; export const askPicklist = (parameter: AskerParameter) => (options: AskerOptions) => ( ); export const askString = (options: AskerOptions) => ( ); export const askLongString = (options: AskerOptions) => ( );