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
JavaScript
/**
* 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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