Code Monkey home page Code Monkey logo

inquirer-file-tree-selection's Introduction

Inquirer File Tree Selection Prompt

Node.js Package

QuickDemo

QuickDemo

Install

npm install inquirer-file-tree-selection-prompt

If you are still using CJS, please install inquirer-file-tree-selection-prompt@^1

Usage

inquirer.registerPrompt('file-tree-selection', inquirerFileTreeSelection)

inquirer.prompt({
  type: 'file-tree-selection',
  ...
})

Options

Takes type, name, message, [filter, validate, transformer, default, pageSize, onlyShowDir, onlyShowValid, hideChildrenOfValid, root, hideRoot, multiple, enableGoUpperDirector] properties.

The extra options that this plugin provides are:

  • onlyShowDir: (Boolean) if true, will only show directory. Default: false.
  • root: (String) it is the root of file tree. Default: process.cwd().
  • onlyShowValid: (Boolean) if true, will only show valid files (if validate is provided). Default: false.
  • hideChildrenOfValid: (Boolean) if true, will hide children of valid directories (if validate is provided). Default: false.
  • transformer: (Function) a hook function to transform the display of directory or file name.
  • multiple: (Boolean) if true, will enable to select multiple files. Default: false.
  • enableGoUpperDirectory: (Boolean) Show .. in inside root dir, and the user can press space on it to go upper directory. Default: false.

When multiple is enabled, default should be string[] type, otherwise it's string type.

Typescript Support

version >= 1.0.16

  1. Install @types/inquirer

  2. Ensure you have registered with file-tree-selection

inquirer.registerPrompt('file-tree-selection', inquirerFileTreeSelection)
  1. And you will get type support when you code in IDE

ts

Example

ESM (version ^2)

import inquirer from 'inquirer'
import inquirerFileTreeSelection from 'inquirer-file-tree-selection-prompt'

inquirer.registerPrompt('file-tree-selection', inquirerFileTreeSelection)

inquirer
  .prompt([
    {
      type: 'file-tree-selection',
      name: 'file'
    }
  ])
  .then(answers => {
    console.log(JSON.stringify(answers))
  });

CJS (version ^1 and <2)

const inquirer = require('inquirer')
const inquirerFileTreeSelection = require('inquirer-file-tree-selection-prompt')

inquirer.registerPrompt('file-tree-selection', inquirerFileTreeSelection)

inquirer
  .prompt([
    {
      type: 'file-tree-selection',
      name: 'file'
    }
  ])
  .then(answers => {
    console.log(JSON.stringify(answers))
  });

More examples

inquirer-file-tree-selection's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

inquirer-file-tree-selection's Issues

Suggestion: add `fs` option to question, for substituting other filesystem implementations

I'm writing a configuration wizard using this project, along with memfs and unionfs to manage a temporary file system as an overlay on top of the existing real file system. I really would like to pass in the temporary file system I built from unionfs as an override.

There are precisely two uses of fs in src/index/index.ts. This could be a pretty straight-forward fix.

On a related note, I did some experiments with enquirer a couple days ago. I was running prompts through a child process and driving it through stdin and stdout. The goal was to add automated tests. I see no reason I couldn't do the same here, if there's a desire for it. I just need to know what testing framework you'd prefer.

Exclude directories from options

Is there any way to exclude or whitelist certain directories from the options?

See the below screenshot.

Screenshot 2022-03-25 at 16 55 20

Idealy I'd like to only show :

/apps
/packages

Require of ES module

You are using an ESM package (chalk) with require(). If you want to keep using require instead of ESM you'll have to use Chalk 4.

Read more
Chalk 5 changelog

Log output:

C:\ProgramData\nvm\v16.14.0\node_modules\solve3-cli\node_modules\inquirer-file-tree-selection-prompt\dist\index.js:15
const chalk = require('chalk');
              ^

