diff --git a/README.md b/README.md index 224b800..a4bd278 100644 --- a/README.md +++ b/README.md @@ -8,45 +8,57 @@ import {JsonItemSelector} from "json-item-selector"; // CommonJS const {JsonItemSelector} = require("json-item-selector"); -const json = { - "galaxy": { - "milky-way": { - "earth": [ - "africa", - "asia", - "aurope", - ], - "venus": [ - "valnaes", - ], - }, - "andromeda": { - "pegasus":[], - "cassopia":[] - } +const galaxy = { + // Depth: 0 + "milky-way": { + // Depth: 1 + "earth": [ + // Depth: 2 + "africa", + "asia", + "aurope", + ], + // Depth: 1 + "venus": [ + // Depth: 2 + "valnaes", + ], + }, + // Depth: 0 + "andromeda": { + // Depth: 1 + "pegasus":[ + // Depth: 2 + "perg", + "gaort" + ], + // Depth: 1 + "cassopia":[ + // Depth: 2 + 'epian', + 'siltron' + ] } } -const JIS = new JsonItemSelector(json); +const JIS = new JsonItemSelector(galaxy); -console.log(JIS.list_options()); // ["galaxy"] +console.log(JIS.list(0)); // ["milky-way", "andromeda"] --> List options at 0 depth -JIS.select_option("galaxy"); // returns true if successful +JIS.select("milky-way", 0); // --> Selects from options at 0 depth -console.log(JIS.list_options()); // ["milky-way", "andromeda"] +console.log(JIS.list(1)); // ["earth", "venus"] --> List options at depth 1 -JIS.select_option("milky-way"); +JIS.select("earth", 1); // --> Selects from options at depth 1 -console.log(JIS.list_options()); // ["earth", "venus"] +console.log(JIS.list(2)); // ["africa", "asia", "europe"] -JIS.select_option("earth"); - -console.log(JIS.list_options()); // ["africa", "asia", "europe"] - -console.log(JIS.get_all_selected()); // ["galaxy", "milky-way", "earth"] +JIS.select("africa", 2); +console.log(JIS.get_all_selected()); // ["milky-way", "earth", "africa"] ``` +[CodePen Example](https://codepen.io/Yoseph-Tenaw/pen/GRzVZzO) # Installation ``` @@ -56,8 +68,10 @@ npm install json-item-selector # Methods | Name | Description | Params | Defaults | Returns | | ------ | ------ | ------ | ------ | ------ | -| list_options | List all the possible options to select, starting from the first level/ highest depth | - | | `string []` | -| select_option | Choose from the available options from the current level/depth, after selecting the next list of option will go to the next level/depth of properties | `option: string` `deny_repeats?: boolean` | `deny_repeats: false`| `boolean` | +| list | List all the possible options to select at a given depth in the object | `depth: number` | | `string []` | +| select | Choose from the available options from the given depth | `option: string` `deny_repeats?: boolean` `depth: number` | `deny_repeats: false`| `boolean` | +| list_no_depth | List all the possible options to select, starting from the first level/ highest depth | - | | `string []` | +| select_no_depth | Choose from the available options from the current level/depth, after selecting the next list of option will go to the next level/depth of properties | `option: string` `deny_repeats?: boolean` | `deny_repeats: false`| `boolean` | | get_all_selected | Lists all the options selected so far | - | | `string []` | | get_last_selected | Gets the last selected option | - | | `string` | | clear_last | Remove the last selected option and go back up a level/higher in depth | - | | `boolean` | diff --git a/src/index.ts b/src/index.ts index 95e607e..4f215fd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,7 @@ export class JsonItemSelector { this.choice_tree = []; } - public list_options ():string[] { + public list_no_depth ():string[] { const option_list: string[] = []; if (this.choice_tree.length === 0) { for (const key in this.json) { @@ -38,8 +38,41 @@ export class JsonItemSelector { return option_list; } - public select_option (option: string, deny_repeats: boolean = false):boolean { - if (!this.list_options().includes(option)) + public list (at_depth: number):string[] { + const option_list: string[] = []; + if (at_depth < 0 || at_depth > this.choice_tree.length) + return []; + + if (this.choice_tree.length === 0) { + for (const key in this.json) { + if (Object.prototype.hasOwnProperty.call(this.json, key)) { + option_list.push(key); + } + } + } + else { + const next_object = JsonItemSelector.access_value(this.choice_tree.slice(0, at_depth), this.json, 0); + if (Array.isArray(next_object)) { + for(let i = 0; i < next_object.length; i++) { + option_list.push(next_object[i]); + } + } + else if (typeof next_object === "object") { + for (const key in next_object) { + if (Object.prototype.hasOwnProperty.call(next_object, key)) { + option_list.push(key); + } + } + } + else { + option_list.length = 0; + } + } + return option_list; + } + + public select_no_depth (option: string, deny_repeats: boolean = false):boolean { + if (!this.list_no_depth().includes(option)) return false; if (deny_repeats && this.choice_tree.includes(option)) return false; @@ -47,6 +80,18 @@ export class JsonItemSelector { return true } + public select (option: string, at_depth: number, deny_repeats: boolean = false):boolean { + if (!this.list(at_depth).includes(option)) + return false; + if (deny_repeats && this.choice_tree.includes(option)) + return false; + if (at_depth < 0 || at_depth > this.choice_tree.length) + return false; + this.choice_tree.splice(at_depth); + this.choice_tree[at_depth] = option; + return true + } + public get_all_selected ():string[] { return this.choice_tree; } diff --git a/test/index.test.ts b/test/index.test.ts index b29e92b..b4d209d 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -24,134 +24,134 @@ describe ("Reset & Clearing", () => { test("clear_last", () => { const JIS_2 = new JsonItemSelector(test_json_2); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.list_options().length).toBe(14); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.list_no_depth().length).toBe(14); expect(JIS_2.clear_last(1)).toBe(true); - expect(JIS_2.list_options().length).toBe(11); + expect(JIS_2.list_no_depth().length).toBe(11); expect(JIS_2.clear_last(1)).toBe(true); - expect(JIS_2.list_options().length).toBe(13); + expect(JIS_2.list_no_depth().length).toBe(13); }) test("clear_all_selected", () => { const JIS_2 = new JsonItemSelector(test_json_2); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); expect(JIS_2.clear_all_selected()).toBe(true); - expect(JIS_2.list_options().length).toBe(13); + expect(JIS_2.list_no_depth().length).toBe(13); }) }) -describe("list_options", () => { - test("list_options length", () => { +describe("list_no_depth", () => { + test("list_no_depth length", () => { const JIS_1 = new JsonItemSelector(test_json_1); const JIS_2 = new JsonItemSelector(test_json_2); - expect(JIS_1.list_options().length).toBe(1); - expect(JIS_2.list_options().length).toBe(13); + expect(JIS_1.list_no_depth().length).toBe(1); + expect(JIS_2.list_no_depth().length).toBe(13); }) - test("list_options content", () => { + test("list_no_depth content", () => { const JIS_1 = new JsonItemSelector(test_json_1); const JIS_2 = new JsonItemSelector(test_json_2); - expect(JIS_1.list_options()[0]).toBe("quiz"); - expect(JIS_2.list_options()[0]).toBe("ADDIS ABABA"); - expect(JIS_2.list_options()[12]).toBe("TIGRAY"); + expect(JIS_1.list_no_depth()[0]).toBe("quiz"); + expect(JIS_2.list_no_depth()[0]).toBe("ADDIS ABABA"); + expect(JIS_2.list_no_depth()[12]).toBe("TIGRAY"); }) - test("list_options array cases", () => { + test("list_no_depth array cases", () => { const JIS_2 = new JsonItemSelector(test_json_2); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.list_options().length).toBe(11); - expect(JIS_2.list_options()[0]).toBe("ADDIS KETEMA SUB CITY"); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.list_options().length).toBe(14); - expect(JIS_2.list_options()[0]).toBe("WOREDA 1"); - expect(JIS_2.list_options()[13]).toBe("WOREDA 14"); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.list_no_depth().length).toBe(11); + expect(JIS_2.list_no_depth()[0]).toBe("ADDIS KETEMA SUB CITY"); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.list_no_depth().length).toBe(14); + expect(JIS_2.list_no_depth()[0]).toBe("WOREDA 1"); + expect(JIS_2.list_no_depth()[13]).toBe("WOREDA 14"); }) - test("list_options nested", () => { + test("list_no_depth nested", () => { const JIS_1 = new JsonItemSelector(test_json_1); - expect(JIS_1.select_option(JIS_1.list_options()[0])).toBe(true); - expect(JIS_1.list_options().length).toBe(2); - expect(JIS_1.list_options()[0]).toBe("sport"); - expect(JIS_1.select_option(JIS_1.list_options()[0])).toBe(true); - expect(JIS_1.list_options()[0]).toBe("q1"); - expect(JIS_1.select_option(JIS_1.list_options()[0])).toBe(true); - expect(JIS_1.list_options()[0]).toBe("question"); + expect(JIS_1.select_no_depth(JIS_1.list_no_depth()[0])).toBe(true); + expect(JIS_1.list_no_depth().length).toBe(2); + expect(JIS_1.list_no_depth()[0]).toBe("sport"); + expect(JIS_1.select_no_depth(JIS_1.list_no_depth()[0])).toBe(true); + expect(JIS_1.list_no_depth()[0]).toBe("q1"); + expect(JIS_1.select_no_depth(JIS_1.list_no_depth()[0])).toBe(true); + expect(JIS_1.list_no_depth()[0]).toBe("question"); }) test("list_option overflow", () => { const JIS_4 = new JsonItemSelector(test_json_4); - expect(JIS_4.select_option("addis")).toBe(true); - expect(JIS_4.select_option("addis")).toBe(true); + expect(JIS_4.select_no_depth("addis")).toBe(true); + expect(JIS_4.select_no_depth("addis")).toBe(true); expect(JIS_4.get_all_selected()).toEqual(["addis", "addis"]); - expect(JIS_4.list_options().length).toBe(1); - expect(JIS_4.select_option("name")).toBe(true); + expect(JIS_4.list_no_depth().length).toBe(1); + expect(JIS_4.select_no_depth("name")).toBe(true); expect(JIS_4.get_all_selected()).toEqual(["addis", "addis", "name"]); - expect(JIS_4.list_options().length).toBe(0); + expect(JIS_4.list_no_depth().length).toBe(0); }) test("Alternative JSON", () => { const JIS_3 = new JsonItemSelector(test_json_3); - expect(JIS_3.list_options().length).toBe(1); - expect(JIS_3.select_option(JIS_3.list_options()[0])).toBe(true); - expect(JIS_3.list_options().length).toBe(2); - expect(JIS_3.select_option(JIS_3.list_options()[0])).toBe(true); - expect(JIS_3.list_options().length).toBe(2); - expect(JIS_3.select_option(JIS_3.list_options()[0])).toBe(true); - expect(JIS_3.list_options().length).toBe(2); - expect(JIS_3.select_option(JIS_3.list_options()[1])).toBe(true); - expect(JIS_3.list_options().length).toBe(14); - expect(JIS_3.list_options()[8]).toBe("WOREDA 9"); - expect(JIS_3.select_option(JIS_3.list_options()[8])).toBe(true); + expect(JIS_3.list_no_depth().length).toBe(1); + expect(JIS_3.select_no_depth(JIS_3.list_no_depth()[0])).toBe(true); + expect(JIS_3.list_no_depth().length).toBe(2); + expect(JIS_3.select_no_depth(JIS_3.list_no_depth()[0])).toBe(true); + expect(JIS_3.list_no_depth().length).toBe(2); + expect(JIS_3.select_no_depth(JIS_3.list_no_depth()[0])).toBe(true); + expect(JIS_3.list_no_depth().length).toBe(2); + expect(JIS_3.select_no_depth(JIS_3.list_no_depth()[1])).toBe(true); + expect(JIS_3.list_no_depth().length).toBe(14); + expect(JIS_3.list_no_depth()[8]).toBe("WOREDA 9"); + expect(JIS_3.select_no_depth(JIS_3.list_no_depth()[8])).toBe(true); }) }) -describe("select_option", () => { - test("select_option selects", () => { +describe("select_no_depth", () => { + test("select_no_depth selects", () => { const JIS_1 = new JsonItemSelector(test_json_1); const JIS_2 = new JsonItemSelector(test_json_2); - expect(JIS_1.select_option(JIS_1.list_options()[0])).toBe(true); - expect(JIS_1.list_options().length).toBe(2); - expect(JIS_1.list_options()[0]).toBe("sport"); + expect(JIS_1.select_no_depth(JIS_1.list_no_depth()[0])).toBe(true); + expect(JIS_1.list_no_depth().length).toBe(2); + expect(JIS_1.list_no_depth()[0]).toBe("sport"); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.list_options().length).toBe(11); - expect(JIS_2.list_options()[0]).toBe("ADDIS KETEMA SUB CITY"); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.list_options().length).toBe(14); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.list_no_depth().length).toBe(11); + expect(JIS_2.list_no_depth()[0]).toBe("ADDIS KETEMA SUB CITY"); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.list_no_depth().length).toBe(14); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); expect(JIS_2.get_all_selected().length).toBe(3); expect(JIS_2.get_all_selected()).toEqual(["ADDIS ABABA", "ADDIS KETEMA SUB CITY", "WOREDA 1"]); }) - test("select_option Not exisiting cases", () => { + test("select_no_depth Not exisiting cases", () => { const JIS_1 = new JsonItemSelector(test_json_1); - expect(JIS_1.select_option("Not existing")).toBe(false); - expect(JIS_1.list_options().length).toBe(1); - expect(JIS_1.list_options()[0]).toBe("quiz"); + expect(JIS_1.select_no_depth("Not existing")).toBe(false); + expect(JIS_1.list_no_depth().length).toBe(1); + expect(JIS_1.list_no_depth()[0]).toBe("quiz"); }) - test("select_option Repeatetion", () => { + test("select_no_depth Repeatetion", () => { const JIS_4 = new JsonItemSelector(test_json_4); - expect(JIS_4.select_option("addis")).toBe(true); - expect(JIS_4.select_option("addis")).toBe(true); + expect(JIS_4.select_no_depth("addis")).toBe(true); + expect(JIS_4.select_no_depth("addis")).toBe(true); expect(JIS_4.get_all_selected()).toEqual(["addis", "addis"]); - expect(JIS_4.list_options().length).toBe(1); + expect(JIS_4.list_no_depth().length).toBe(1); expect(JIS_4.clear_all_selected()).toBe(true); - expect(JIS_4.select_option("addis", true)).toBe(true); - expect(JIS_4.select_option("addis", true)).toBe(false); + expect(JIS_4.select_no_depth("addis", true)).toBe(true); + expect(JIS_4.select_no_depth("addis", true)).toBe(false); expect(JIS_4.get_all_selected()).toEqual(["addis"]); }) }) @@ -160,17 +160,62 @@ describe("Getters", () => { test("get_all_selected", () => { const JIS_2 = new JsonItemSelector(test_json_2); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.list_options().length).toBe(14); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.list_no_depth().length).toBe(14); expect(JIS_2.get_all_selected().length).toBe(2); }) test("get_last_selected", () => { const JIS_2 = new JsonItemSelector(test_json_2); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.select_option(JIS_2.list_options()[0])).toBe(true); - expect(JIS_2.list_options().length).toBe(14); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.select_no_depth(JIS_2.list_no_depth()[0])).toBe(true); + expect(JIS_2.list_no_depth().length).toBe(14); expect(JIS_2.get_last_selected()).toBe("ADDIS KETEMA SUB CITY"); }) +}) + +describe("Depth based", () => { + test("list & select", () => { + const JIS_3 = new JsonItemSelector(test_json_3); + expect(JIS_3.list(0).length).toBe(1); + expect(JIS_3.list(0)[0]).toBe("Africa"); + expect(JIS_3.select("Africa", 0)).toBe(true); + // Depth: 1 + expect(JIS_3.list(1)[0]).toBe("Ethiopia"); + expect(JIS_3.select("Ethiopia", 1)).toBe(true); + // Depth: 2 + expect(JIS_3.list(2)[0]).toBe("Addis Ababa"); + expect(JIS_3.select("Addis Ababa", 2)).toBe(true); + // Depth: 3 + expect(JIS_3.list(3)[0]).toBe("Bole"); + expect(JIS_3.select("Bole", 3)).toBe(true); + expect(JIS_3.get_all_selected()).toEqual(["Africa", "Ethiopia", "Addis Ababa", "Bole"]); + // Change value at depth: 1 + expect(JIS_3.select("Ghana", 1)).toBe(true); + expect(JIS_3.get_all_selected()).toEqual(["Africa", "Ghana"]); + // New path at Depth: 2 + expect(JIS_3.list(2)[0]).toBe("Accra"); + expect(JIS_3.select("Accra", 2)).toBe(true); + // New path at Depth: 3 + expect(JIS_3.list(3)[0]).toBe("Partey"); + expect(JIS_3.select("Partey", 3)).toBe(true); + // New path at Depth: 4 + expect(JIS_3.list(4)[0]).toBe("PARTY 1"); + expect(JIS_3.select("PARTY 1", 4)).toBe(true); + expect(JIS_3.get_all_selected()).toEqual(["Africa", "Ghana", "Accra", "Partey", "PARTY 1"]); + // Change value again at depth: 2 + expect(JIS_3.select("BAMAKO", 2)).toBe(true); + expect(JIS_3.get_all_selected()).toEqual(["Africa", "Ghana", "BAMAKO"]); + }); + test("edge cases", () => { + const JIS_3 = new JsonItemSelector(test_json_3); + expect(JIS_3.list(-1).length).toBe(0); + expect(JIS_3.list(10).length).toBe(0); + expect(JIS_3.select("Africa", -1)).toBe(false); + expect(JIS_3.select("Africa", 10)).toBe(false); + expect(JIS_3.select("Not exists", 0)).toBe(false); + expect(JIS_3.list(0)).toEqual(["Africa"]); + expect(JIS_3.select("Africa", 0)).toBe(true); + }) }) \ No newline at end of file