Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
danewalters committed Aug 1, 2024
1 parent ea9c04f commit 3e74dae
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 92 deletions.
126 changes: 37 additions & 89 deletions src/jcli/config/project-json-patch-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -33,6 +34,7 @@ interface BuilderContext {
currentPathNode: PathNode;
assigns: Map<string, unknown>;
restPathNodes: ReadonlyArray<PathNode>;
datawasWithObject: ProjectJsonWithObject;
}

type BuilderFn = (
Expand Down Expand Up @@ -99,6 +101,7 @@ class BuilderNode {
currentPathNode,
assigns,
restPathNodes: diffPatch.path,
datawasWithObject: buildProjectJsonWithObjects(dataWas),
});
}

Expand Down Expand Up @@ -137,10 +140,6 @@ function equal(value: PathNode): BuilderNodeFilter {
return (pathNode) => pathNode === value;
}

function equalAny(value: ReadonlyArray<PathNode>): BuilderNodeFilter {
return (pathNode) => value.includes(pathNode);
}

function isNumber(value: PathNode): value is number {
return typeof value === "number";
}
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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<T>(
patches: Array<T>,
predicate: (value: T) => boolean,
Expand Down Expand Up @@ -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,
Expand Down
36 changes: 33 additions & 3 deletions src/jcli/config/project-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ import projectJSONSchema from "@schemas/project-file.v1.json" with {
type: "json",
};

export type ProjectJsonWithObject =
& Omit<Project, "id" | "instances" | "capabilities">
& {
capabilities: {
[key: string]: ProjectCapability;
};
instances: {
[key: string]: ProjectPluginInstance;
};
};

export function projectDotJSONPath(projectName?: string): string {
if (undefined === projectName) {
return "./project.json";
Expand Down Expand Up @@ -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 = <T extends { name: string }>(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<DiffPatch>,
dataWas: ProjectJSON,
Expand Down

0 comments on commit 3e74dae

Please sign in to comment.