UNPKG

forest-cli

Version:

The Lumberjacks' toolbelt is the Forest CLI which makes easy to manage your back office application directly from the terminal.

316 lines 31.5 kB
/** * Wide role-centric CSV helpers for `forest roles:export` / `forest roles:apply`. * PRD-535. */ const CRUD_SUFFIXES = ['browse', 'read', 'add', 'edit', 'delete', 'export']; const SMART_ACTION_SUFFIXES = [ 'trigger', 'approvalRequired', 'userApproval', 'selfApproval', 'hasConditions', ]; const SMART_ACTION_WRITE_SUFFIXES = ['trigger', 'approvalRequired', 'userApproval', 'selfApproval']; const CRUD_FIELD_MAP = { browse: 'browseEnabled', read: 'readEnabled', add: 'addEnabled', edit: 'editEnabled', delete: 'deleteEnabled', export: 'exportEnabled', }; const SA_FIELD_MAP = { trigger: 'triggerEnabled', approvalRequired: 'approvalRequired', userApproval: 'userApprovalEnabled', selfApproval: 'selfApprovalEnabled', }; // Derived from the maps so the diff field lists can't drift from the column maps. const CRUD_FIELDS = Object.values(CRUD_FIELD_MAP); const SA_FIELDS = Object.values(SA_FIELD_MAP); // --------------------------------------------------------------------------- // Internal CSV helpers (no external library) // --------------------------------------------------------------------------- function escapeCsv(value) { const str = String(value == null ? '' : value); if (str.includes(',') || str.includes('"') || str.includes('\n')) { return `"${str.replace(/"/g, '""')}"`; } return str; } function parseCsvCharacters(line) { return line.split('').reduce((acc, ch, i) => { if (acc.inQuotes) { // Consume the second quote of an escaped pair (`""`) before treating // `"` as a section delimiter, otherwise it closes the quotes early. if (acc.skipNext) return { ...acc, skipNext: false }; if (ch === '"') { if (line[i + 1] === '"') { return { ...acc, current: `${acc.current}"`, skipNext: true }; } return { ...acc, inQuotes: false }; } return { ...acc, current: acc.current + ch }; } if (ch === '"') return { ...acc, inQuotes: true }; if (ch === ',') return { ...acc, fields: [...acc.fields, acc.current], current: '' }; return { ...acc, current: acc.current + ch }; }, { fields: [], current: '', inQuotes: false, skipNext: false }); } function parseCsvLine(line) { const result = parseCsvCharacters(line); return [...result.fields, result.current]; } function parseBool(value) { const normalized = String(value).trim().toLowerCase(); if (normalized === 'true') return true; if (normalized === 'false') return false; throw new Error(`Invalid boolean value "${value}" in CSV (expected "true" or "false").`); } // --------------------------------------------------------------------------- // Build the ordered column list from a set of roles (for formatWide) // --------------------------------------------------------------------------- function collectSmartActionsForCollection(roles, envId, colName) { const actionSet = new Set(); roles.forEach(role => { const envPerms = (role.permissions.environments || []).find(e => String(e.environmentId ?? e.id) === String(envId)); if (!envPerms) return; const col = (envPerms.collections || []).find(c => c.collectionName === colName); if (!col) return; (col.smartActions || []).forEach(sa => actionSet.add(sa.smartActionName)); }); return Array.from(actionSet).sort(); } function collectColumns(collections, roles, envId) { return collections.reduce((cols, colName) => { const crudCols = CRUD_SUFFIXES.map(s => `${colName}:${s}`); const actions = collectSmartActionsForCollection(roles, envId, colName); const saCols = actions.reduce((acc, action) => [...acc, ...SMART_ACTION_SUFFIXES.map(s => `${colName}:${action}:${s}`)], []); return [...cols, ...crudCols, ...saCols]; }, []); } function buildColumns(roles, envId) { const collectionSet = new Set(); roles.forEach(role => { const envPerms = (role.permissions.environments || []).find(e => String(e.environmentId ?? e.id) === String(envId)); if (!envPerms) return; (envPerms.collections || []).forEach(col => collectionSet.add(col.collectionName)); }); const collections = Array.from(collectionSet).sort(); return collectColumns(collections, roles, envId); } // --------------------------------------------------------------------------- // formatWide helpers // --------------------------------------------------------------------------- function getCrudValue(col, suffix) { if (!col) return false; return Boolean(col[CRUD_FIELD_MAP[suffix]]); } function getSmartActionValue(col, actionName, suffix) { if (!col) return false; const sa = (col.smartActions || []).find(a => a.smartActionName === actionName); if (!sa) return false; if (suffix === 'hasConditions') { return (sa.triggerCondition != null || sa.approvalRequiredCondition != null || sa.userApprovalCondition != null); } return Boolean(sa[SA_FIELD_MAP[suffix]]); } function buildCellForColumn(colHeader, colByName) { const parts = colHeader.split(':'); if (parts.length === 2) { const [colName, suffix] = parts; return String(getCrudValue(colByName[colName], suffix)); } if (parts.length === 3) { const [colName, actionName, suffix] = parts; return String(getSmartActionValue(colByName[colName], actionName, suffix)); } return 'false'; } function buildRoleRow(role, columns, envId) { const envPerms = (role.permissions.environments || []).find(e => String(e.environmentId ?? e.id) === String(envId)); const enabled = envPerms ? Boolean(envPerms.enabled) : false; const colByName = {}; if (envPerms) { (envPerms.collections || []).forEach(col => { colByName[col.collectionName] = col; }); } const cells = [role.name, String(enabled), ...columns.map(h => buildCellForColumn(h, colByName))]; return cells.map(escapeCsv).join(','); } /** * Format an array of full role objects into a wide CSV string. * @param {Array<{ id: string, name: string, permissions: { environments: Array } }>} roles * @param {string|number} envId * @returns {string} */ function formatWide(roles, envId) { const columns = buildColumns(roles, envId); const header = ['role', 'enabled', ...columns].map(escapeCsv).join(','); const rows = [header, ...roles.map(role => buildRoleRow(role, columns, envId))]; return `${rows.join('\n')}\n`; } // --------------------------------------------------------------------------- // parseWide helpers // --------------------------------------------------------------------------- function emptyCollection(colName) { return { collectionName: colName, browseEnabled: false, readEnabled: false, addEnabled: false, editEnabled: false, deleteEnabled: false, exportEnabled: false, smartActions: [], }; } function emptySa(actionName) { return { smartActionName: actionName, triggerEnabled: false, approvalRequired: false, userApprovalEnabled: false, selfApprovalEnabled: false, }; } function applyTwoPartHeader(collectionMap, colName, suffix, rawValue) { if (!CRUD_SUFFIXES.includes(suffix)) { throw new Error(`Unknown permission column "${colName}:${suffix}" in CSV.`); } const col = collectionMap[colName] || emptyCollection(colName); return { ...collectionMap, [colName]: { ...col, [CRUD_FIELD_MAP[suffix]]: parseBool(rawValue) } }; } function applyThreePartHeader(collectionMap, colName, actionName, suffix, rawValue) { // hasConditions is derived/read-only on export — ignore it on the write path. if (suffix === 'hasConditions') return collectionMap; if (!SMART_ACTION_WRITE_SUFFIXES.includes(suffix)) { throw new Error(`Unknown smart-action column "${colName}:${actionName}:${suffix}" in CSV.`); } const col = collectionMap[colName] || emptyCollection(colName); const existingSa = col.smartActions.find(a => a.smartActionName === actionName) || emptySa(actionName); const updatedSa = { ...existingSa, [SA_FIELD_MAP[suffix]]: parseBool(rawValue) }; const updatedSmartActions = col.smartActions.find(a => a.smartActionName === actionName) ? col.smartActions.map(a => (a.smartActionName === actionName ? updatedSa : a)) : [...col.smartActions, updatedSa]; return { ...collectionMap, [colName]: { ...col, smartActions: updatedSmartActions } }; } function applyHeader(collectionMap, header, rawValue) { const parts = header.split(':'); if (parts.length === 2) return applyTwoPartHeader(collectionMap, parts[0], parts[1], rawValue); if (parts.length === 3) return applyThreePartHeader(collectionMap, parts[0], parts[1], parts[2], rawValue); throw new Error(`Unrecognized CSV column "${header}".`); } function parseRow(headers, cells, envId) { if (cells.length !== headers.length) { throw new Error(`CSV row has ${cells.length} cell(s) but the header has ${headers.length}.`); } const row = headers.reduce((acc, h, j) => ({ ...acc, [h]: cells[j] }), {}); const name = row.role; const enabled = parseBool(row.enabled); const collectionMap = Object.keys(row) .filter(h => h !== 'role' && h !== 'enabled') .reduce((map, h) => applyHeader(map, h, row[h]), {}); return { name, enabled, envId: String(envId), collections: Object.values(collectionMap) }; } /** * Parse a wide CSV string back into a structured desired-state array. * @param {string} csvContent * @param {string|number} envId */ function parseWide(csvContent, envId) { // Split on CRLF or LF: a CSV saved by Excel/Windows uses \r\n, and a trailing // \r would otherwise taint the last field (e.g. `enabled\r`) and break parsing. const lines = csvContent.split(/\r?\n/).filter(l => l.trim() !== ''); if (lines.length < 2) return []; const headers = parseCsvLine(lines[0]); return lines.slice(1).map(line => parseRow(headers, parseCsvLine(line), envId)); } // --------------------------------------------------------------------------- // computeDiff helpers // --------------------------------------------------------------------------- function diffEnabled(cur, desired, envId) { const curEnabled = cur ? cur.enabled : false; if (curEnabled === desired.enabled) return []; return [{ op: 'replace', path: `/environments/${envId}/enabled`, value: desired.enabled }]; } function diffCrudField(envId, colName, curCol, field, desiredVal) { const curVal = curCol ? Boolean(curCol[field]) : false; if (curVal === desiredVal) return null; return { op: 'replace', path: `/environments/${envId}/collections/${colName}/${field}`, value: desiredVal, }; } function diffCrud(envId, desiredCol, curCol) { return CRUD_FIELDS.map(field => diffCrudField(envId, desiredCol.collectionName, curCol, field, Boolean(desiredCol[field]))).filter(Boolean); } function diffSaField(envId, colName, actionName, curSa, field, desiredVal) { const curVal = curSa ? Boolean(curSa[field]) : false; if (curVal === desiredVal) return null; return { op: 'replace', path: `/environments/${envId}/collections/${colName}/smartActions/${actionName}/${field}`, value: desiredVal, }; } function diffSmartAction(envId, colName, desiredSa, curCol) { const curSa = curCol ? (curCol.smartActions || []).find(a => a.smartActionName === desiredSa.smartActionName) : null; return SA_FIELDS.map(field => diffSaField(envId, colName, desiredSa.smartActionName, curSa, field, Boolean(desiredSa[field]))).filter(Boolean); } function diffCollection(envId, desiredCol, cur) { const curCol = cur ? (cur.collections || []).find(c => c.collectionName === desiredCol.collectionName) : null; const crudOps = diffCrud(envId, desiredCol, curCol); const saOps = (desiredCol.smartActions || []).reduce((acc, desiredSa) => [ ...acc, ...diffSmartAction(envId, desiredCol.collectionName, desiredSa, curCol), ], []); return [...crudOps, ...saOps]; } function diffRole(current, desired) { const cur = current.find(r => r.name === desired.name); const { envId } = desired; const enabledOps = diffEnabled(cur, desired, envId); const collectionOps = desired.collections.reduce((acc, desiredCol) => [...acc, ...diffCollection(envId, desiredCol, cur)], []); return { roleName: desired.name, roleId: cur ? cur.id : null, ops: [...enabledOps, ...collectionOps], }; } /** * Compute the diff between the current state and the desired state. * @param {Array} current * @param {Array} parsed */ function computeDiff(current, parsed) { return parsed.map(desired => diffRole(current, desired)); } module.exports = { formatWide, parseWide, computeDiff }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9sZXMtY3N2LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2VzL3JvbGVzLWNzdi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxNQUFNLGFBQWEsR0FBRyxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7QUFDNUUsTUFBTSxxQkFBcUIsR0FBRztJQUM1QixTQUFTO0lBQ1Qsa0JBQWtCO0lBQ2xCLGNBQWM7SUFDZCxjQUFjO0lBQ2QsZUFBZTtDQUNoQixDQUFDO0FBQ0YsTUFBTSwyQkFBMkIsR0FBRyxDQUFDLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxjQUFjLEVBQUUsY0FBYyxDQUFDLENBQUM7QUFFcEcsTUFBTSxjQUFjLEdBQUc7SUFDckIsTUFBTSxFQUFFLGVBQWU7SUFDdkIsSUFBSSxFQUFFLGFBQWE7SUFDbkIsR0FBRyxFQUFFLFlBQVk7SUFDakIsSUFBSSxFQUFFLGFBQWE7SUFDbkIsTUFBTSxFQUFFLGVBQWU7SUFDdkIsTUFBTSxFQUFFLGVBQWU7Q0FDeEIsQ0FBQztBQUVGLE1BQU0sWUFBWSxHQUFHO0lBQ25CLE9BQU8sRUFBRSxnQkFBZ0I7SUFDekIsZ0JBQWdCLEVBQUUsa0JBQWtCO0lBQ3BDLFlBQVksRUFBRSxxQkFBcUI7SUFDbkMsWUFBWSxFQUFFLHFCQUFxQjtDQUNwQyxDQUFDO0FBRUYsa0ZBQWtGO0FBQ2xGLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7QUFDbEQsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUU5Qyw4RUFBOEU7QUFDOUUsNkNBQTZDO0FBQzdDLDhFQUE4RTtBQUU5RSxTQUFTLFNBQVMsQ0FBQyxLQUFLO0lBQ3RCLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxLQUFLLElBQUksSUFB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