UNPKG

joicomponents

Version:

Design patterns to build native web components

411 lines (380 loc) 17.2 kB
import {HashDots, HashDotMap} from "../../src/router/HashDot.js"; describe("parseHashDot", function () { it("empty test", function () { expect(HashDots.parse("")).to.deep.equal([]); }); it("basic test: #omg.what.is.'this:!#...#'##wtf/OMG123.123", function () { const res = HashDots.parse("#omg.what.is.'this:!#...#'##wtf/OMG123.123")[0]; expect(res.left).to.deep.equal([ { "tagName": "#omg", "tagValue": "omg", "args": [".what", ".is", ".'this:!#...#'"], flatArgs: ["what", "is", "this:!#...#"] }, { "tagName": "##wtf", "tagValue": "wtf", args: [], flatArgs: [] }, { "tagName": "/OMG123", "tagValue": "OMG123", "args": [".123"], "flatArgs": ["123"] } ]); }); it("parameter: !omg:what", function () { const res = HashDots.parse("!omg:what")[0]; expect(res.left).to.deep.equal([ { "tagName": "!omg", "tagValue": "omg", "args": [":what-1"], "flatArgs": [undefined] }]); }); it("parameter: #!/wtf::A", function () { const res = HashDots.parse("#!/wtf::A")[0]; expect(res.left).to.deep.equal([ { "tagName": "#!/wtf", "tagValue": "wtf", "args": "::A-2", "flatArgs": [] }]); }); it("Whitespace", () => { const a = HashDots.parse(" #white.abc#inBetween")[0]; const b = HashDots.parse("#white.abc#inBetween ")[0]; expect(a).to.deep.equal(b); const c = HashDots.parse("#white.abc #inBetween")[0]; expect(a).to.deep.equal(c); const d = HashDots.parse("#white .abc#inBetween")[0]; expect(a).to.deep.equal(d); }); it(`String: #singlestring.'\\''`, function () { const res = HashDots.parse(`#singlestring.'\\''`)[0]; expect(res.left).to.deep.equal([{ "tagName": "#singlestring", "tagValue": "singlestring", "args": [".'\\''"], "flatArgs": ["'"] }]); }); it(`String: #doublestring."\\""`, function () { const res = HashDots.parse(`#doublestring."\\""`)[0]; expect(res.left).to.deep.equal([{ "tagName": "#doublestring", "tagValue": "doublestring", "args": [".\"\\\"\""], "flatArgs": ["\""] }]); }); it("#one.'a single \\' string?¤#'.end", function () { const res = HashDots.parse("#one.'a single \\' string?¤#'.end")[0]; expect(res.left).to.deep.equal([{ "tagName": "#one", "tagValue": "one", "args": [".'a single \\' string?¤#'", ".end"], "flatArgs": ["a single ' string?¤#", "end"] }]); }); it('#one."a double \\" string?¤#".end', function () { const res = HashDots.parse('#one."a double \\" string?¤#".end')[0]; expect(res.left).to.deep.equal([{ "tagName": "#one", "tagValue": "one", "args": [".\"a double \\\" string?¤#\"", ".end"], "flatArgs": ["a double \" string?¤#", "end"] }]); }); it('#one;#two', function () { const res = HashDots.parse('#one;#two'); expect(res).to.deep.equal([{ left: [{ tagName: "#one", tagValue: "one", args: [], flatArgs: [] }] }, { left: [{ tagName: "#two", tagValue: "two", args: [], flatArgs: [] }] }]); }); it(';#one;', function () { const res = HashDots.parse(';#one;'); expect(res).to.deep.equal([{ left: [{ tagName: "#one", tagValue: "one", args: [], flatArgs: [] }] }]); }); }); describe("HashDotMatch", function () { it("HashDots.subsetMatch(#one:A:B, #one.a.b)", function () { const res = HashDots.subsetMatch(HashDots.parse("#one:A:B")[0].left, HashDots.parse("#one.a.b")[0].left); expect(res.start).to.be.equal(0); expect(res.varMap).to.deep.equal({":A-13": ".a", ":B-13": ".b"}); }); it(`HashDots.subsetMatch(#one:A:B, #one.'hello'."world")`, function () { const res = HashDots.subsetMatch(HashDots.parse("#one:A:B")[0].left, HashDots.parse(`#one.'hello'."world"`)[0].left); expect(res.start).to.be.equal(0); expect(res.varMap).to.deep.equal({":A-15": ".'hello'", ":B-15": '."world"'}); }); it("HashDots.subsetMatch(#one.a.b, #one:A:B)", function () { const res = HashDots.subsetMatch(HashDots.parse("#one.a.b")[0].left, HashDots.parse("#one:A:B")[0].left); expect(res.start).to.be.equal(0); expect(res.varMap).to.deep.equal({":A-18": ".a", ":B-18": ".b"}); }); it("HashDots.subsetMatch(#one.a.b.с#two.lala, #one:A:B:C#two:LALA)", function () { const res = HashDots.subsetMatch(HashDots.parse("#one.a.b.c#two.lala")[0].left, HashDots.parse("#one:A:B:C#two:LALA")[0].left); expect(res.start).to.be.equal(0); expect(res.varMap).to.deep.equal({":A-20": ".a", ":B-20": ".b", ":C-20": ".c", ":LALA-20": ".lala"}); }); it("HashDots.subsetMatch(#one.a.b.с#two.lala, #one::ALL)", function () { const res = HashDots.subsetMatch(HashDots.parse("#one.a.b.c#two.lala")[0].left, HashDots.parse("#one::ALL")[0].left); expect(res.start).to.be.equal(0); expect(res.stop).to.be.equal(1); assert(Object.keys(res.varMap)[0].match(/::ALL-\d+/)); expect(Object.values(res.varMap)[0]).to.deep.equal([".a", ".b", ".c"]); }); it("HashDots.subsetMatch: equal tag names, but unequal tag length", function () { let res = HashDots.subsetMatch(HashDots.parse("#one.a#two.b.error")[0].left, HashDots.parse("#one:A#two:B:C:D")[0].left); expect(res).to.be.equal(null); res = HashDots.subsetMatch(HashDots.parse("#one.a.b")[0].left, HashDots.parse("#one.a.b.c")[0].left); expect(res).to.be.equal(null); res = HashDots.subsetMatch(HashDots.parse("#one:A.b")[0].left, HashDots.parse("#one.a:B.c")[0].left); expect(res).to.be.equal(null); res = HashDots.subsetMatch(HashDots.parse("#one:A:B")[0].left, HashDots.parse("#one.a:B:C")[0].left); expect(res).to.be.equal(null); res = HashDots.subsetMatch(HashDots.parse("#one")[0].left, HashDots.parse("#one.a")[0].left); expect(res).to.be.equal(null); res = HashDots.subsetMatch(HashDots.parse("#one")[0].left, HashDots.parse("#one:A")[0].left); expect(res).to.be.equal(null); }); it("HashDots.subsetMatch: equal tag names, but unequal parity", function () { const res = HashDots.subsetMatch(HashDots.parse("#one.a#two.b.error")[0].left, HashDots.parse("#one:A#two:B:C:D")[0].left); expect(res).to.be.equal(null); }); it("HashDots.subsetMatch with the same variable name on both sides: #one:A#two.b = #one.c#two:A", function () { const res = HashDots.subsetMatch(HashDots.parse("#one:A#two.b")[0].left, HashDots.parse("#one.c#two:A")[0].left); expect(res.start).to.be.equal(0); expect(res.stop).to.be.equal(2); expect(res.varMap).to.deep.equal({':A-37': '.c', ':A-38': '.b'}); }); it("HashDots.subsetMatch on the second occurence: #one#two#three#one#four, #one#four", function () { const res = HashDots.subsetMatch(HashDots.parse("#one#two#three#one#four")[0].left, HashDots.parse("#one#four")[0].left); expect(res.start).to.be.equal(3); expect(res.stop).to.be.equal(2); expect(res.varMap).to.deep.equal({}); }); }); describe("HashDotMap.transform & .transform(..).first()", function () { it("HashDotMap.make()", function () { const map = HashDotMap.make("#one:A:B = #two:A#three:B"); expect(map._rules[0]).to.deep.equal({ "left": [{ "tagName": "#one", "tagValue": "one", "args": [":A-41", ":B-41"], "flatArgs": [undefined, undefined] }], "right": [{ "tagName": "#two", "tagValue": "two", "args": [":A-41"], "flatArgs": [undefined] }, { "tagName": "#three", "tagValue": "three", "args": [":B-41"], "flatArgs": [undefined] }] }); }); it("#one:A:B = #two:A#three:B", function () { const routeMap = HashDotMap.make("#one:A:B = #two:A#three:B"); let res = Array.from(routeMap.query("#one.a.b").ruleIsSubsetOfQuery().transform().first()); expect(res.map(dot => dot.toString())).to.deep.equal(['#two.a', '#three.b']); res = routeMap.query("#two.a#three.b").reverse().ruleIsSubsetOfQuery().transform().first(); expect(res.map(dot => dot.toString())).to.deep.equal(['#one.a.b']); }); it("#one:A:B = #two:A#three:B; #alpha = #one::X#x", function () { const routeMap = HashDotMap.make("#one:A:B = #two:A#three:B; #alpha = #one::X#x"); const res = Array.from(routeMap.query("#three.b").reverse().queryIsSubsetOfRule().recursive()); expect(res.map(dot => dot.toString())).to.deep.equal(["#one:A-45.b", "#alpha"]); }); it("#one:A:B = #two:A#three:B", function () { const routeMap = HashDotMap.make("#one:A:B = #two:A#three:B"); let res = Array.from(routeMap.query(`#one."hello"."world"`).transform().first()); expect(res.map(dot => dot.toString())).to.deep.equal(['#two."hello"', '#three."world"']); res = Array.from(routeMap.query(`#two.'hello'#three."world"`).reverse().transform().first()); expect(res.map(dot => dot.toString())).to.deep.equal(['#one.\'hello\'."world"']); expect(res[0].flatArgs).to.deep.equal(["hello", "world"]); }); it("#nothing#one:A:B = #two:A#three:B", function () { const routeMap = HashDotMap.make("#nothing#one:A:B = #two:A#three:B"); let res = Array.from(routeMap.query("#nothing#one.a.b").ruleIsSubsetOfQuery().transform().first()); expect(res.map(dot => dot.toString())).to.deep.equal(['#two.a', '#three.b']); res = Array.from(routeMap.query("#two.a#three.b").reverse().ruleIsSubsetOfQuery().transform().first()); expect(res.map(dot => dot.toString())).to.deep.equal(['#nothing', '#one.a.b']); }); it("#one::A = #two::A", function () { const routeMap = HashDotMap.make("#one::A = #two::A"); let res = Array.from(routeMap.query("#one.a.b").ruleIsSubsetOfQuery().transform().first()); expect(res.map(dot => dot.toString())).to.deep.equal(["#two.a.b"]); res = Array.from(routeMap.query("#two.a.b.c").reverse().ruleIsSubsetOfQuery().transform().first()); expect(res.map(dot => dot.toString())).to.deep.equal(["#one.a.b.c"]); }); it("#red:A = #orange:A ; #orange:B = #yellow:B", function () { const routeMap = HashDotMap.make("#red:A = #orange:A; #orange:B = #yellow:B"); let res = Array.from(routeMap.query("#red.re").ruleIsSubsetOfQuery().transform().recursive()); expect(res.map(dot => dot.toString())).to.deep.equal(["#orange.re", "#yellow.re"]); res = Array.from(routeMap.query("#yellow.ye").reverse().ruleIsSubsetOfQuery().transform().recursive()); expect(res.map(dot => dot.toString())).to.deep.equal(["#orange.ye", "#red.ye"]); }); it("#red:A = #orange:A ; #orange:A = #yellow:A (Same variable name across different HashDot statements)", function () { const routeMap = HashDotMap.make("#red:A = #orange:A; #orange:A = #yellow:A"); let res = Array.from(routeMap.query("#red.re").ruleIsSubsetOfQuery().transform().recursive()); expect(res.map(dot => dot.toString())).to.deep.equal(["#orange.re", "#yellow.re"]); res = Array.from(routeMap.query("#yellow.ye").reverse().ruleIsSubsetOfQuery().transform().recursive()); expect(res.map(dot => dot.toString())).to.deep.equal(['#orange.ye', '#red.ye']); }); it("#a:X = #aa:X ; #b:X = #bb:X ; #a:X#b:Y = #cc:X:Y (Rule order is preserved and given priority)", function () { const routeMap = HashDotMap.make("#a:A = #aa:A; #b:B = #bb:B; #a:A#b:B = #cc:A:B"); let res = Array.from(routeMap.query("#a.1#b.2").ruleIsSubsetOfQuery().transform().recursive()); expect(res.map(dot => dot.toString())).to.deep.equal(['#aa.1,#b.2', '#aa.1,#bb.2']); res = Array.from(routeMap.query("#cc.1.2").reverse().ruleIsSubsetOfQuery().transform().recursive()); expect(res.map(dot => dot.toString())).to.deep.equal(['#a.1,#b.2']); }); it("#b:X = #c:X ; #a:X = #b:X (Rule order problem for variables)", function () { const routeMap = HashDotMap.make("#b:A = #c:A; #a:A = #b:A"); let res = Array.from(routeMap.query("#a.1").ruleIsSubsetOfQuery().transform().recursive()); expect(res.map(dot => dot.toString())).to.deep.equal(['#b.1', '#c.1']); }); it("#x = #y ; #a = #x ; #b = #a (Need to run the same rule twice)", function () { const routeMap = HashDotMap.make("#x = #y; #a = #x; #b = #a"); const right = routeMap.query("#a#b").ruleIsSubsetOfQuery().transform().recursive(); const res = Array.from(right); expect(res.map(dots => dots.map(dot => dot.toString()).join(""))).to.deep.equal(["#x#b", "#y#b", "#y#a", "#y#x", "#y#y"]); }); it("#a#x = #y.1 ; #c#x = #y.2 ; #b = #x ; #d = #x (Need to output the same hashtag with different parameters)", function () { const routeMap = HashDotMap.make("#a#x = #y.1; #c#x = #y.2; #b = #x; #d = #x"); const right = routeMap.query("#a#b#c#d").ruleIsSubsetOfQuery().transform().recursive(); const res = Array.from(right); const map = res.map(dots => dots.map(dot => dot.toString()).join("")); expect(map).to.deep.equal(["#a#x#c#d","#y.1#c#d", "#y.1#c#x", "#y.1#y.2"]); }); }); describe("new Resolvers", function () { it("resolveRight: #book = #chp.1#chp.2#chp.3 ; #chp.1 = #chp.1.1#chp.1.2#chp.1.3", function () { const routeMap = HashDotMap.make("#book = #chp.1#chp.2#chp.3; #chp.1 = #chp.1.1#chp.1.2#chp.1.3"); for (let r of routeMap.query("#book")) expect(r.map(dot => dot.toString()).join("")).to.be.equal("#chp.1#chp.2#chp.3"); for (let r of routeMap.query("#book#test.abc").ruleIsSubsetOfQuery().transform()) expect(r.map(dot => dot.toString()).join("")).to.be.equal("#chp.1#chp.2#chp.3#test.abc"); for (let r of routeMap.query("#test.abc#book").ruleIsSubsetOfQuery().transform()) expect(r.map(dot => dot.toString()).join("")).to.be.equal("#test.abc#chp.1#chp.2#chp.3"); }); it("HashDotMap.resolver('#chp:X')", function () { const rules = ` #chp.1 = #txt.hello; #chp.2 = #txt.world; #chp.1.1 = #txt.go; #chp.1.2 = #txt.figure`; const routeMap = HashDotMap.make(rules); let res = ["#chp.1", "#chp.2"]; for (let r of routeMap.query("#chp:X").find()) expect(r.map(dot => dot.toString()).join("")).to.be.equal(res.shift()); res = ["#chp.1.1", "#chp.1.2"]; for (let r of routeMap.query("#chp:X:Y").find()) expect(r.map(dot => dot.toString()).join("")).to.be.equal(res.shift()); res = ["#chp.1.1"]; for (let r of routeMap.query("#chp:X:X").find()) expect(r.map(dot => dot.toString()).join("")).to.be.equal(res.shift()); res = ["#chp.1.1", "#chp.1.2"]; for (let r of routeMap.query("#chp.1:Y").find()) expect(r.map(dot => dot.toString()).join("")).to.be.equal(res.shift()); res = ["#chp.1", "#chp.2", "#chp.1.1", "#chp.1.2"]; for (let r of routeMap.query("#chp::X").find()) expect(r.map(dot => dot.toString()).join("")).to.be.equal(res.shift()); for (let r of routeMap.query("#chp.2:Y").find()) assert(false); }); }); describe("HashDotMap.resolver 2", function () { const rules = ` #book = #chp1#chp2; #chp.1 = #txt.hello#h1.something; #chp.2 = #txt.world; #chp.1.1 = #txt.go; #chp.1.2 = #txt.figure; #title#chp.1 = #long.'hello world'; `; }); describe("Syntactic errors (HashDots.parse())", function () { it("Several universal parameters", () => { try { HashDots.parse("#a::B::C"); assert(false); } catch (err) { expect(err.message).to.deep.equal("HashDot syntax error: DoubleDots '::' must be the only argument.\nInput: #a::B::C\nError: ↑"); } }); it("Line start with different symbol", () => { try { HashDots.parse(".error"); assert(false); } catch (err) { expect(err.message).to.deep.equal("HashDot sequence must start with #,!,/ or ;.\nInput: .error\nError: ↑"); } }); it("Line start without # and ends with different symbol", () => { try { HashDots.parse("error@"); assert(false); } catch (err) { expect(err.message).to.deep.equal("HashDot sequence must start with #,!,/ or ;.\nInput: error@\nError: ↑"); } }); it("Empty #", () => { try { HashDots.parse("#empty#"); assert(false); } catch (err) { expect(err.message).to.deep.equal("HashDot syntax error:\nInput: #empty#\nError: ↑"); } }); it("Empty .", () => { try { HashDots.parse("#empty."); assert(false); } catch (err) { expect(err.message).to.deep.equal("HashDot syntax error:\nInput: #empty.\nError: ↑"); } try { HashDots.parse("#no.missing.#args"); assert(false); } catch (err) { expect(err.message).to.deep.equal("HashDot syntax error:\nInput: #no.missing.#args\nError: ↑"); } }); it("HashDot wrong sequence", () => { try { HashDots.parse("#a.b c#d"); assert(false); } catch (err) { expect(err.message).to.deep.equal("HashDot syntax error:\nInput: #a.b c#d\nError: ↑"); } }); // HashDots.parse("#no#illegal.characters?%&¤,;:-_); });