aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Beltran del Rio <jj@r.bdr.sh>2025-12-12 15:33:04 +0100
committerRuben Beltran del Rio <jj@r.bdr.sh>2025-12-12 18:01:10 +0100
commit80aefd27ffc19a948c74f2418a2a5bf5f95a6868 (patch)
tree87467674eadfacae3c4d3fecbbcb95a9c28519c7
parentaee5dffd8013f6f6a6b77e5d00edd981bcfcad48 (diff)
Use stage instead of number, and use an actual signed value
-rw-r--r--src/index.js10
-rw-r--r--test/parser.test.js240
2 files changed, 123 insertions, 127 deletions
diff --git a/src/index.js b/src/index.js
index 24a2c2e..f705f5a 100644
--- a/src/index.js
+++ b/src/index.js
@@ -44,7 +44,7 @@
* An override for the width of an evolution stage.
* @typedef {Object} Stage
* @property {'stage'} type - Entity type
- * @property {string} number - Stage number (i, ii, iii, iv)
+ * @property {string} stage - Stage number (i, ii, iii, iv)
* @property {number} value - Stage value
*/
@@ -67,7 +67,6 @@
* @typedef {Object} Evolution
* @property {'evolution'} type - Entity type
* @property {string} component - Component label
- * @property {boolean} isPositive - Whether evolution is positive (+) or negative (-)
* @property {number} value - Evolution value
*/
@@ -142,7 +141,7 @@ function parseKeywordEntity(line, start, length) {
// Skip whitespace after ']'
while (i < length && isWhitespace(line[i])) i++;
- // Stage: [I|II|III|IV] number
+ // Stage: [I|II|III|IV] stage
if (
keyword === "i" ||
keyword === "ii" ||
@@ -154,7 +153,7 @@ function parseKeywordEntity(line, start, length) {
if (i > numStart) {
return {
type: "stage",
- number: keyword,
+ stage: keyword,
value: parseFloat(line.substring(numStart, i)),
};
}
@@ -250,8 +249,7 @@ function parseKeywordEntity(line, start, length) {
return {
type: "evolution",
component,
- isPositive: signCharacter === "+",
- value: parseFloat(line.substring(numStart, indexOfNumber)),
+ value: (signCharacter === "+" ? 1 : -1) * parseFloat(line.substring(numStart, indexOfNumber)),
};
}
diff --git a/test/parser.test.js b/test/parser.test.js
index 975c6f0..13ddd72 100644
--- a/test/parser.test.js
+++ b/test/parser.test.js
@@ -5,51 +5,51 @@ import { parse } from "../src/index.js";
describe("wmap parser", () => {
describe("components", () => {
it("should parse a basic component", async () => {
- const source = "Tea (0.9, 0.5)";
- const result = await parse(source);
+ const source = "Dominoes (0.9, 0.5)";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 1);
assert.strictEqual(result.entities[0].type, "component");
- assert.strictEqual(result.entities[0].label, "Tea");
+ assert.strictEqual(result.entities[0].label, "Dominoes");
assert.deepStrictEqual(result.entities[0].coordinates, [0.9, 0.5]);
assert.strictEqual(result.entities[0].shape, "circle");
});
it("should parse a component with shape", async () => {
- const source = "Database (0.3, 0.8) [Square]";
- const result = await parse(source);
+ const source = "Database (0.33, 0.81) [Square]";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 1);
assert.strictEqual(result.entities[0].type, "component");
assert.strictEqual(result.entities[0].label, "Database");
- assert.deepStrictEqual(result.entities[0].coordinates, [0.3, 0.8]);
+ assert.deepStrictEqual(result.entities[0].coordinates, [0.33, 0.81]);
assert.strictEqual(result.entities[0].shape, "square");
});
it("should parse component with x shape", async () => {
const source = "API (0.5, 0.6) [x]";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities[0].shape, "x");
});
it("should parse component with triangle shape", async () => {
const source = "Service (0.4, 0.7) [Triangle]";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities[0].shape, "triangle");
});
it("should parse component with circle shape", async () => {
const source = "Process (0.2, 0.9) [CIRCLE]";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities[0].shape, "circle");
});
it("should handle decimal numbers", async () => {
const source = "Item (.5, .123)";
- const result = await parse(source);
+ const result = parse(source);
assert.deepStrictEqual(
result.entities[0].coordinates,
@@ -59,30 +59,30 @@ describe("wmap parser", () => {
it("should handle integers as coordinates", async () => {
const source = "Item (1, 0)";
- const result = await parse(source);
+ const result = parse(source);
assert.deepStrictEqual(result.entities[0].coordinates, [1, 0]);
});
it("should preserve case in component labels", async () => {
- const source = "MySpecialTea (0.5, 0.5)";
- const result = await parse(source);
+ const source = "RubberGaskets (0.5, 0.5)";
+ const result = parse(source);
- assert.strictEqual(result.entities[0].label, "MySpecialTea");
+ assert.strictEqual(result.entities[0].label, "RubberGaskets");
});
it("should handle component labels with spaces", async () => {
- const source = "Cup of Tea (0.5, 0.5)";
- const result = await parse(source);
+ const source = "Big Lawnmowers (0.5, 0.5)";
+ const result = parse(source);
- assert.strictEqual(result.entities[0].label, "Cup of Tea");
+ assert.strictEqual(result.entities[0].label, "Big Lawnmowers");
});
it("should handle whitespace around tokens", async () => {
- const source = " Tea ( 0.9 , 0.5 ) [ Square ] ";
- const result = await parse(source);
+ const source = " Outer Space ( 0.9 , 0.5 ) [ Square ] ";
+ const result = parse(source);
- assert.strictEqual(result.entities[0].label, "Tea");
+ assert.strictEqual(result.entities[0].label, "Outer Space");
assert.deepStrictEqual(result.entities[0].coordinates, [0.9, 0.5]);
assert.strictEqual(result.entities[0].shape, "square");
});
@@ -90,47 +90,47 @@ describe("wmap parser", () => {
describe("dependencies (edges)", () => {
it("should parse undirected dependency", async () => {
- const source = "Tea -- Cup";
- const result = await parse(source);
+ const source = "Smoke -- Fire";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 1);
assert.strictEqual(result.entities[0].type, "dependency");
- assert.strictEqual(result.entities[0].from, "Tea");
- assert.strictEqual(result.entities[0].to, "Cup");
+ assert.strictEqual(result.entities[0].from, "Smoke");
+ assert.strictEqual(result.entities[0].to, "Fire");
assert.strictEqual(result.entities[0].isDirected, false);
});
it("should parse directed dependency", async () => {
- const source = "Tea -> Cup";
- const result = await parse(source);
+ const source = "Cool Thing -> Different Cool Thing";
+ const result = parse(source);
assert.strictEqual(result.entities[0].type, "dependency");
- assert.strictEqual(result.entities[0].from, "Tea");
- assert.strictEqual(result.entities[0].to, "Cup");
+ assert.strictEqual(result.entities[0].from, "Cool Thing");
+ assert.strictEqual(result.entities[0].to, "Different Cool Thing");
assert.strictEqual(result.entities[0].isDirected, true);
});
it("should preserve case in dependency labels", async () => {
- const source = "MyTea -> YourCup";
- const result = await parse(source);
+ const source = "SaRcAsM -> Seriousness.";
+ const result = parse(source);
- assert.strictEqual(result.entities[0].from, "MyTea");
- assert.strictEqual(result.entities[0].to, "YourCup");
+ assert.strictEqual(result.entities[0].from, "SaRcAsM");
+ assert.strictEqual(result.entities[0].to, "Seriousness.");
});
it("should ignore whitespace in dependencies", async () => {
- const source = " Tea -- Cup ";
- const result = await parse(source);
+ const source = " loose --TIGHT";
+ const result = parse(source);
- assert.strictEqual(result.entities[0].from, "Tea");
- assert.strictEqual(result.entities[0].to, "Cup");
+ assert.strictEqual(result.entities[0].from, "loose");
+ assert.strictEqual(result.entities[0].to, "TIGHT");
});
});
describe("notes", () => {
it("should parse a note", async () => {
const source = "[Note] (0.5, 0.5) This is a note";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities.length, 1);
assert.strictEqual(result.entities[0].type, "note");
@@ -139,22 +139,22 @@ describe("wmap parser", () => {
});
it("should handle case insensitive note keyword", async () => {
- const source = "[note] (0.5, 0.5) Text";
- const result = await parse(source);
+ const source = "[note] (0.1, 0.2) Text";
+ const result = parse(source);
assert.strictEqual(result.entities[0].type, "note");
});
it("should preserve case in note text", async () => {
- const source = "[NOTE] (0.5, 0.5) Important NOTE";
- const result = await parse(source);
+ const source = "[NOTE] (0.77, 0.19) Important NOTE";
+ const result = parse(source);
assert.strictEqual(result.entities[0].text, "Important NOTE");
});
it("should handle empty note text", async () => {
const source = "[Note] (0.5, 0.5) ";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities[0].text, "");
});
@@ -163,41 +163,41 @@ describe("wmap parser", () => {
describe("stages", () => {
it("should parse stage I", async () => {
const source = "[I] 0.25";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities.length, 1);
assert.strictEqual(result.entities[0].type, "stage");
- assert.strictEqual(result.entities[0].number, "i");
+ assert.strictEqual(result.entities[0].stage, "i");
assert.strictEqual(result.entities[0].value, 0.25);
});
it("should parse stage II", async () => {
const source = "[ii] 0.5";
- const result = await parse(source);
+ const result = parse(source);
- assert.strictEqual(result.entities[0].number, "ii");
+ assert.strictEqual(result.entities[0].stage, "ii");
assert.strictEqual(result.entities[0].value, 0.5);
});
it("should parse stage III", async () => {
const source = "[III] 0.75";
- const result = await parse(source);
+ const result = parse(source);
- assert.strictEqual(result.entities[0].number, "iii");
+ assert.strictEqual(result.entities[0].stage, "iii");
assert.strictEqual(result.entities[0].value, 0.75);
});
it("should parse stage IV", async () => {
const source = "[Iv] 1.0";
- const result = await parse(source);
+ const result = parse(source);
- assert.strictEqual(result.entities[0].number, "iv");
+ assert.strictEqual(result.entities[0].stage, "iv");
assert.strictEqual(result.entities[0].value, 1.0);
});
it("should handle decimal stage values", async () => {
const source = "[I] .333";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities[0].value, 0.333);
});
@@ -205,116 +205,114 @@ describe("wmap parser", () => {
describe("groups", () => {
it("should parse a group with single component", async () => {
- const source = "[Group] Tea";
- const result = await parse(source);
+ const source = "[Group] Lonely";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 1);
assert.strictEqual(result.entities[0].type, "group");
- assert.deepStrictEqual(result.entities[0].components, ["Tea"]);
+ assert.deepStrictEqual(result.entities[0].components, ["Lonely"]);
});
it("should parse a group with multiple components", async () => {
- const source = "[Group] Tea, Cup, Kettle";
- const result = await parse(source);
+ const source = "[Group] Huey, Dewey, Louie";
+ const result = parse(source);
assert.deepStrictEqual(result.entities[0].components, [
- "Tea",
- "Cup",
- "Kettle",
+ "Huey",
+ "Dewey",
+ "Louie",
]);
});
it("should handle case insensitive group keyword", async () => {
- const source = "[group] Tea, Cup";
- const result = await parse(source);
+ const source = "[group] Salt, Pepper";
+ const result = parse(source);
assert.strictEqual(result.entities[0].type, "group");
});
it("should preserve case in group component labels", async () => {
- const source = "[GROUP] MyTea, YourCup";
- const result = await parse(source);
+ const source = "[GROUP] XML, LaTeX";
+ const result = parse(source);
assert.deepStrictEqual(result.entities[0].components, [
- "MyTea",
- "YourCup",
+ "XML",
+ "LaTeX",
]);
});
it("should handle whitespace around commas", async () => {
- const source = "[Group] Tea , Cup , Kettle";
- const result = await parse(source);
+ const source = "[Group] sky, is large, emperor";
+ const result = parse(source);
assert.deepStrictEqual(result.entities[0].components, [
- "Tea",
- "Cup",
- "Kettle",
+ "sky",
+ "is large",
+ "emperor",
]);
});
});
describe("inertia", () => {
it("should parse inertia", async () => {
- const source = "[Inertia] Tea";
- const result = await parse(source);
+ const source = "[Inertia] Print Media";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 1);
assert.strictEqual(result.entities[0].type, "inertia");
- assert.strictEqual(result.entities[0].component, "Tea");
+ assert.strictEqual(result.entities[0].component, "Print Media");
});
it("should handle case insensitive inertia keyword", async () => {
- const source = "[inertia] Tea";
- const result = await parse(source);
+ const source = "[inertia] Yes";
+ const result = parse(source);
assert.strictEqual(result.entities[0].type, "inertia");
});
it("should preserve case in inertia component label", async () => {
- const source = "[INERTIA] MyTea";
- const result = await parse(source);
+ const source = "[INERTIA] SpOnGeBoB";
+ const result = parse(source);
- assert.strictEqual(result.entities[0].component, "MyTea");
+ assert.strictEqual(result.entities[0].component, "SpOnGeBoB");
});
});
describe("evolution", () => {
it("should parse evolution with positive sign", async () => {
- const source = "[Evolution] Tea + 0.5";
- const result = await parse(source);
+ const source = "[Evolution] Nanomachines + 0.5";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 1);
assert.strictEqual(result.entities[0].type, "evolution");
- assert.strictEqual(result.entities[0].component, "Tea");
- assert.strictEqual(result.entities[0].isPositive, true);
+ assert.strictEqual(result.entities[0].component, "Nanomachines");
assert.strictEqual(result.entities[0].value, 0.5);
});
it("should parse evolution with negative sign", async () => {
- const source = "[Evolution] Tea - 0.3";
- const result = await parse(source);
+ const source = "[Evolution] FOXDIE - 0.3";
+ const result = parse(source);
- assert.strictEqual(result.entities[0].isPositive, false);
- assert.strictEqual(result.entities[0].value, 0.3);
+ assert.strictEqual(result.entities[0].value, -0.3);
});
it("should handle case insensitive evolution keyword", async () => {
- const source = "[evolution] Tea + 0.5";
- const result = await parse(source);
+ const source = "[evolution] tamales + 0.73";
+ const result = parse(source);
assert.strictEqual(result.entities[0].type, "evolution");
});
it("should preserve case in evolution component label", async () => {
- const source = "[EVOLUTION] MyTea - 0.2";
- const result = await parse(source);
+ const source = "[EVOLUTION] iMac - 0.2";
+ const result = parse(source);
- assert.strictEqual(result.entities[0].component, "MyTea");
+ assert.strictEqual(result.entities[0].component, "iMac");
});
it("should handle decimal evolution values", async () => {
- const source = "[Evolution] Tea + .75";
- const result = await parse(source);
+ const source = "[Evolution] Numerals + .75";
+ const result = parse(source);
assert.strictEqual(result.entities[0].value, 0.75);
});
@@ -322,10 +320,10 @@ describe("wmap parser", () => {
describe("multiple entities", () => {
it("should parse multiple entities", async () => {
- const source = `Tea (0.9, 0.5)
-Cup (0.8, 0.4)
-Tea -> Cup`;
- const result = await parse(source);
+ const source = `Water (0.9, 0.5)
+Bucket (0.8, 0.4) [x]
+Water -> Bucket`;
+ const result = parse(source);
assert.strictEqual(result.entities.length, 3);
assert.strictEqual(result.entities[0].type, "component");
@@ -334,46 +332,46 @@ Tea -> Cup`;
});
it("should handle different line endings (LF)", async () => {
- const source = "Tea (0.9, 0.5)\nCup (0.8, 0.4)";
- const result = await parse(source);
+ const source = "Penguins (0.9, 0.5)\nI Use Arch BTW (0.8, 0.4)";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 2);
});
it("should handle different line endings (CRLF)", async () => {
- const source = "Tea (0.9, 0.5)\r\nCup (0.8, 0.4)";
- const result = await parse(source);
+ const source = "Clippy (0.9, 0.5)\r\nSpace Cadet (0.8, 0.4)";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 2);
});
it("should handle different line endings (CR)", async () => {
- const source = "Tea (0.9, 0.5)\rCup (0.8, 0.4)";
- const result = await parse(source);
+ const source = "SE/30 (0.9, 0.5)\rPerforma (0.8, 0.4)";
+ const result = parse(source);
assert.strictEqual(result.entities.length, 2);
});
it("should handle empty lines", async () => {
- const source = `Tea (0.9, 0.5)
+ const source = `The Void (0.9, 0.5)
-Cup (0.8, 0.4)`;
- const result = await parse(source);
+The Abyss (0.8, 0.4)`;
+ const result = parse(source);
assert.strictEqual(result.entities.length, 2);
});
it("should ignore invalid lines", async () => {
- const source = `Tea (0.9, 0.5)
-This is invalid
-Cup (0.8, 0.4)
-Another invalid line
-Tea -> Cup`;
- const result = await parse(source);
+ const source = `Hello (0.9, 0.5)
+Oh No
+It's OK (0.8, 0.4)
+NO IT ISN'T
+Hello -> It's OK`;
+ const result = parse(source);
assert.strictEqual(result.entities.length, 3);
- assert.strictEqual(result.entities[0].label, "Tea");
- assert.strictEqual(result.entities[1].label, "Cup");
+ assert.strictEqual(result.entities[0].label, "Hello");
+ assert.strictEqual(result.entities[1].label, "It's OK");
assert.strictEqual(result.entities[2].type, "dependency");
});
});
@@ -381,32 +379,32 @@ Tea -> Cup`;
describe("edge cases", () => {
it("should handle empty input", async () => {
const source = "";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities.length, 0);
});
it("should handle only whitespace", async () => {
const source = " \n \n ";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities.length, 0);
});
it("should handle only invalid lines", async () => {
const source = "invalid\nstill invalid";
- const result = await parse(source);
+ const result = parse(source);
assert.strictEqual(result.entities.length, 0);
});
it("should handle complex component labels", async () => {
- const source = "My Super Complex Label 123 (0.5, 0.5)";
- const result = await parse(source);
+ const source = "My Sü'per Complex Label 123 (0.5, 0.5)";
+ const result = parse(source);
assert.strictEqual(
result.entities[0].label,
- "My Super Complex Label 123",
+ "My Sü'per Complex Label 123",
);
});
});
@@ -433,7 +431,7 @@ Kettle -> Hot Water
[Inertia] Kettle
[Evolution] Tea + 0.1`;
- const result = await parse(source);
+ const result = parse(source);
// 4 stages + 4 components + 3 dependencies + 1 note + 1 group + 1 inertia + 1 evolution = 15
assert.strictEqual(result.entities.length, 15);