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  }