UNPKG

@onereach/channel-transformer

Version:

Convert data model between different channels (Slack, Microsoft Teams, Generic...)

274 lines (235 loc) 7.8 kB
import { IGenericSection, IGenericText, IGenericFields } from '../../../generic/types'; import { ISlackSection, ISlackActions, ISlackInput, ISlackImage } from '../../types'; import { getMethods } from '../methods'; function transformSection ({ props, children }: IGenericSection): ISlackActions; function transformSection ({ props, children }: IGenericSection): Array<ISlackSection|ISlackActions>; function transformSection ({ props, children }: IGenericSection) { const flattenedSections = flattenSection(props, children); const result = flattenedSections.reduce((acc, item) => { const { type, props, children } = item; const itemType = props?.slack?.type || type; if (itemType === 'input' && children.length === 1) { // if no label => transform as actions return acc.concat(getMethods('inputWrapper')({ props, children })); } else if (itemType === 'context' || itemType === 'header') { return acc.concat(getMethods(itemType)({ props, children })); } else if (itemType === 'actions') { return acc.concat(transformActions({ props, children })); } else if (itemType === 'fields') { const result = getMethods(itemType)({ props, children }); return Array.isArray(result) ? acc.concat({ type: 'section', fields: result }) : acc.concat(result); } else { return acc.concat(transformRegularSection({ props, children })); } }, []); const block_id = props?.slack?.block_id; if (block_id && result[0] && !result[0].block_id) { result[0].block_id = block_id; } return result; } // HELPER FUNCTIONS function flat (arr) { if (!Array.isArray(arr)) return arr; return arr.reduce((acc, item) => { return acc.concat(flat(item)); }, []); } function flattenSection (props, children) { const isSection = item => { const sectionTypes = ['section', 'context', 'header']; return sectionTypes.includes(item.type); }; const result = []; let section = { props, children: [] }; children.forEach(item => { if (isSection(item)) { if (section.children.length > 0) { result.push(section); result.push(item); section = { props: { type: 'section' }, children: [] }; } else { result.push(item); } } else { section.children.push(item); } }); if (section.children.length > 0) { result.push(section); } return result; } function transformActions ({ props, children }): ISlackActions { const section: ISlackActions = { type: 'actions', elements: children.map(child => getMethods(child.type)(child)) }; const block_id = props?.slack?.block_id; if (block_id) section.block_id = block_id; return section; } function isInteractiveType (type: string): boolean { return [ 'button', 'checkbox', 'datePicker', 'radio', 'select', 'timePicker' ].includes(type); } function transformRegularSection ({ props, children }): Array<ISlackSection|ISlackActions|ISlackInput> { const additionalSections: Array<ISlackSection|ISlackActions> = []; const block_id = props?.slack?.block_id; const result: Array<ISlackSection|ISlackActions|ISlackInput> = []; let res; for (let i = 0; i < children.length; i++) { const el = children[i]; if (el.type === 'text') { if (!res) { res = { type: 'section' } as ISlackSection; } if (res.type === 'section' && res.text || res.type !== 'section') { result.push(res); res = { type: 'section' }; } res.text = getMethods(el.type)(el); } else if (isInteractiveType(el.type) || el.type === 'input') { const slackElement = getMethods(el.type)(el); if (slackElement.type === 'input') { res && result.push(res); result.push(slackElement); res = null; } else if (res?.type === 'section' && !res.accessory) { res.accessory = slackElement; } else { if (res?.type === 'section') { result.push(res); res = { type: 'actions', elements: [] } as ISlackActions; res.elements.push(slackElement); } else if (res?.type === 'actions') { res.elements.push(slackElement); } else { res = { type: 'actions', elements: [slackElement] } as ISlackActions; } } } else if (el.type === 'image') { const slackElement = getMethods(el.type)(el); if (!res) { result.push(slackElement); } else if (res?.type === 'section' && res.accessory || res?.type !== 'section') { result.push(res, slackElement); res = null; } else { delete slackElement.title; res.accessory = slackElement; } } else if (el.type === 'section') { const convertedSection = getMethods(el.type)(el); result.push(...convertedSection); } } if (res) { result.push(res); } if (block_id && result[0]) { result[0].block_id = block_id; } // console.log('transformRegularSection', { children, result }); return result; const textObjects: Array<IGenericText> = children.filter(item => item.type === 'text'); // TODO: implement fields converting const fields: Array<IGenericFields> = children.filter( item => item.type === 'fields' || item.props?.slack?.type === 'fields' ); const elements = children.filter( item => !['text', 'fields'].includes(item.type) && !['text', 'fields'].includes(item.props?.slack?.type) ); if (textObjects.length) { res.text = concatSectionTextObjects(textObjects); } if (fields.length) { const transformed = transformFieldElements(fields); if (transformed.fields) { res.fields = transformed.fields; } additionalSections.push(...transformed.sections); } if (elements.length === 1) { res.accessory = getMethods(elements[0].type)(elements[0]); } else if (elements.length > 1) { const actSection: ISlackActions = { type: 'actions', elements: children.map(child => getMethods(child.type)(child)) }; additionalSections.push(actSection); } if (!res.text && !res.fields && !res.accessory) { return flat(additionalSections); } return [res, ...flat(additionalSections)]; } function concatSectionTextObjects (children, init=null) { const transformed = children.map(item => getMethods(item.type)(item)); // concatenate values from all text objects const initial = Object.assign({ type: 'mrkdwn' }, transformed[0], { text: '' }, init); return transformed .reduce( (acc, item) => { if(acc.type === 'plain_text' && item.type === 'mrkdwn') { delete acc.emoji; acc.type = 'mrkdwn'; } acc.text = `${acc.text} ${item.text}`.trim(); return acc; }, initial ); } function transformFieldElements (elements) { const fields = Array.isArray(elements) ? [...elements] : [elements]; const result = { fields: null, sections: [] }; const slackFields = fields.map(item => getMethods(item.type)(item)); if ( Array.isArray(slackFields[0]) && ['mrkdwn', 'plain_text'].includes(slackFields[0][0].type) ) { result.fields = slackFields[0]; if (slackFields.length > 1) { // create a new section for each additional field result.sections.push( ...slackFields.slice(1).map(item => { const section: ISlackSection = { type: 'section', fields: item }; return section; }) ); } } else { result.sections.push(...slackFields); } return result; } export { transformSection };