From 3e74daeadeae1c6d512b6b8f445f55e12ac1ab6c Mon Sep 17 00:00:00 2001 From: Dane Walters Date: Thu, 1 Aug 2024 16:26:44 +0800 Subject: [PATCH] wip --- src/jcli/config/project-json-patch-builder.ts | 126 +++++------------- src/jcli/config/project-json.ts | 36 ++++- 2 files changed, 70 insertions(+), 92 deletions(-) diff --git a/src/jcli/config/project-json-patch-builder.ts b/src/jcli/config/project-json-patch-builder.ts index 0bf281c..f83fc2a 100644 --- a/src/jcli/config/project-json-patch-builder.ts +++ b/src/jcli/config/project-json-patch-builder.ts @@ -7,9 +7,10 @@ import { } from "@/jet/project.ts"; import { + buildProjectJsonWithObjects, ProjectCapabilityUpdatePatch, + ProjectJsonWithObject, ProjectPatch, - ProjectPluginInstanceUpdatePatch, } from "@/jcli/config/project-json.ts"; import { diffApply } from "just-diff-apply"; @@ -33,6 +34,7 @@ interface BuilderContext { currentPathNode: PathNode; assigns: Map; restPathNodes: ReadonlyArray; + datawasWithObject: ProjectJsonWithObject; } type BuilderFn = ( @@ -99,6 +101,7 @@ class BuilderNode { currentPathNode, assigns, restPathNodes: diffPatch.path, + datawasWithObject: buildProjectJsonWithObjects(dataWas), }); } @@ -137,10 +140,6 @@ function equal(value: PathNode): BuilderNodeFilter { return (pathNode) => pathNode === value; } -function equalAny(value: ReadonlyArray): BuilderNodeFilter { - return (pathNode) => value.includes(pathNode); -} - function isNumber(value: PathNode): value is number { return typeof value === "number"; } @@ -249,18 +248,38 @@ function buildInstancesPatch( value: unknown, patch: ProjectPatch, context: BuilderContext, -): void { - if (0 === context.restPathNodes.length) { +) { + const { currentPathNode, restPathNodes, datawasWithObject } = context; + const currentInstance = + datawasWithObject.instances[currentPathNode as string]; + + if (restPathNodes.length === 0) { doBuildInstancesPatch(op, value, patch, context); } else { - const { dataWas: { instances }, currentPathNode, assigns } = context; - const instance = instances[currentPathNode as number]; + diffApply(context.datawasWithObject.instances, [ + { + op, + path: [currentPathNode, ...restPathNodes] as string[], + value, + }, + ]); + + const instanceData = { + name: currentPathNode as string, + description: currentInstance.description, + config: currentInstance.config, + capabilityNames: currentInstance.capabilityNames, + }; + + const index = patch.instances.findIndex((ins) => + ins.name === currentPathNode + ); - if (patch.instances.every((e) => e.name !== instance.name)) { - patch.instances.push({ action: "update", name: instance.name }); + if (index === -1) { + patch.instances.push({ action: "update", ...instanceData }); + } else { + patch.instances[index] = { action: "update", ...instanceData }; } - - assigns.set("instance", instance); } } @@ -283,85 +302,19 @@ function doBuildInstancesPatch( config, capabilityNames, }); - break; } case "remove": { - const { dataWas: { instances }, currentPathNode } = context; + const { currentPathNode } = context; patch.instances.push({ action: "delete", - name: instances[currentPathNode as number].name, + name: currentPathNode as string, }); } } } -function buildInstancePatch( - op: DiffPatchOp, - value: unknown, - patch: ProjectPatch, - context: BuilderContext, -): void { - const instance = context.assigns.get("instance") as ProjectPluginInstance; - - switch (context.currentPathNode) { - case "description": { - updatePatch( - patch.instances, - (e) => e.name === instance.name, - (p) => - (p as ProjectPluginInstanceUpdatePatch).description = value as string, - ); - - break; - } - - case "config": { - const path = `/${context.restPathNodes.join("/")}`; - - updatePatch( - patch.instances, - (e) => e.name === instance.name, - (e) => { - const patch = e as ProjectPluginInstanceUpdatePatch; - const config = applyPatch(patch.config ?? instance.config, [{ - op, - path, - value, - }]); - patch.config = config; - }, - ); - - break; - } - - case "capabilityNames": { - const path = `/${context.restPathNodes.join("/")}`; - - updatePatch( - patch.instances, - (e) => e.name === instance.name, - (e) => { - const patch = e as ProjectPluginInstanceUpdatePatch; - const capabilityNames = applyPatch( - patch.capabilityNames ?? instance.capabilityNames, - [{ - op, - path, - value, - }], - ); - patch.capabilityNames = capabilityNames; - }, - ); - - break; - } - } -} - function updatePatch( patches: Array, predicate: (value: T) => boolean, @@ -422,14 +375,9 @@ export const builder = new BuilderNode({ name: "root" }).children([ ), ]), new BuilderNode({ name: "instances" }).on(equal("instances")).children([ - new BuilderNode({ name: "instances.item", alwaysRun: true }).on(isNumber) - .do(buildInstancesPatch) - .children([ - new BuilderNode({ name: "instances.item.attributes", alwaysRun: true }) - .on( - equalAny(["description", "config", "capabilityNames"]), - ).do(buildInstancePatch), - ]), + new BuilderNode({ name: "instance", alwaysRun: true }).do( + buildInstancesPatch, + ), ]), new BuilderNode({ name: "imports", alwaysRun: true }).on(equal("imports")).do( buildImportsPatch, diff --git a/src/jcli/config/project-json.ts b/src/jcli/config/project-json.ts index ed532af..5b67938 100644 --- a/src/jcli/config/project-json.ts +++ b/src/jcli/config/project-json.ts @@ -19,6 +19,17 @@ import projectJSONSchema from "@schemas/project-file.v1.json" with { type: "json", }; +export type ProjectJsonWithObject = + & Omit + & { + capabilities: { + [key: string]: ProjectCapability; + }; + instances: { + [key: string]: ProjectPluginInstance; + }; + }; + export function projectDotJSONPath(projectName?: string): string { if (undefined === projectName) { return "./project.json"; @@ -61,12 +72,31 @@ export class ProjectDotJSON { } diff(other: ProjectDotJSON): ProjectPatch { - const selfJSON = this.toJSON(); - const result = diff(selfJSON, other.toJSON()); - return buildPatch(result, selfJSON); + const result = diff( + buildProjectJsonWithObjects(this.toJSON()), + buildProjectJsonWithObjects(other.toJSON()), + ); + + return buildPatch(result, this.toJSON()); } } +export function buildProjectJsonWithObjects( + project: ProjectJSON, +): ProjectJsonWithObject { + const convertArrayToObject = (array: T[]) => + array.reduce((acc, item) => { + acc[item.name] = item; + return acc; + }, {} as { [key: string]: T }); + + return { + ...project, + capabilities: convertArrayToObject(project.capabilities), + instances: convertArrayToObject(project.instances), + }; +} + function buildPatch( diffPatches: ReadonlyArray, dataWas: ProjectJSON,