Error [ERR_REQUIRE_ESM]: require() of ES Module C:\ProgramData\nvm\v16.14.0\node_modules\solve3-cli\node_modules\chalk\source\index.js from C:\ProgramData\nvm\v16.14.0\node_modules\solve3-cli\node_modules\inquirer-file-tree-selection-prompt\dist\index.js not supported.
Instead change the require of C:\ProgramData\nvm\v16.14.0\node_modules\solve3-cli\node_modules\chalk\source\index.js in C:\ProgramData\nvm\v16.14.0\node_modules\solve3-cli\node_modules\inquirer-file-tree-selection-prompt\dist\index.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (C:\ProgramData\nvm\v16.14.0\node_modules\solve3-cli\node_modules\inquirer-file-tree-selection-prompt\dist\index.js:15:15)
    at async Promise.all (index 0) {
  code: 'ERR_REQUIRE_ESM'
}

Have a way to distinguish between empty directories and files

Currently there is no way to distinguish between a file and an empty directory.

Example output (emptydirectory is a directory)

 ? Select a file
 ↓ .(root directory)
   → .git
     emptydirectory
     afile
 -----------------

maybe something like this

 ? Select a file
 ↓ .(root directory)
   → .git\
     emptydirectory\
     afile
 -----------------

I tried using transformer, but since only the path is provided, I would have to make a file system call to check if the path is a directory.

Feat: ignoring certain files

I think a nice feature would be the ability to ignore certain files from displaying in the tree. Where it ignores none by default, but allows the user to pass a optional array of patterns (strings) to match against for files that the user does NOT want displayed. Maybe this functionality is handled already if so please point me in the right direction.

I'm willing to contribute to this feat, getting familiar with the codebase right now.

Multiple selection types/categories

I would like to go through a directory and assign the files to various categories, e.g. not selected, selected, or ignored. In my scenario the pure boolean value selected or not selected in not enough.
Would it be possible/in your focus to add such a feature?

Changing root path causes inquirer to hang.

I want to be able to select files from outside the current working directory (process.cwd()). However if I update the root parameter to anything higher than the current directory it hangs. Is this something that is not possible with this library or an error in my configuration?

{
     type: 'file-tree-selection',
     name: 'example',
     root: "/",
     message: "Choose file:",
}

Validation does not work when filter is used

I use the validate function to make sure the user cannot select the root folder:

  validate: async answer => Boolean(answer !== process.cwd())

I also use the filter function to get a relative path as output:

  filter: answer => path.relative(process.cwd(), answer)

When I add the filter function, the validate function seems to stop working. The root path is still a red color, but if I press enter, I am allowed to select it as my answer. This seems to only happen when the filter function returns a different answer than the original answer. If it outputs the same as its input, everything still works fine.

Steps to reproduce

Create a new test project with the following code:

import inquirer from "inquirer";
import fileTree from "inquirer-file-tree-selection-prompt";
const prompt = inquirer.createPromptModule();
prompt.registerPrompt("file-tree", fileTree);

await prompt([
    {
        name: "test",
        type: "file-tree",
        message: `This is a test.`,
        validate: async path => Boolean(path !== process.cwd()),
        filter: answer => answer,
    }
]);

Run this example and notice that you cannot select the root folder, as is expected.
(you can also try to remove the filter function and see that that also works as expected)

Now change the filter function to this:

  filter: answer => "different output answer",

Run the example again and notice that you can now select the root folder, even though you weren't supposed to be able to do that.

Write some unit tests.

Spin-off of #92 .

EDIT: ignore all the stuff below (except ts-jest). There's a much simpler solution: use a fake Inquirer implementation. Tests for the same are here.

Helpful links:

Cannot find module 'inquirer-file-tree-selection-prompt' or its corresponding type declarations.

Hey!
After updating my project, along with this package, I can't import this package anymore.
Here is a reproduction, I'm getting this error:

