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  }