UNPKG

aws-ddk-core

Version:

The AWS DataOps Development Kit is an open source development framework for customers that build data workflows and modern data architecture on AWS.

152 lines (149 loc) 4.88 kB
'use strict'; const FOLD_FLOW = 'flow'; const FOLD_BLOCK = 'block'; const FOLD_QUOTED = 'quoted'; /** * Tries to keep input at up to `lineWidth` characters, splitting only on spaces * not followed by newlines or spaces unless `mode` is `'quoted'`. Lines are * terminated with `\n` and started with `indent`. */ function foldFlowLines(text, indent, mode = 'flow', { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) { if (!lineWidth || lineWidth < 0) return text; if (lineWidth < minContentWidth) minContentWidth = 0; const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length); if (text.length <= endStep) return text; const folds = []; const escapedFolds = {}; let end = lineWidth - indent.length; if (typeof indentAtStart === 'number') { if (indentAtStart > lineWidth - Math.max(2, minContentWidth)) folds.push(0); else end = lineWidth - indentAtStart; } let split = undefined; let prev = undefined; let overflow = false; let i = -1; let escStart = -1; let escEnd = -1; if (mode === FOLD_BLOCK) { i = consumeMoreIndentedLines(text, i, indent.length); if (i !== -1) end = i + endStep; } for (let ch; (ch = text[(i += 1)]);) { if (mode === FOLD_QUOTED && ch === '\\') { escStart = i; switch (text[i + 1]) { case 'x': i += 3; break; case 'u': i += 5; break; case 'U': i += 9; break; default: i += 1; } escEnd = i; } if (ch === '\n') { if (mode === FOLD_BLOCK) i = consumeMoreIndentedLines(text, i, indent.length); end = i + indent.length + endStep; split = undefined; } else { if (ch === ' ' && prev && prev !== ' ' && prev !== '\n' && prev !== '\t') { // space surrounded by non-space can be replaced with newline + indent const next = text[i + 1]; if (next && next !== ' ' && next !== '\n' && next !== '\t') split = i; } if (i >= end) { if (split) { folds.push(split); end = split + endStep; split = undefined; } else if (mode === FOLD_QUOTED) { // white-space collected at end may stretch past lineWidth while (prev === ' ' || prev === '\t') { prev = ch; ch = text[(i += 1)]; overflow = true; } // Account for newline escape, but don't break preceding escape const j = i > escEnd + 1 ? i - 2 : escStart - 1; // Bail out if lineWidth & minContentWidth are shorter than an escape string if (escapedFolds[j]) return text; folds.push(j); escapedFolds[j] = true; end = j + endStep; split = undefined; } else { overflow = true; } } } prev = ch; } if (overflow && onOverflow) onOverflow(); if (folds.length === 0) return text; if (onFold) onFold(); let res = text.slice(0, folds[0]); for (let i = 0; i < folds.length; ++i) { const fold = folds[i]; const end = folds[i + 1] || text.length; if (fold === 0) res = `\n${indent}${text.slice(0, end)}`; else { if (mode === FOLD_QUOTED && escapedFolds[fold]) res += `${text[fold]}\\`; res += `\n${indent}${text.slice(fold + 1, end)}`; } } return res; } /** * Presumes `i + 1` is at the start of a line * @returns index of last newline in more-indented block */ function consumeMoreIndentedLines(text, i, indent) { let end = i; let start = i + 1; let ch = text[start]; while (ch === ' ' || ch === '\t') { if (i < start + indent) { ch = text[++i]; } else { do { ch = text[++i]; } while (ch && ch !== '\n'); end = i; start = i + 1; ch = text[start]; } } return end; } exports.FOLD_BLOCK = FOLD_BLOCK; exports.FOLD_FLOW = FOLD_FLOW; exports.FOLD_QUOTED = FOLD_QUOTED; exports.foldFlowLines = foldFlowLines;