❯ node index.js
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/projects/node-mckcqj/node_modules/inquirer-file-tree-selection-prompt/dist/index.js' imported from /home/projects/node-mckcqj/index.js
    at InternalError.get (https://node-mckcqj.w.staticblitz.com/blitz.1f021b18268b32e6c6b2095e039ac8c9f88b0d52.js:6:292488)
    at Object.triggerUncaughtException (https://node-mckcqj.w.staticblitz.com/blitz.1f021b18268b32e6c6b2095e039ac8c9f88b0d52.js:15:355829)
    at i.loadESM (https://node-mckcqj.w.staticblitz.com/blitz.1f021b18268b32e6c6b2095e039ac8c9f88b0d52.js:6:246694)
    at async handleMainPromise (https://node-mckcqj.w.staticblitz.com/blitz.1f021b18268b32e6c6b2095e039ac8c9f88b0d52.js:6:989049) {
  code: 'ERR_MODULE_NOT_FOUND'
}

It seems like a version on npm doesn't have a dist folder.
image

Select parent directory

Hey

Thanks for your awesome plugin.

Any plans to implement selecting from the parent directory?

enhancement to allow only displaying valid choices

When a validate function is provided, it would be useful to only display valid choices in the file tree. For instance, if you only want to have the user select files of a specific file extension, then removing all invalid files from the tree (and any folders that don't contain valid files) could make for a significantly better user experience when the file tree structure is large and/or deeply nested.

I'll submit a pull request which addresses this issue.

Make directories "valid" by default but not selectable

Say you want to display only files of a specific extension, like .js this could be your code:

// execute with "ts-node ./demo.ts"

import inquirer from 'inquirer';
import inquirerFileTreeSelection from 'inquirer-file-tree-selection-prompt';
import { extname } from 'path';
import { lstat, PathLike } from 'fs';

inquirer.registerPrompt('file-tree-selection', inquirerFileTreeSelection);

inquirer.prompt({
  type: 'file-tree-selection',
  name: 'file',
  message: 'Please select a JS file',
  onlyShowValid: true,
  multiple: false,
  pageSize: 10,
  root: './db',
  validate: async (item) => {
    return extname(item) === '.js' || await isDirectory(item);
  }
}).then(
  ({file}) =>
  console.log('selected', file)
);

async function isDirectory(path: PathLike) {
  return new Promise((resolve) => {
    lstat(path,
      (err, stat) => {
        if (!err) {
          resolve(stat.isDirectory());
        } else {
          resolve(false);
        }
      });
  });
}

However, this will show folders and these folders will now be valid selections!

It would be better, if you could not select folders using enter but still benefit from onlyShowValid.

The option "default" does not take effect

{
    name: 'folder',
    type: 'inquirer-file-tree-selection',
    message: 'Select a folder:',
    onlyShowDir: true,
   // expect to display the default value, or it is selected in the list
   // the folder already exists, try to use path.resolve('./src') but it’s still doesn't work
    default: './src'  
}

Folders are only found when a user selects them

Hello again, and once again thanks for this really cool plugin :)

In all versions of this package prior to 1.0.7, any folder in the file tree would have an arrow in front of it, showing that it is a folder, and that it can be opened. In version 1.0.7, it seems there has been a regression where it only checks if something is a folder when you hover over it.
It also seems that the very first folder that is automatically selected, isn't checked at all, which means it gets a play symbol instead of an arrow. That is not supposed to happen at all.
(the last issue only happens when you use a validate function that displaces the cursor)

Steps to reproduce

Create a test project with the following code:

import inquirer from "inquirer";
import fileTree from "inquirer-file-tree-selection-prompt";
const prompt = inquirer.createPromptModule();
prompt.registerPrompt("file-tree", fileTree);

await prompt([
    {
        name: "test",
        type: "file-tree",
        onlyShowDir: true,
        onlyShowValid: true,
        message: `This is a test.`,
        validate: async path => Boolean(path !== process.cwd()),
    }
]);

Run it with version 1.0.6 (or any other older version) and see that it works as intended:

working

Then run it again with version 1.0.7 and see that there are multiple issues with the display:

broken

Multiple files selections

Any plans adding multiple selections? Use case: Select files to be deleted in the specified directory

Provide default value or press key to exit prompt

I have a problem when the user want to exit the file selector prompt. They don't know what button to press to exit when there aren't any valid file to select or the root folder was empty. So I think the prompt should provide a default value or callback when press key e.g ESC

Expose filter and validate API

Hi!

First of all, nice job for this plugin, it works very well!

Then, is it possible to have filter and validate method exposed in the prompt configuration like for the others built-in inquirer prompt type?

Currently, when I'm doing something like:

   const answer = await inquirer.prompt([
      {
        type: 'file-tree-selection',
        message: 'Choose folder',
        onlyShowDir: true,
        name: 'srcDir',
        filter: (input) => {
          return new Promise(() => {
            throw new Error(input);
            return input;            
          });
        }
      }
    ]);

Filter is not called.

I have currently an easy workaround, but it will be really nice to configure this prompt like the others one.

What do you think?

onlyShowDir filters out symlinked dirs (pnpm)

Hello and thank you for this. I only want to show the directories and I use pnpm that symlinks modules.

onlyShowDir: true does not include symlinked dirs if (fileObj.type == 'directory') {

Maybe use fs.realpath() or something? Or is this user error?

Error when trying to register a prompt

inquirer.registerPrompt('file-tree-selection', inquirerFileTreeSelection)

When trying to register this prompt, I get a typescript error:

Argument of type 'typeof FileTreeSelectionPrompt' is not assignable to parameter of type 'PromptConstructor'.
  Type 'FileTreeSelectionPrompt' is missing the following properties from type 'PromptBase': status, run
ts(2345)

Split the question type and the application

Given that this is the only inquirer plugin afaics that provides a tree based question - how about splitting it up in 2 packages inquirer-tree-selection and on top of that a thin layer for the filesystem?

There are many more applications of trees than just filesystems.

Error: Invalid count value on Windows

Hi,

I'm getting an error on Windows on a couple of computers, error happens because prefix.length is too large for root directory.

Apparently the issue is that on Windows the symbol: is replaced for ( )

index.js #172

showValue = ' '.repeat(indent - prefix.length + 2) + prefix + itemPath.name + (itemPath.type === 'directory' ? path.sep : '')  + '\n'

Testing code, add before line #172

const ind = indent - prefix.length + 2;
console.log(ind, indent, prefix.length, prefix, itemPath.name);
// Linux prints:    0 2 4 ↓ ◯  .(root directory)
// Windows prints: -2 2 6 ↓ ( )   .(root directory)

// temporary fix
showValue = ' '.repeat(ind < 0 ? 0 : ind) + prefix + itemPath.name + (itemPath.type === 'directory' ? path.sep : '')  + '\n'

Not sure what would be the best way to solve this issue as it comes from figures: https://www.npmjs.com/package/figures

I'll make a clone with the quick fix and can submit a pull request if this patch is the better option.

Typescript support

Hello,

First of all thanks for the great inquirer module, it really helps making a great cli experience

I raise the question of TypeScript support, which would make integrating the plugin smoother. Hoping to find time to provide the PR shortly

if anyone is willing to add the type.d.ts file and test the change on its side, here is some base material:

interface FileTreeQuestionOptions<Answers> {
  type: 'file-tree-selection';
  name: keyof Answers;
  message: string;
  filter?: (path: string) => Promise<string> | string;
  validate?: (filteredPath: string, answers: unknown) => boolean;
  transformer?: (directoryName: string, answers: Answers, context: { isFinal: boolean }) => string;
  pageSize?: number;
  onlyShowDir?: boolean;
  onlyShowValid?: boolean;
  hideChildrenOfValid?: boolean;
  root?: string;
  hideRoot?: boolean;
  multiple?: boolean;
  default?: string | string[];
}

(this could be improved by binding multiple & default typings)

Thanks!

expose `transformer` as an option

The capability to add a transform function to return a transformed value to display to the user is a standard option in most Inquirer question types. I'll submit a pull request which adds this capability as an enhancement to the existing functionality.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.