UNPKG

@atlaskit/adf-utils

Version:

Set of utilities to traverse, modify and create ADF documents.

135 lines (132 loc) 5.43 kB
import { fg } from '@atlaskit/platform-feature-flags'; const DUMMY_TEXT = `Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua Ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur Excepteur sint occaecat cupidatat non proident sunt in culpa qui officia deserunt mollit anim id est laborum`; const DUMMY_DIGITS = ['2', '7', '4', '3', '5', '9', '1', '8', '0', '5']; const BYPASS_ATTR_LIST = { bodiedExtension: ['extensionKey', 'extensionType', 'layout'], codeBlock: ['language'], decisionItem: ['state'], embedCard: ['layout', 'originalHeight', 'originalWidth', 'width'], extension: ['extensionKey', 'extensionType', 'layout', 'type'], heading: ['level'], inlineExtension: ['extensionKey', 'extensionType', 'layout'], layoutColumn: ['width'], media: ['__fileMimeType', '__fileSize', 'height', 'width', 'type'], mediaSingle: ['layout', 'width', 'widthType'], orderedList: ['order'], panel: ['panelType'], status: ['color', 'style'], table: ['isNumberColumnEnabled', 'layout', 'width'], tableCell: ['background', 'colspan', 'colwidth', 'defaultMarks', 'rowspan'], tableHeader: ['background', 'colspan', 'colwidth', 'defaultMarks', 'rowspan'], tableRow: ['defaultMarks'], taskItem: ['state'], blockTaskItem: ['state'] }; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any const fromEntries = iterable => { return [...iterable].reduce((obj, [key, val]) => { obj[key] = val; return obj; }, {}); }; const scrubNum = (val, start = 0) => { return parseInt(val.toString().split('').map((_, index) => { const base = start + index; const len = DUMMY_DIGITS.length - 1; return DUMMY_DIGITS[base % len]; }).join(''), 10); }; export const scrubStr = (val, offset = 0) => { const base = DUMMY_TEXT.repeat(Math.ceil((offset + val.length) / DUMMY_TEXT.length)); // using [...val] splits emoji character pairs correctly, compared to // something like "".split('') return [...val].map((char, index, chars) => { // @ts-ignore - TS1501 TypeScript 5.9.2 upgrade if (/^\p{Nd}$/u.test(char)) { // Decimal digits return scrubNum(parseInt(char, 10), index).toString(); // @ts-ignore - TS1501 TypeScript 5.9.2 upgrade } else if (/^\p{So}$/u.test(char)) { var _chars; // Emoji return ((_chars = chars[index - 1]) === null || _chars === void 0 ? void 0 : _chars.codePointAt(0)) === 8205 ? '' : '⭐️'; // @ts-ignore - TS1501 TypeScript 5.9.2 upgrade } else if (/^\p{Sc}$/u.test(char)) { // Currency return '$'; // @ts-ignore - TS1501 TypeScript 5.9.2 upgrade } else if (/^[\p{P}\p{Z}\p{C}]$/u.test(char)) { // Punctuation, Seperators, Control return char; // @ts-ignore - TS1501 TypeScript 5.9.2 upgrade } else if (char.codePointAt(0) === 65039 && /^\p{So}$/u.test(chars[index - 1])) { // Ingore compound emoji control char return ''; } else { // Everything else // modulo to ensure wrapping occurs around base string (no OOB access) const correction = base[offset % base.length] === ' ' ? 1 : 0; const raw = fg('platform_adf-utils_fix-dummy-text-index-oob') ? base[(offset + correction) % base.length] : base[offset + correction]; const isLower = char.toLowerCase() === char; const result = isLower ? raw.toLowerCase() : raw.toUpperCase(); offset += 1 + correction; return result; } }).join(''); }; export const scrubLink = (marks, { valueReplacements }) => { return marks.map(mark => { if (mark.type === 'link' && mark.attrs.href) { return { ...mark, attrs: { ...mark.attrs, href: valueReplacements.href(mark.attrs.href) } }; } return mark; }); }; const scrubObj = (nodeType, attrsObj) => { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any const entries = Object.entries(attrsObj).map(([key, value]) => { var _BYPASS_ATTR_LIST$nod; return (_BYPASS_ATTR_LIST$nod = BYPASS_ATTR_LIST[nodeType]) !== null && _BYPASS_ATTR_LIST$nod !== void 0 && _BYPASS_ATTR_LIST$nod.includes(key) ? [key, value] : [key, scrubAttrs(nodeType, value)]; }); return fromEntries(entries); }; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any export const scrubAttrs = (nodeType, attrs, offset = 0) => { if (typeof attrs === 'number') { return scrubNum(attrs, offset); } if (typeof attrs === 'string') { return scrubStr(attrs, offset); } if (typeof attrs === 'boolean') { return attrs; } if (!attrs) { return attrs; } const attrsObj = attrs; if (attrsObj && attrsObj.constructor === Object && Object.keys(attrsObj).length === 0) { return {}; } if (typeof attrsObj === 'object' && !Array.isArray(attrsObj)) { return scrubObj(nodeType, attrsObj); } if (Array.isArray(attrsObj)) { return attrsObj.map(el => { return typeof el === 'object' ? scrubObj(nodeType, el) : scrubAttrs(nodeType, el); }); } throw new TypeError(`scrubAttrs: encountered unsupported attributes type "${typeof attrsObj}" of value ${JSON.stringify(attrsObj)}`); };