Skip to content

Commit 75239ef

Browse files
committed
npm
1 parent 00b9ec9 commit 75239ef

File tree

4 files changed

+116
-1
lines changed

4 files changed

+116
-1
lines changed

packages/inquirerer/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,12 @@ const questions = [
700700
message: 'Author email?',
701701
defaultFrom: 'git.user.email' // Auto-fills from git config
702702
},
703+
{
704+
type: 'text',
705+
name: 'npmUser',
706+
message: 'NPM username?',
707+
defaultFrom: 'npm.whoami' // Auto-fills from npm whoami
708+
},
703709
{
704710
type: 'text',
705711
name: 'copyrightYear',
@@ -723,6 +729,12 @@ Inquirerer comes with several built-in resolvers ready to use:
723729
| `git.user.name` | Git global user name | `"John Doe"` |
724730
| `git.user.email` | Git global user email | `"[email protected]"` |
725731

732+
#### NPM
733+
734+
| Resolver | Description | Example Output |
735+
|----------|-------------|----------------|
736+
| `npm.whoami` | Currently logged in npm user | `"johndoe"` |
737+
726738
#### Date & Time
727739

728740
| Resolver | Description | Example Output |

packages/inquirerer/__tests__/resolvers.test.ts

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {
33
globalResolverRegistry,
44
registerDefaultResolver,
55
resolveDefault,
6-
getGitConfig
6+
getGitConfig,
7+
getNpmWhoami
78
} from '../src/resolvers';
89

910
// Mock child_process.execSync for git config tests
@@ -245,6 +246,75 @@ describe('Git Resolvers', () => {
245246
});
246247
});
247248

249+
describe('NPM Resolvers', () => {
250+
beforeEach(() => {
251+
jest.clearAllMocks();
252+
});
253+
254+
describe('getNpmWhoami', () => {
255+
it('should return npm username when logged in', () => {
256+
mockedExecSync.mockReturnValue('johndoe\n' as any);
257+
258+
const result = getNpmWhoami();
259+
260+
expect(result).toBe('johndoe');
261+
expect(mockedExecSync).toHaveBeenCalledWith(
262+
'npm whoami',
263+
expect.objectContaining({
264+
encoding: 'utf8',
265+
stdio: ['pipe', 'pipe', 'ignore']
266+
})
267+
);
268+
});
269+
270+
it('should trim whitespace from npm username', () => {
271+
mockedExecSync.mockReturnValue(' janedoe \n' as any);
272+
273+
const result = getNpmWhoami();
274+
275+
expect(result).toBe('janedoe');
276+
});
277+
278+
it('should return undefined when not logged in to npm', () => {
279+
mockedExecSync.mockImplementation(() => {
280+
throw new Error('Not logged in');
281+
});
282+
283+
const result = getNpmWhoami();
284+
285+
expect(result).toBeUndefined();
286+
});
287+
288+
it('should return undefined when npm whoami returns empty string', () => {
289+
mockedExecSync.mockReturnValue('' as any);
290+
291+
const result = getNpmWhoami();
292+
293+
expect(result).toBeUndefined();
294+
});
295+
});
296+
297+
describe('npm.whoami resolver', () => {
298+
it('should resolve npm username', async () => {
299+
mockedExecSync.mockReturnValue('npmuser\n' as any);
300+
301+
const result = await globalResolverRegistry.resolve('npm.whoami');
302+
303+
expect(result).toBe('npmuser');
304+
});
305+
306+
it('should return undefined when npm not logged in', async () => {
307+
mockedExecSync.mockImplementation(() => {
308+
throw new Error('Not logged in');
309+
});
310+
311+
const result = await globalResolverRegistry.resolve('npm.whoami');
312+
313+
expect(result).toBeUndefined();
314+
});
315+
});
316+
});
317+
248318
describe('Date Resolvers', () => {
249319
beforeEach(() => {
250320
// Mock Date to return consistent values
@@ -328,6 +398,10 @@ describe('Global Registry', () => {
328398
expect(globalResolverRegistry.has('git.user.email')).toBe(true);
329399
});
330400

401+
it('should have npm resolvers registered by default', () => {
402+
expect(globalResolverRegistry.has('npm.whoami')).toBe(true);
403+
});
404+
331405
it('should have date resolvers registered by default', () => {
332406
expect(globalResolverRegistry.has('date.year')).toBe(true);
333407
expect(globalResolverRegistry.has('date.month')).toBe(true);

packages/inquirerer/src/resolvers/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { gitResolvers } from './git';
22
import { dateResolvers } from './date';
3+
import { npmResolvers } from './npm';
34
import type { DefaultResolver, ResolverRegistry } from './types';
45

56
/**
@@ -88,6 +89,7 @@ export class DefaultResolverRegistry {
8889
export const globalResolverRegistry = new DefaultResolverRegistry({
8990
...gitResolvers,
9091
...dateResolvers,
92+
...npmResolvers,
9193
});
9294

9395
/**
@@ -111,3 +113,4 @@ export function resolveDefault(key: string): Promise<any> {
111113
// Re-export types and utilities
112114
export type { DefaultResolver, ResolverRegistry } from './types';
113115
export { getGitConfig } from './git';
116+
export { getNpmWhoami } from './npm';
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { execSync } from 'child_process';
2+
import type { ResolverRegistry } from './types';
3+
4+
/**
5+
* Retrieves the currently logged in npm user.
6+
* @returns The npm username, or undefined if not logged in or error occurs
7+
*/
8+
export function getNpmWhoami(): string | undefined {
9+
try {
10+
const result = execSync('npm whoami', {
11+
encoding: 'utf8',
12+
stdio: ['pipe', 'pipe', 'ignore'] // Suppress stderr
13+
});
14+
const trimmed = result.trim();
15+
return trimmed || undefined; // Treat empty string as undefined
16+
} catch {
17+
return undefined;
18+
}
19+
}
20+
21+
/**
22+
* Built-in npm resolvers.
23+
*/
24+
export const npmResolvers: ResolverRegistry = {
25+
'npm.whoami': () => getNpmWhoami(),
26+
};

0 commit comments

Comments
 (0)