[READ-ONLY] Mirror of https://github.com/bombshell-dev/clack. Effortlessly build beautiful command-line apps bomb.sh/docs/clack/basics/getting-started/
cli command-line command-line-app node prompt prompts
0

Configure Feed

Select the types of activity you want to include in your feed.

fix(prompts): submit initial directory value in path prompt (#484)

Co-authored-by: James Garbutt <43081j@users.noreply.github.com>

+65 -3
+5
.changeset/tricky-states-tease.md
··· 1 + --- 2 + "@clack/prompts": patch 3 + --- 4 + 5 + Fix `path` directory mode so pressing Enter with an existing directory `initialValue` submits that current directory instead of the first child option, and add regression coverage for immediate submit and child-directory navigation.
+7 -3
packages/prompts/src/path.ts
··· 44 44 searchPath = dirname(userInput); 45 45 } else { 46 46 const stat = lstatSync(userInput); 47 - if (stat.isDirectory()) { 47 + if (stat.isDirectory() && (!opts.directory || userInput.endsWith('/'))) { 48 48 searchPath = userInput; 49 49 } else { 50 50 searchPath = dirname(userInput); 51 51 } 52 52 } 53 53 54 + // Strip trailing slash so startsWith matches the directory itself among its siblings 55 + const prefix = 56 + userInput.length > 1 && userInput.endsWith('/') ? userInput.slice(0, -1) : userInput; 57 + 54 58 const items = readdirSync(searchPath) 55 59 .map((item) => { 56 60 const path = join(searchPath, item); ··· 62 66 }; 63 67 }) 64 68 .filter( 65 - ({ path, isDirectory }) => 66 - path.startsWith(userInput) && (isDirectory || !opts.directory) 69 + ({ path, isDirectory }) => path.startsWith(prefix) && (isDirectory || !opts.directory) 67 70 ); 71 + 68 72 return items.map((item) => ({ 69 73 value: item.path, 70 74 }));
+53
packages/prompts/test/path.test.ts
··· 163 163 expect(value).toBe('/tmp/foo'); 164 164 }); 165 165 166 + test('directory mode submits initial directory value on enter', async () => { 167 + const result = prompts.path({ 168 + message: 'foo', 169 + root: '/tmp/', 170 + initialValue: '/tmp', 171 + directory: true, 172 + input, 173 + output, 174 + }); 175 + 176 + input.emit('keypress', '', { name: 'return' }); 177 + 178 + const value = await result; 179 + 180 + expect(value).toBe('/tmp'); 181 + }); 182 + 183 + test('directory mode traverses into child when trailing slash entered', async () => { 184 + const result = prompts.path({ 185 + message: 'foo', 186 + root: '/tmp/', 187 + initialValue: '/tmp', 188 + directory: true, 189 + input, 190 + output, 191 + }); 192 + 193 + input.emit('keypress', '/', { name: '/' }); 194 + input.emit('keypress', '', { name: 'return' }); 195 + 196 + const value = await result; 197 + 198 + expect(value).toBe('/tmp/foo'); 199 + }); 200 + 201 + test('directory mode can navigate from initial directory to child directory', async () => { 202 + const result = prompts.path({ 203 + message: 'foo', 204 + root: '/tmp/', 205 + initialValue: '/tmp/', 206 + directory: true, 207 + input, 208 + output, 209 + }); 210 + 211 + input.emit('keypress', 'f', { name: 'f' }); 212 + input.emit('keypress', '', { name: 'return' }); 213 + 214 + const value = await result; 215 + 216 + expect(value).toBe('/tmp/foo'); 217 + }); 218 + 166 219 test('default mode allows selecting files', async () => { 167 220 const result = prompts.path({ 168 221 message: 'foo',