UNPKG

forest-cli

Version:

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

259 lines 23.5 kB
"use strict"; /** * The diff engine: compares a remote canonical document against the locally * edited one and produces ONLY server-whitelisted JSON Patch operations. * * Identity-based: items are matched by `id` then `name` (see `matchItems`), * never by index. Renames are plain `replace .../name` ops because children * are always addressed by the REMOTE item's key (stable across edits). * Emission order per domain: adds (parents first) → replaces → removes. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.diffDomain = exports.remoteResolver = void 0; const util_1 = require("util"); const uuid_1 = require("uuid"); const layout_file_1 = require("./layout-file"); const patch_rules_1 = require("./patch-rules"); /** Address segment for an item: prefer the stable id, else a path-safe name. */ function addressOf(item, jsonPath) { if (item.id !== undefined && item.id !== null) return String(item.id); const { name } = item; if (typeof name === 'string' && /^[^\s/:]+$/.test(name)) return name; throw new layout_file_1.LayoutFileError(`${jsonPath}: item without a usable \`id\` (and the name contains characters forbidden in a path). ` + 'Do not remove the `id` fields generated by `forest layout pull`.'); } /** Identity key used to match local and remote items. */ function identityOf(item) { if (item.id !== undefined && item.id !== null) return `id:${String(item.id)}`; if (typeof item.name === 'string') return `name:${item.name}`; return undefined; } /** * Match local items to remote ones by `id`, then by `name` — so a hand-authored * item that omits its `id` updates the existing element instead of being seen as * an add + a remove. Fails loudly on ambiguous input (duplicate local identities, * or two locals resolving to the same remote). */ /** * Build the local→remote resolver: a singleton (e.g. the main folder) matches its * remote counterpart regardless of id/name; otherwise match by id, then by name. * Exported so the sidecar upload (`workflow-sidecar.ts`) resolves its target with * the EXACT same semantics as the domain patch (incl. last-wins on duplicate names). */ function remoteResolver(remoteItems, singletonFlag) { const remoteById = new Map(); const remoteByName = new Map(); remoteItems.forEach(item => { if (item.id !== undefined && item.id !== null) remoteById.set(String(item.id), item); if (typeof item.name === 'string') remoteByName.set(item.name, item); }); const remoteSingleton = singletonFlag ? remoteItems.find(item => item[singletonFlag] === true) : undefined; return local => (singletonFlag !== undefined && local[singletonFlag] === true ? remoteSingleton : undefined) ?? (local.id !== undefined && local.id !== null ? remoteById.get(String(local.id)) : undefined) ?? (typeof local.name === 'string' ? remoteByName.get(local.name) : undefined); } exports.remoteResolver = remoteResolver; function matchItems(remoteItems, localItems, jsonPath, singletonFlag) { const matchOf = remoteResolver(remoteItems, singletonFlag); const seen = new Set(); const matched = new Set(); const added = []; const common = []; localItems.forEach(local => { const key = identityOf(local); if (key === undefined) { throw new layout_file_1.LayoutFileError(`${jsonPath}: item without \`id\` or \`name\` — unable to identify it.`); } if (seen.has(key)) { throw new layout_file_1.LayoutFileError(`${jsonPath}: two items share the same identity (${key}).`); } seen.add(key); const remote = matchOf(local); if (!remote) { added.push(local); } else if (matched.has(remote)) { throw new layout_file_1.LayoutFileError(`${jsonPath}: two items resolve to the same remote element (\`id\`/\`name\` collision).`); } else { matched.add(remote); common.push({ local, remote }); } }); return { added, common, removed: remoteItems.filter(item => !matched.has(item)) }; } function short(value) { if (value === null) return 'null'; if (value === undefined) return '∅'; if (typeof value === 'object') { const { name } = value; if (typeof name === 'string') return `{ name: « ${name} », … }`; return Array.isArray(value) ? `[${value.length} items]` : '{…}'; } const text = typeof value === 'string' ? ${value} »` : String(value); return text.length > 60 ? `${text.slice(0, 57)}…` : text; } function emit(ctx, kind, op) { ctx.bucket[kind].push(op); } function diffScalarLike(ctx, rule, remote, local) { const path = `${ctx.pathPrefix}/${rule.prop}`; const jsonPath = `${ctx.jsonPrefix}.${rule.prop}`; const remoteValue = remote[rule.prop]; const localValue = local[rule.prop]; if ((0, util_1.isDeepStrictEqual)(remoteValue, localValue)) return; const premiumPack = rule.premiumPack ?? ctx.premiumPack; // Absent locally = "leave alone" (partial-authoring / patch semantics): the // file need not carry every field. To clear a value, set it explicitly to // `null` (which reaches the replace path below as a value, not `undefined`). if (localValue === undefined) return; emit(ctx, 'replaces', { domain: ctx.domain, label: `${jsonPath}: ${short(remoteValue)}${short(localValue)}`, op: 'replace', path, premiumPack, value: localValue, jsonPath, }); } /** * Build the value sent in an `add` op. The server requires a client-supplied * `id` on add (PRIMARY_KEYS) — so we KEEP the local id (stable across re-apply * and cross-env copies) and generate a uuid only when none is present. Any * per-rule `stripOnAdd` keys and `undefined` values are dropped; remaining * write-required defaults are filled by the rule's own `addDefaults` hook. */ function prepareAddValue(item, rule) { const cleaned = {}; Object.entries(item).forEach(([key, value]) => { if (rule.stripOnAdd?.includes(key)) return; if (value === undefined) return; cleaned[key] = value; }); if (cleaned.id === undefined || cleaned.id === null) cleaned.id = (0, uuid_1.v4)(); return rule.addDefaults ? rule.addDefaults(cleaned) : cleaned; } function diffKeyedArray(ctx, rule, remoteItems, localItems) { // A root rule with `prop: ''` (folders/workflows) receives the document itself, // which is `{}` when the domain is absent remotely — guard against non-arrays so // `matchItems` never iterates a plain object. const remotes = Array.isArray(remoteItems) ? remoteItems : []; const locals = Array.isArray(localItems) ? localItems : []; const arrayPath = rule.segment ? `${ctx.pathPrefix}/${rule.segment}` : ctx.pathPrefix; const jsonPath = rule.prop ? `${ctx.jsonPrefix}.${rule.prop}` : ctx.jsonPrefix; const premiumPack = rule.premiumPack ?? ctx.premiumPack; const { added, common, removed } = matchItems(remotes, locals, jsonPath, rule.singletonFlag); if (rule.fallbackReplaceWhole && (added.length > 0 || removed.length > 0)) { emit(ctx, 'replaces', { domain: ctx.domain, label: `${jsonPath}: replacing the array (${locals.length} items)`, op: 'replace', path: arrayPath, premiumPack, value: locals, jsonPath, }); return; } added.forEach(item => { if (!rule.addable) { ctx.bucket.warnings.push(`${jsonPath}: cannot add « ${String(item.name ?? item.id)} » (items defined by the agent schema).`); return; } emit(ctx, 'adds', { domain: ctx.domain, label: `${jsonPath}: adding ${short(item)}`, op: 'add', path: `${arrayPath}/-`, premiumPack, value: prepareAddValue(item, rule), jsonPath, }); }); removed.forEach(item => { if (!rule.removable) { ctx.bucket.warnings.push(`${jsonPath}: cannot remove « ${String(item.name ?? item.id)} » (items defined by the agent schema).`); return; } emit(ctx, 'removes', { domain: ctx.domain, label: `${jsonPath}: removing ${short(item)}`, op: 'remove', path: `${arrayPath}/${addressOf(item, jsonPath)}`, premiumPack, jsonPath, }); }); common.forEach(({ local, remote }) => { const address = addressOf(remote, jsonPath); const childCtx = { ...ctx, pathPrefix: `${arrayPath}/${address}`, premiumPack, jsonPrefix: `${jsonPath}[${address}]`, }; // eslint-disable-next-line no-use-before-define -- applyRules and diffKeyedArray are mutually recursive applyRules(childCtx, rule.children, remote, local); }); } function applyRules(ctx, rules, remote, local) { rules.forEach(rule => { switch (rule.kind) { case 'keyedArray': { const remoteItems = (rule.prop ? remote[rule.prop] : remote); const localItems = (rule.prop ? local[rule.prop] : local); diffKeyedArray(ctx, rule, remoteItems ?? [], localItems ?? []); break; } case 'object': { const remoteChild = (remote[rule.prop] ?? {}); const localChild = (local[rule.prop] ?? {}); applyRules({ ...ctx, pathPrefix: `${ctx.pathPrefix}/${rule.segment}`, jsonPrefix: `${ctx.jsonPrefix}.${rule.prop}`, }, rule.children, remoteChild, localChild); break; } case 'opaque': case 'scalar': { diffScalarLike(ctx, rule, remote, local); break; } default: break; } }); } /** Diff one domain; returns whitelisted ops (adds → replaces → removes) + warnings. */ function diffDomain(domain, remote, local) { const bucket = { adds: [], removes: [], replaces: [], warnings: [] }; const ctx = { bucket, domain, pathPrefix: '', jsonPrefix: domain }; applyRules(ctx, patch_rules_1.DOMAIN_RULES[domain].root, (remote ?? {}), (local ?? {})); const ops = [...bucket.adds, ...bucket.replaces, ...bucket.removes]; const offending = ops.find(op => !(0, patch_rules_1.matchesWhitelist)(domain, op)); if (offending) { throw new Error(`Internal bug: op generated outside the whitelist (${offending.op} ${offending.path}). ` + 'Please report this case — nothing was sent.'); } return { ops, warnings: bucket.warnings }; } exports.diffDomain = diffDomain; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlmZi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9sYXlvdXQvZGlmZi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7O0dBUUc7OztBQUtILCtCQUF5QztBQUN6QywrQkFBb0M7QUFFcEMsK0NBQWdEO0FBQ2hELCtDQUErRDtBQVMvRCxnRkFBZ0Y7QUFDaEYsU0FBUyxTQUFTLENBQUMsSUFBVSxFQUFFLFFBQWdCO0lBQzdDLElBQUksSUFBSSxDQUFDLEVBQUUsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLEVBQUUsS0FBSyxJQUFJO1FBQUUsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBRXRFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFDdEIsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUVyRSxNQUFNLElBQUksNkJBQWUsQ0FDdkIsR0FBRyxRQUFRLHlGQUF5RjtRQUNsRyxrRUFBa0UsQ0FDckUsQ0FBQztBQUNKLENBQUM7QUFFRCx5REFBeUQ7QUFDekQsU0FBUyxVQUFVLENBQUMsSUFBVTtJQUM1QixJQUFJLElBQUksQ0FBQyxFQUFFLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxFQUFFLEtBQUssSUFBSTtRQUFFLE9BQU8sTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDOUUsSUFBSSxPQUFPLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUTtRQUFFLE9BQU8sUUFBUSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFFOUQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQVFEOzs7OztHQUtHO0FBQ0g7Ozs7O0dBS0c7QUFDSCxTQUFnQixjQUFjLENBQzVCLFdBQW1CLEVBQ25CLGFBQXNCO0lB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