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