UNPKG

attrpath

Version:
803 lines 42.5 kB
/** * Copyright © 2020 2021 2022 7thCode.(http://seventh-code.com/) * This software is released under the MIT License. * opensource.org/licenses/mit-license.php */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const base_1 = require("./base"); const index_1 = require("./index"); const handler_1 = require("./handler"); describe('base', () => { it('base', () => { expect((0, base_1.isNumber)(1)).toBe(true); expect((0, base_1.isContainer)({})).toBe(true); expect((0, base_1.isContainer)({ a: 1 })).toBe(true); expect((0, base_1.isContainer)([])).toBe(true); expect((0, base_1.isContainer)([1])).toBe(true); expect((0, base_1.isValue)({})).toBe(true); expect((0, base_1.isValue)(null)).toBe(false); expect((0, base_1.isValue)(undefined)).toBe(false); }); }); /** * for test */ describe('Parts', () => { it("ValueHandler", () => { class TestHandler extends index_1.ValueHandler { static sibling(array, index) { return index_1.ValueHandler.sibling(array, index); } static child(obj, index) { return index_1.ValueHandler.child(obj, index); } } expect(TestHandler.sibling([1, 2, 3, 4, 5], '2')).toStrictEqual(3); expect(TestHandler.child({ a: 1, b: 2, c: 3 }, 'b')).toStrictEqual(2); const handler = new index_1.ValueHandler({ a: "1" }); expect(handler.value).toStrictEqual({ a: "1" }); }); it("ParserStream", () => { const stream = new index_1.ParserStream("0123456789"); expect(stream.char).toBe("0"); expect(stream.charCode).toBe(48); stream.next(); expect(stream.char).toBe("1"); expect(stream.charCode).toBe(49); stream.restore_point(); stream.next(); stream.next(); stream.next(); expect(stream.current).toBe("123"); stream.restore_point(); stream.next(); stream.next(); stream.next(); expect(stream.current).toBe("456"); stream.restore(); stream.next(); stream.next(); stream.next(); expect(stream.current).toBe("456"); expect(stream.is_terminal).toBe(false); stream.next(); stream.next(); expect(stream.is_terminal).toBe(false); stream.next(); expect(stream.is_terminal).toBe(true); expect(stream.current).toBe("456789"); stream.next(); expect(stream.is_terminal).toBe(true); stream.next(); expect(stream.current).toBe("456789"); }); it("AttributeParser", () => { class TestParser extends index_1.AttributeParser { constructor(handler, stream) { super(handler, stream); } is_s() { return super.is_s(); } parse_s() { return super.parse_s(); } is_terminal() { return super.is_terminal(); } is_char(c) { return super.is_char(c); } //public is_symbol(): boolean { // return super.is_symbol(); //} is_digit() { return super.is_digit(); } parse_number() { return super.parse_number(); } is_reading() { return super.is_reading(); } is_trailing() { return super.is_trailing(); } is_subscript_trailing() { return super.is_subscript_trailing(); } parse_name() { return super.parse_name(); } parse_subscript_string() { return super.parse_subscript_string(); } parse_attr() { return super.parse_attr(); } parse_path() { return super.parse_path(); } // expr ::= term { { "+" | "-" } term } * is_expr() { return super.is_expr(); } // term ::= factor { { "*" | "/" } factor } * is_term() { return super.is_term(); } // factor ::= "(" expr ")" | number is_factor() { return super.is_factor(); } } expect(new TestParser(null, new index_1.ParserStream(" ")).is_s()).toBe(true); expect(new TestParser(null, new index_1.ParserStream(" ")).parse_s()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("")).is_terminal()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("A")).is_char("A")).toBe(true); // expect(new TestParser(null, new ParserStream(".")).is_symbol()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("0")).is_digit()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("123456")).parse_number()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("A")).is_reading()).toBe(true); expect(new TestParser(null, new index_1.ParserStream('z')).is_reading()).toBe(true); expect(new TestParser(null, new index_1.ParserStream(String.fromCharCode(0x2FFFF))).is_reading()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("0")).is_reading()).toBe(false); expect(new TestParser(null, new index_1.ParserStream("_")).is_reading()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("$")).is_reading()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("A")).is_trailing()).toBe(true); expect(new TestParser(null, new index_1.ParserStream('z')).is_trailing()).toBe(true); expect(new TestParser(null, new index_1.ParserStream(String.fromCharCode(0x2FFFF))).is_trailing()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("0")).is_trailing()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("_")).is_trailing()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("$")).is_trailing()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("ABCDE")).parse_name()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("1BCDE")).parse_name()).toBe(false); expect(new TestParser(null, new index_1.ParserStream("'ABCDE'")).parse_subscript_string()).toBe(true); expect(new TestParser(null, new index_1.ParserStream('"ABCDE"')).parse_subscript_string()).toBe(true); expect(new TestParser(null, new index_1.ParserStream(".ABCDE")).parse_attr()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("[0]")).parse_attr()).toBe(true); expect(new TestParser(null, new index_1.ParserStream("['ABC']")).parse_attr()).toBe(true); expect(new TestParser(null, new index_1.ParserStream('["ABC"]')).parse_attr()).toBe(true); expect(new TestParser(null, new index_1.ParserStream(".ABCDE")).parse_path()).toBe(true); expect(new TestParser(null, new index_1.ParserStream(".ABCDE.XYZ")).parse_path()).toBe(true); expect(new TestParser(null, new index_1.ParserStream(".ABCDE.XYZ[0]")).parse_path()).toBe(true); }); it("FormulaParser", () => { const _handler = new index_1.ValueHandler({}); // is_term メソッドを公開してテスト用に利用 class TermParser extends index_1.AttributeParser { constructor(handler, stream) { super(handler, stream); } is_term() { return super.is_term(); } is_factor() { return super.is_factor(); } } // is_expr メソッドも公開してより詳細なテスト class ExprParser extends index_1.AttributeParser { constructor(handler, stream) { super(handler, stream); } is_expr() { return super.is_expr(); } is_term() { return super.is_term(); } is_factor() { return super.is_factor(); } } // parser.ts:213-214の確実なカバレッジ: is_factor()がfalseを返すケース // 重要: 演算子の後にis_factor()がfalseになるが、すでにresult=trueのケース const testCases = [ "3*", "4/", "5*xyz", "6/xyz", "7* ", "8/ ", "9*!", "10/!" // スペースや記号は無効なfactor ]; testCases.forEach(testCase => { expect(new ExprParser(_handler, new index_1.ParserStream(testCase)).is_expr()).toBe(true); }); // 未カバー箇所のテスト: 乗算・除算演算子の後にfactorが続かない場合 // parser.ts:213-214の完全カバレッジのため、is_factor()がfalseになるケースをテスト expect(new TermParser(_handler, new index_1.ParserStream("1*(")).is_term()).toBe(true); // (で始まるが不完全 expect(new TermParser(_handler, new index_1.ParserStream("1/+")).is_term()).toBe(true); // +は無効なfactor開始 expect(new TermParser(_handler, new index_1.ParserStream("1* ")).is_term()).toBe(true); // スペースの後に何もない expect(new TermParser(_handler, new index_1.ParserStream("1/ ")).is_term()).toBe(true); // 複数スペースの後に何もない class FormParser extends index_1.AttributeParser { constructor(handler, stream) { super(handler, stream); } // factor ::= "(" expr ")" | number is_factor() { return super.is_factor(); } } expect(new FormParser(_handler, new index_1.ParserStream("1")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("1+1")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("1-1")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("1*1")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("1/1")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("(1+1)")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("(1+1+1)")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("(1+1-1)")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("(1+(1-1))")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("(1+(1-1))/1")).is_factor()).toBe(true); expect(new FormParser(_handler, new index_1.ParserStream("(1+(1-1)")).is_factor()).toBe(false); expect(new FormParser(_handler, new index_1.ParserStream(" ( 1 + ( 1 - 1 ) ) / 1 ")).is_factor()).toBe(true); }); }); /* * * ESModules * * */ describe('ESModule', () => { it('Basic', () => { const value = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; expect(index_1.AttrPath.traverse(value, '.children')).toStrictEqual({ "john": { "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }, "花子": { "hobby": [{ "name": "Squash" }], "pet": [{ "type": "cat", "name": "Chloe" }] } }); expect(index_1.AttrPath.traverse(value, '.children.john')).toStrictEqual({ "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }); expect(index_1.AttrPath.traverse(value, '.children.john.hobby')).toStrictEqual([{ "name": "Cycling" }, { "name": "Dance" }]); expect(index_1.AttrPath.traverse(value, '.children.john.hobby[0]')).toStrictEqual({ "name": "Cycling" }); expect(index_1.AttrPath.traverse(value, '.children.john.hobby[0].name')).toBe("Cycling"); expect(index_1.AttrPath.traverse(value, '.children.john.hobby[0a].name')).toBeUndefined(); expect(index_1.AttrPath.traverse(value, '.children.john.hobby[1].name')).toBe("Dance"); expect(index_1.AttrPath.traverse(value, '.children.john.pet[0].type')).toBe("dog"); expect(index_1.AttrPath.traverse(value, '.children.john.pet[0].name')).toBe("Max"); expect(index_1.AttrPath.traverse(value, '.children.花子.hobby[0].name')).toBe("Squash"); expect(index_1.AttrPath.traverse(value, '.children.花子.pet[0].type')).toBe("cat"); expect(index_1.AttrPath.traverse(value, '.children.花子.pet[0].name')).toBe("Chloe"); expect(index_1.AttrPath.traverse(value, '.children.john.hobby["0"].name')).toBeUndefined(); expect(index_1.AttrPath.traverse(value, '.children.john.hobby["0"].name', "no name")).toBe("no name"); expect(index_1.AttrPath.traverse(value, '.children["john"].hobby[0].name')).toBe("Cycling"); expect(index_1.AttrPath.traverse(value, '.children["john"].hobby[0]["name"]')).toBe("Cycling"); expect(index_1.AttrPath.traverse(value, '["children"]["john"].hobby[0].name')).toBe("Cycling"); expect(index_1.AttrPath.traverse(value, '.children["john"].hobby[0].name')).toBe("Cycling"); expect(index_1.AttrPath.traverse(value, '["children"]["john"]["hobby"][0]["name"]')).toBe("Cycling"); expect(index_1.AttrPath.traverse(value, '["children"]["john"]["hobby"][0].["name"]')).toBeUndefined(); expect(index_1.AttrPath.traverse(value, '["children"]["john"]["hobby"][0]["name"]')).toBe("Cycling"); expect(index_1.AttrPath.traverse(value, '.children["john"].hobby[1].name')).toBe("Dance"); expect(index_1.AttrPath.traverse([1], '[0]')).toBe(1); expect(index_1.AttrPath.traverse(index_1.AttrPath.traverse(value, '.children.john'), '.hobby')).toStrictEqual([{ "name": "Cycling" }, { "name": "Dance" }]); expect(index_1.AttrPath.traverse(null, '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse(null, '.path.path')).toBeUndefined(); expect(index_1.AttrPath.traverse(null, '["path"]')).toBeUndefined(); expect(index_1.AttrPath.traverse(null, '.path["path"]')).toBeUndefined(); expect(index_1.AttrPath.traverse(null, '["0"]')).toBeUndefined(); expect(index_1.AttrPath.traverse(null, '[0]')).toBeUndefined(); expect(index_1.AttrPath.traverse([1, 2, 3], '[3]')).toBeUndefined(); expect(index_1.AttrPath.traverse(undefined, '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse(false, '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse(true, '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse(NaN, '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse(Infinity, '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse(0, '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse(-1, '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse("", '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse("1", '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse([1], '.path')).toBeUndefined(); expect(index_1.AttrPath.traverse({}, '.path')).toBeUndefined(); }); it('Performance', () => { const value = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; const start = process.hrtime(); index_1.AttrPath.traverse(value, '.children'); index_1.AttrPath.traverse(value, '.children.john'); index_1.AttrPath.traverse(value, '.children.john.hobby'); index_1.AttrPath.traverse(value, '.children.john.hobby[0]'); index_1.AttrPath.traverse(value, '.children.john.hobby[0].name'); index_1.AttrPath.traverse(value, '.children.john.hobby[0a].name'); index_1.AttrPath.traverse(value, '.children.john.hobby[1].name'); index_1.AttrPath.traverse(value, '.children.john.pet[0].type'); index_1.AttrPath.traverse(value, '.children.john.pet[0].name'); index_1.AttrPath.traverse(value, '.children.花子.hobby[0].name'); index_1.AttrPath.traverse(value, '.children.花子.pet[0].type'); index_1.AttrPath.traverse(value, '.children.花子.pet[0].name'); index_1.AttrPath.traverse(value, '.children.john.hobby["0"].name'); index_1.AttrPath.traverse(value, '.children.john.hobby["0"].name', "no name"); index_1.AttrPath.traverse(value, '.children["john"].hobby[0].name'); index_1.AttrPath.traverse(value, '.children["john"].hobby[0]["name"]'); index_1.AttrPath.traverse(value, '["children"]["john"].hobby[0].name'); index_1.AttrPath.traverse(value, '.children["john"].hobby[0].name'); index_1.AttrPath.traverse(value, '["children"]["john"]["hobby"][0]["name"]'); index_1.AttrPath.traverse(value, '["children"]["john"]["hobby"][0].["name"]'); index_1.AttrPath.traverse(value, '["children"]["john"]["hobby"][0]["name"]'); index_1.AttrPath.traverse(value, '.children["john"].hobby[1].name'); index_1.AttrPath.traverse([1], '[0]'); index_1.AttrPath.traverse(index_1.AttrPath.traverse(value, '.children.john'), '.hobby'); index_1.AttrPath.traverse(null, '.path'); index_1.AttrPath.traverse(null, '.path.path'); index_1.AttrPath.traverse(null, '["path"]'); index_1.AttrPath.traverse(null, '.path["path"]'); index_1.AttrPath.traverse(null, '["0"]'); index_1.AttrPath.traverse(null, '[0]'); index_1.AttrPath.traverse([1, 2, 3], '[3]'); index_1.AttrPath.traverse(undefined, '.path'); index_1.AttrPath.traverse(false, '.path'); index_1.AttrPath.traverse(true, '.path'); index_1.AttrPath.traverse(NaN, '.path'); index_1.AttrPath.traverse(Infinity, '.path'); index_1.AttrPath.traverse(0, '.path'); index_1.AttrPath.traverse(-1, '.path'); index_1.AttrPath.traverse("", '.path'); index_1.AttrPath.traverse("1", '.path'); index_1.AttrPath.traverse([1], '.path'); index_1.AttrPath.traverse({}, '.path'); const end = process.hrtime(start); console.log((end[1] / 1000000) + "ms"); }); it('Key', () => { const value = { children1: { john2: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, "花子2": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; expect(index_1.AttrPath.traverse(value, '.children1')).toStrictEqual({ "john2": { "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }, "花子2": { "hobby": [{ "name": "Squash" }], "pet": [{ "type": "cat", "name": "Chloe" }] } }); }); it("!'[]^`", () => { // "!" "'" "[" "]" "^" "`" const value = [ { irrigal: { "contains!": [{ name: "NG" }], "contains'": [{ name: "NG" }], "contains[": [{ name: "NG" }], "contains]": [{ name: "NG" }], "contains^": [{ name: "NG" }], "contains`": [{ name: "NG" }], }, } ]; expect(index_1.AttrPath.traverse(value, '[0].irrigal.contains![0].name')).toBeUndefined(); expect(index_1.AttrPath.traverse(value, "[0].irrigal.contains'[0].name")).toBeUndefined(); expect(index_1.AttrPath.traverse(value, '[0].irrigal.contains[[0].name')).toBeUndefined(); expect(index_1.AttrPath.traverse(value, '[0].irrigal.contains][0].name')).toBeUndefined(); expect(index_1.AttrPath.traverse(value, '[0].irrigal.contains^[0].name')).toBeUndefined(); expect(index_1.AttrPath.traverse(value, '[0].irrigal.contains`[0].name')).toBeUndefined(); }); it('Symbol Value', () => { const symbol = Symbol(); const value = [ { john: { "hobby": [{ name: symbol }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, } ]; expect(index_1.AttrPath.traverse(value, '[0].john.hobby[0].name')).toBe(symbol); }); it('Computed Key', () => { const name = "john"; const value = { [name]: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] } }; expect(index_1.AttrPath.traverse(value, '["john"]')).toBe(value[name]); expect(index_1.AttrPath.traverse(value, '["' + name + '"]')).toBe(value[name]); expect(index_1.AttrPath.traverse(value, '["john"]')).toStrictEqual({ "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }); }); it('A.B Key', () => { const value = { "john.data": { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] } }; expect(index_1.AttrPath.is_valid('["john.data"]')).toBe(true); expect(index_1.AttrPath.traverse(value, '["john.data"]')).toBe(value["john.data"]); expect(index_1.AttrPath.traverse(value, '["john.data"]')).toStrictEqual({ "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }); }); it('MBCS Key', () => { const value = { "漢字": { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] } }; expect(index_1.AttrPath.traverse(value, '["漢字"]')).toBe(value["漢字"]); }); it('Update', () => { const before = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; const after = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Breaking" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; index_1.AttrPath.traverse(before, '.children.john.hobby[1]').name = "Breaking"; expect(before).toStrictEqual(after); const after2 = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Breaking" }, { name: "Game" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; index_1.AttrPath.traverse(after, '.children.john.hobby').push({ name: "Game" }); expect(after).toStrictEqual(after2); }); it('Update', () => { // under constuction. const before = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] } } }; const after = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Tennis" }], pet: [{ type: "cat", name: "Chloe" }] } }, }; expect(index_1.AttrPath.update(before, '.children.花子', { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] })).toBeTruthy(); expect(index_1.AttrPath.update(before, '.children.花子.hobby[0]', { name: "Tennis" })).toBeTruthy(); expect(index_1.AttrPath.update(before, '.children.花子.hobby[1]', { name: "Swimming" })).toBeTruthy(); expect(index_1.AttrPath.update(before, '.there.is.nothing', { name: "Do Nothing" })).toBeFalsy(); // under constuction. }); it('Valid', () => { expect(index_1.AttrPath.is_valid('[1]')).toBe(true); expect(index_1.AttrPath.is_valid('["john"]')).toBe(true); expect(index_1.AttrPath.is_valid('.children["john"].hobby[1].name')).toBe(true); expect(index_1.AttrPath.is_valid('.children["john"].hobby[1a].name')).toBe(false); expect(index_1.AttrPath.is_valid('.children["john"].hobby["1"].name')).toBe(false); expect(index_1.AttrPath.is_valid('this.name')).toBe(false); }); it('Classes', () => { const value = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] }, _jack$: { _hobby$: [{ $name: "Fury" }], $pet$: [{ type_: "bat", $name: "Dread" }] } } }; function Traverse(obj, path) { let result = undefined; const _handler = new index_1.ValueHandler(obj); if (new index_1.AttributeParser(_handler, new index_1.ParserStream(path)).parse_path()) { result = _handler.value; } return result; } function isValid(path) { return new index_1.AttributeParser(null, new index_1.ParserStream(path)).parse_path(); } expect(Traverse(value, '.children')).toStrictEqual({ "john": { "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }, "花子": { "hobby": [{ "name": "Squash" }], "pet": [{ "type": "cat", "name": "Chloe" }] }, _jack$: { _hobby$: [{ $name: "Fury" }], $pet$: [{ type_: "bat", $name: "Dread" }] } }); expect(Traverse(value, '.children.john')).toStrictEqual({ "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }); expect(Traverse(value, '.children.john.hobby')).toStrictEqual([{ "name": "Cycling" }, { "name": "Dance" }]); expect(Traverse(value, '.children.john.hobby[0]')).toStrictEqual({ "name": "Cycling" }); expect(Traverse(value, '.children.john.hobby[0].name')).toBe("Cycling"); expect(Traverse(value, '.children.john.hobby[0a].name')).toBeUndefined(); expect(Traverse(value, '.children.john.hobby[1].name')).toBe("Dance"); expect(Traverse(value, '.children.john.pet[0].type')).toBe("dog"); expect(Traverse(value, '.children.john.pet[0].name')).toBe("Max"); expect(Traverse(value, '.children.花子.hobby[0].name')).toBe("Squash"); expect(Traverse(value, '.children.花子.pet[0].type')).toBe("cat"); expect(Traverse(value, '.children.花子.pet[0].name')).toBe("Chloe"); expect(Traverse(value, '.children.john.hobby["0"].name')).toBeUndefined(); expect(Traverse(value, '.children["john"].hobby[0].name')).toBe("Cycling"); expect(Traverse(value, '.children["john"].hobby[0]["name"]')).toBe("Cycling"); expect(Traverse(value, '["children"]["john"].hobby[0].name')).toBe("Cycling"); expect(Traverse(value, '.children["john"].hobby[0].name')).toBe("Cycling"); expect(Traverse(value, '["children"]["john"]["hobby"][0]["name"]')).toBe("Cycling"); expect(Traverse(value, '["children"]["john"]["hobby"][0].["name"]')).toBeUndefined(); expect(Traverse(value, '["children"]["john"]["hobby"][0]["name"]')).toBe("Cycling"); expect(Traverse(value, '.children["john"].hobby[1].name')).toBe("Dance"); expect(isValid('.children["john"].hobby[1].name')).toBe(true); expect(isValid('.children["john"].hobby[1a].name')).toBe(false); expect(isValid('.children["john"].hobby["1"].name')).toBe(false); expect(Traverse(value, '.children._jack$._hobby$[0].$name')).toBe("Fury"); expect(Traverse(value, '.children._jack$.$pet$[0].$name')).toBe("Dread"); }); it('Extends', () => { class Klass { constructor() { this.member = "name"; } Member() { return index_1.AttrPath.traverse(this, '.member'); } } const klass = new Klass(); expect(klass.Member()).toBe("name"); class ParentKlass { constructor() { this.member = "name"; } } class SubKlass extends ParentKlass { Member() { return index_1.AttrPath.traverse(this, '.member'); } } const sub_klass = new SubKlass(); expect(sub_klass.Member()).toBe("name"); }); }); /* * * CommonJS * * */ describe('CommonJS', () => { it('Basic', () => { var _a, _b, _c; const { AttrPath } = require('./index'); const value = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; expect(AttrPath.traverse(value, '.children')).toStrictEqual({ "john": { "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }, "花子": { "hobby": [{ "name": "Squash" }], "pet": [{ "type": "cat", "name": "Chloe" }] } }); expect(AttrPath.traverse(value, '.children')).toStrictEqual(value.children); expect(AttrPath.traverse(value, '.children.john')).toStrictEqual({ "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }); expect(AttrPath.traverse(value, '.children.john')).toStrictEqual(value.children.john); expect(AttrPath.traverse(value, '.children.john.hobby')).toStrictEqual([{ "name": "Cycling" }, { "name": "Dance" }]); expect(AttrPath.traverse(value, '.children.john.hobby')).toStrictEqual(value.children.john.hobby); expect(AttrPath.traverse(value, '.children.john.hobby[0]')).toStrictEqual({ "name": "Cycling" }); expect(AttrPath.traverse(value, '.children.john.hobby[0]')).toStrictEqual(value.children.john.hobby[0]); expect(AttrPath.traverse(value, '.children.john.hobby[0].name')).toBe("Cycling"); expect(AttrPath.traverse(value, '.children.john.hobby[0].name')).toBe(value.children.john.hobby[0].name); expect(AttrPath.traverse(value, '.children.john.hobby["0"].name')).toBeUndefined(); expect(AttrPath.traverse(value, '.children.john.hobby[0a].name')).toBeUndefined(); expect(AttrPath.traverse(value, '.children.john.hobby["0"].name', "no name")).toBe("no name"); expect(AttrPath.traverse(value, '.children.john.hobby[a].name', "no name")).toBe("no name"); const Default = (n) => { return n; }; expect(AttrPath.traverse(value, '.children.john.hobby["0"].name', Default(1))).toBe(1); expect(AttrPath.traverse(value, '.children.john.hobby[a].name', Default(1))).toBe(1); const Result = (param) => { return (result) => { expect(result).toBe(param); }; }; expect(AttrPath.traverse(value, '.children.john.hobby[1].name', Result("Dance"))).toBe(null); expect(AttrPath.traverse(value, '.children.john.pet[0].type', Result("dog"))).toBe(null); expect(AttrPath.traverse(value, '.children.john.hobby[1].name')).toBe("Dance"); expect(AttrPath.traverse(value, '.children.john.pet[0].type')).toBe("dog"); expect(AttrPath.traverse(value, '.children.john.pet[0].name')).toBe("Max"); expect(AttrPath.traverse(value, '.children.花子.hobby[0].name')).toBe("Squash"); expect(AttrPath.traverse(value, '.children.花子.pet[0].type')).toBe("cat"); expect(AttrPath.traverse(value, '.children.花子.pet[0].name')).toBe("Chloe"); expect(AttrPath.traverse(value, '.children.john.hobby["0"].name')).toBeUndefined(); expect(AttrPath.traverse(value, '.children["john"].hobby[0].name')).toBe("Cycling"); expect(AttrPath.traverse(value, '.children["john"].hobby[0]["name"]')).toBe("Cycling"); expect(AttrPath.traverse(value, '["children"]["john"].hobby[0].name')).toBe("Cycling"); expect(AttrPath.traverse(value, '.children["john"].hobby[0].name')).toBe("Cycling"); expect(AttrPath.traverse(value, '["children"]["john"]["hobby"][0]["name"]')).toBe("Cycling"); expect(AttrPath.traverse(value, '["children"]["john"]["hobby"][0].["name"]')).toBeUndefined(); expect(AttrPath.traverse(value, '["children"]["john"]["hobby"][0]["name"]')).toBe("Cycling"); expect(AttrPath.traverse(value, '.children["john"].hobby[1].name')).toBe("Dance"); expect(AttrPath.traverse([1], '[0]')).toBe(1); expect(AttrPath.traverse([1], '[1]')).toBeUndefined(); expect(AttrPath.traverse(AttrPath.traverse(value, '.children.john'), '.hobby')).toStrictEqual([{ "name": "Cycling" }, { "name": "Dance" }]); expect(AttrPath.traverse(null, '.path')).toBeUndefined(); expect(AttrPath.traverse(undefined, '.path')).toBeUndefined(); expect(AttrPath.traverse(false, '.path')).toBeUndefined(); expect(AttrPath.traverse(true, '.path')).toBeUndefined(); expect(AttrPath.traverse(NaN, '.path')).toBeUndefined(); expect(AttrPath.traverse(Infinity, '.path')).toBeUndefined(); expect(AttrPath.traverse(0, '.path')).toBeUndefined(); expect(AttrPath.traverse(-1, '.path')).toBeUndefined(); expect(AttrPath.traverse("", '.path')).toBeUndefined(); expect(AttrPath.traverse("1", '.path')).toBeUndefined(); expect(AttrPath.traverse([1], '.path')).toBeUndefined(); expect(AttrPath.traverse({}, '.path')).toBeUndefined(); expect(AttrPath.traverse({}, '.path', 1)).toBe(1); expect((_c = (_b = (_a = value === null || value === void 0 ? void 0 : value.children) === null || _a === void 0 ? void 0 : _a.john) === null || _b === void 0 ? void 0 : _b.hobby[10]) === null || _c === void 0 ? void 0 : _c.name).toBeUndefined(); const value2 = [ { john: { "hobby": [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, } ]; expect(AttrPath.traverse(value2, '[0].john.hobby[1].name')).toBe("Dance"); const value3 = { "john.data": { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] } }; expect(AttrPath.traverse(value3, '["john.data"]')).toBe(value3["john.data"]); expect(AttrPath.traverse(value3, '["john.data"]')).toStrictEqual({ "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }); const value4 = { "漢字": { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] } }; expect(AttrPath.traverse(value4, '["漢字"]')).toBe(value4["漢字"]); expect(AttrPath.traverse(value4, '["漢字"].hobby[0].name')).toBe(value4["漢字"].hobby[0].name); expect(AttrPath.is_valid('["john.data"]')).toBe(true); expect(AttrPath.is_valid('.children["john"].hobby[1].name')).toBe(true); expect(AttrPath.is_valid('.children["john"].hobby[1a].name')).toBe(false); expect(AttrPath.is_valid('.children["john"].hobby["1"].name')).toBe(false); expect(AttrPath.is_valid('this.name')).toBe(false); }); it('Customize', () => { const { AttributeParser, ValueHandler, ParserStream } = require('./index'); const value = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Dance" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; const value2 = { children: { john: { hobby: [{ name: "Cycling" }, { name: "Game" }], pet: [{ type: "dog", name: "Max" }] }, "花子": { hobby: [{ name: "Squash" }], pet: [{ type: "cat", name: "Chloe" }] } } }; function CustomTraverse(obj, path) { let result = undefined; const handler = new ValueHandler(obj); if (new AttributeParser(handler, new ParserStream(path)).parse_path()) { result = handler.value; } return result; } function CustomUpdate(target, path, value) { let result; if (target) { const updater = new handler_1.Updater(target, value); if (new AttributeParser(updater, new ParserStream(path)).parse_path()) { result = target; } } return result; } function CustomIsValid(path) { return new AttributeParser(null, new ParserStream(path)).parse_path(); } expect(CustomTraverse(value, '.children')).toStrictEqual({ "john": { "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }, "花子": { "hobby": [{ "name": "Squash" }], "pet": [{ "type": "cat", "name": "Chloe" }] } }); expect(CustomTraverse(value, '.children.john')).toStrictEqual({ "hobby": [{ "name": "Cycling" }, { "name": "Dance" }], "pet": [{ "type": "dog", "name": "Max" }] }); expect(CustomTraverse(value, '.children.john.hobby')).toStrictEqual([{ "name": "Cycling" }, { "name": "Dance" }]); expect(CustomTraverse(value, '.children.john.hobby[0]')).toStrictEqual({ "name": "Cycling" }); expect(CustomTraverse(value, '.children.john.hobby[0].name')).toBe("Cycling"); expect(CustomTraverse(value, '.children.john.hobby[0a].name')).toBeUndefined(); expect(CustomTraverse(value, '.children.john.hobby[1].name')).toBe("Dance"); expect(CustomTraverse(value, '.children.john.pet[0].type')).toBe("dog"); expect(CustomTraverse(value, '.children.john.pet[0].name')).toBe("Max"); expect(CustomTraverse(value, '.children.花子.hobby[0].name')).toBe("Squash"); expect(CustomTraverse(value, '.children.花子.pet[0].type')).toBe("cat"); expect(CustomTraverse(value, '.children.花子.pet[0].name')).toBe("Chloe"); expect(CustomTraverse(value, '.children.john.hobby["0"].name')).toBeUndefined(); expect(CustomTraverse(value, '.children["john"].hobby[0].name')).toBe("Cycling"); expect(CustomTraverse(value, '.children["john"].hobby[0]["name"]')).toBe("Cycling"); expect(CustomTraverse(value, '["children"]["john"].hobby[0].name')).toBe("Cycling"); expect(CustomTraverse(value, '.children["john"].hobby[0].name')).toBe("Cycling"); expect(CustomTraverse(value, '["children"]["john"]["hobby"][0]["name"]')).toBe("Cycling"); expect(CustomTraverse(value, '["children"]["john"]["hobby"][0].["name"]')).toBeUndefined(); expect(CustomTraverse(value, '["children"]["john"]["hobby"][0]["name"]')).toBe("Cycling"); expect(CustomTraverse(value, '.children["john"].hobby[1].name')).toBe("Dance"); expect(CustomUpdate(value, '.children["john"].hobby[1].name', "Game")).toStrictEqual(value2); expect(CustomIsValid('.children["john"].hobby[1].name')).toBe(true); expect(CustomIsValid('.children["john"].hobby[1a].name')).toBe(false); expect(CustomIsValid('.children["john"].hobby["1"].name')).toBe(false); expect(CustomIsValid('XXXXX')).toBe(false); expect(CustomIsValid('.expect(isValid(\'.children["john"].hobby[1].name\')).toBe(true);')).toBe(false); }); it('Extends', () => { const { AttrPath } = require('./index'); class Klass { constructor() { this.member = "name"; } Member() { return AttrPath.traverse(this, '.member'); } } const klass = new Klass(); expect(klass.Member()).toBe("name"); class ParentKlass { constructor() { this.member = "name"; } } class SubKlass extends ParentKlass { Member() { return AttrPath.traverse(this, '.member'); } } const sub_klass = new SubKlass(); expect(sub_klass.Member()).toBe("name"); }); }); //# sourceMappingURL=test.js.map