attrpath
Version:
Attribute Path Traverser.
803 lines • 42.5 kB
JavaScript
/**
* 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