github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/utils/path-tree.js (about) 1 // @ts-check 2 3 // eslint-disable-next-line no-unused-vars 4 import VariableModel from '../models/variable'; 5 // eslint-disable-next-line no-unused-vars 6 import MutableArray from '@ember/array/mutable'; 7 import { trimPath } from '../helpers/trim-path'; 8 9 //#region Types 10 /** 11 * @typedef {Object} VariableFile 12 * @property {string} path - the folder path containing our "file", relative to parent 13 * @property {string} name - the variable "file" name 14 * @property {string} absoluteFilePath - the folder path containing our "file", absolute 15 * @property {VariableModel} variable - the variable itself 16 */ 17 18 /** 19 * @typedef {Object} VariableFolder 20 * @property {Array<VariableFile>} files 21 * @property {NestedPathTreeNode} children 22 * @property {string} absolutePath - the folder path containing our "file", absolute 23 */ 24 25 /** 26 * @typedef {Object.<string, VariableFolder>} NestedPathTreeNode 27 */ 28 //#endregion Types 29 30 /** 31 * @returns {NestedPathTreeNode} 32 */ 33 export default class PathTree { 34 /** 35 * @param {MutableArray<VariableModel>} variables 36 */ 37 constructor(variables) { 38 this.variables = variables; 39 this.paths = this.generatePaths(variables); 40 } 41 42 /** 43 * @type {VariableFolder} 44 */ 45 root = { children: {}, files: [], absolutePath: '' }; 46 47 /** 48 * Takes our variables array and creates a tree of paths 49 * @param {MutableArray<VariableModel>} variables 50 * @returns {NestedPathTreeNode} 51 */ 52 generatePaths = (variables) => { 53 variables.forEach((variable) => { 54 const path = trimPath([variable.path]).split('/'); 55 path.reduce((acc, segment, index, arr) => { 56 if (index === arr.length - 1) { 57 // If it's a file (end of the segment array) 58 acc.files.push({ 59 name: segment, 60 absoluteFilePath: path.join('/'), 61 path: arr.slice(0, index + 1).join('/'), 62 variable, 63 }); 64 } else { 65 // Otherwise, it's a folder 66 if (!acc.children[segment]) { 67 acc.children[segment] = { 68 children: {}, 69 files: [], 70 absolutePath: trimPath([`${acc.absolutePath || ''}/${segment}`]), 71 }; 72 } 73 } 74 return acc.children[segment]; 75 }, this.root); 76 }); 77 return { root: this.root }; 78 }; 79 80 /** 81 * Search for the named absolutePath within our tree using recursion 82 * @param {string} name 83 * @param {Object} root 84 */ 85 findPath = (name, root = this.paths.root) => { 86 if (root.absolutePath === name) { 87 return root; 88 } 89 if (root.children) { 90 return Object.keys(root.children).reduce((acc, cur) => { 91 if (!acc) { 92 return this.findPath(name, root.children[cur]); 93 } 94 return acc; 95 }, null); 96 } 97 }; 98 }