Skip to content

Commit

Permalink
implement getPath for Yaml handler
Browse files Browse the repository at this point in the history
  • Loading branch information
LorisSigrist committed Oct 12, 2023
1 parent 53c8ad5 commit 347c1d6
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 40 deletions.
26 changes: 2 additions & 24 deletions src/core/file-handling/formats/json.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ResultMatcher } from "../../utils/resultMatcher.js";
import { LoadingException } from "../exception.js";
import { flattenTree } from "../utils.js";
import { flattenTree, setPathOnTree } from "../utils.js";

/** @type {import("../types.js").FormatHandler} */
export const JsonHandler = {
Expand Down Expand Up @@ -28,29 +28,7 @@ export const JsonHandler = {
const obj = JSON.parse(oldJSON);

const path = key.split(".");

/**
* @param {any} tree
* @param {string[]} path
* @param {string} value
* @returns
*/
function setOnTree(tree, path, value) {
//Split the path into the current level and the rest of the path
const [current, ...rest] = path;
if (!current)
throw new Error("There must be at least one level in the path");

if (rest.length === 0) {
tree[current] = value;
return;
}

if (!tree[current]) tree[current] = {};
setOnTree(tree[current], rest, value);
}

setOnTree(obj, path, value);
setPathOnTree(obj, path, value);

const newJSON = JSON.stringify(obj);
return newJSON;
Expand Down
57 changes: 41 additions & 16 deletions src/core/file-handling/formats/yaml.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,51 @@
import { load as loadYaml, YAMLException } from "js-yaml";
import { flattenTree } from "../utils.js";
import { dump, load as loadYaml, YAMLException } from "js-yaml";
import { flattenTree, setPathOnTree } from "../utils.js";
import { LoadingException } from "../exception.js";
import { ResultMatcher } from "../../utils/resultMatcher.js";

/** @type {import("../types.js").FormatHandler} */
export const YamlHandler = {
fileExtensions: ["yaml", "yml"],
load: (filePath, content) => {
/** @param {YAMLException} e */
const raiseLoadingException = (e) => {
throw new LoadingException(
`Could not parse YAML file ${filePath}: ${e.message}`,
{ cause: e },
);
};

return new ResultMatcher(loadYaml)
.ok(flattenTree)
.catch(YAMLException, raiseLoadingException)
.run(content, { filename: filePath });
const tree = parseAsTree(content, filePath);
return new ResultMatcher(flattenTree)
.catchAll((e) => raiseLoadingException(e, filePath))
.run(tree);
},
setPath() {
throw new Error("Not implemented");
setPath(oldYaml, key, value) {
const tree = parseAsTree(oldYaml);

const path = key.split(".");
setPathOnTree(tree, path, value);

const newYaml = dump(tree);
return newYaml;
},
};

/**
* @param {string} content
* @param {string|undefined} filePath
* @return {unknown}
*/
function parseAsTree(content, filePath = undefined) {
return new ResultMatcher(loadYaml)
.ok((res) => {
if (typeof res !== "object") return {};
return res;
})
.catch(YAMLException, (e) => raiseLoadingException(e, filePath))
.run(content, { filename: filePath });
}

/**
* @param {unknown} e
* @param {string | undefined} filePath
*/
const raiseLoadingException = (e, filePath = undefined) => {
const msg =
e instanceof Error
? `Could not parse YAML file ${filePath ?? ""}: ${e.message}`
: `Could not parse YAML file ${filePath ?? ""}`;
throw new LoadingException(msg, { cause: e });
};
21 changes: 21 additions & 0 deletions src/core/file-handling/formats/yaml.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { describe, expect, it } from "vitest";
import { LoadingException } from "../exception";
import { YamlHandler } from "./yaml";

describe("YamlHandler", () => {
it("parses an empty file as an empty dictionary", () => {
const result = YamlHandler.load("test.yaml", "");
expect(result).toEqual(new Map());
});

it("sets a path on an empty file", () => {
const newYaml = YamlHandler.setPath("", "key1.key2", "value");
expect(newYaml).toEqual("key1:\n key2: value\n");
});

it("sets a path on an existing file", () => {
const oldYaml = "key1:\n key2: value\n";
const newYaml = YamlHandler.setPath(oldYaml, "key1.key3", "value");
expect(newYaml).toEqual("key1:\n key2: value\n key3: value\n");
});
});
23 changes: 23 additions & 0 deletions src/core/file-handling/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,26 @@ export function flattenTree(tree) {
throw new Error("Invalid tree");
}
}

/**
* Modifies a tree so that the given path has the given value.
* Will create intermediate levels as needed.
*
* @param {any} tree
* @param {string[]} path
* @param {string} value
* @returns
*/
export function setPathOnTree(tree, path, value) {
//Split the path into the current level and the rest of the path
const [current, ...rest] = path;
if (!current) throw new Error("There must be at least one level in the path");

if (rest.length === 0) {
tree[current] = value;
return;
}

if (!tree[current]) tree[current] = {};
setPathOnTree(tree[current], rest, value);
}

0 comments on commit 347c1d6

Please sign in to comment.