All files / src/utils project-name.ts

88.88% Statements 40/45
89.47% Branches 17/19
100% Functions 1/1
88.88% Lines 40/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102        1x                                                                                             1x 46x 46x 46x 46x   46x 46x 40x 40x   46x 4x 4x 4x 4x 4x   46x 1x 1x 1x 1x 1x 1x             41x 46x 3x 46x 38x 38x   41x 46x 4x 46x 37x 37x   41x 41x 41x 41x 41x  
/**
 * Project name utilities
 */
 
import { basename, isAbsolute, normalize, resolve } from 'node:path';
 
export interface ProjectNameResult {
    name: string;
    root: string;
}
 
/**
 * Format project name and determine target directory
 *
 * Examples:
 * 1. Input: 'foo', cwd: '/home/user' (Unix)
 *    Output: { name: 'foo', root: '/home/user/foo' }
 *    Input: 'foo', cwd: 'C:\\workspace' (Windows)
 *    Output: { name: 'foo', root: 'C:\\workspace\\foo' }
 *
 * 2. Input: 'foo/bar', cwd: '/home/user' (Unix)
 *    Output: { name: 'bar', root: '/home/user/foo/bar' }
 *    Input: 'foo\\bar', cwd: 'C:\\workspace' (Windows)
 *    Output: { name: 'bar', root: 'C:\\workspace\\foo\\bar' }
 *
 * 3. Input: '@scope/foo', cwd: '/home/user' (Unix)
 *    Output: { name: '@scope/foo', root: '/home/user/@scope/foo' }
 *    Input: '@scope/foo', cwd: 'C:\\workspace' (Windows)
 *    Output: { name: '@scope/foo', root: 'C:\\workspace\\@scope\\foo' }
 *
 * 4. Input: './foo/bar', cwd: '/home/user/current' (Unix)
 *    Output: { name: 'bar', root: '/home/user/current/foo/bar' }
 *    Input: '.\\foo\\bar', cwd: 'C:\\workspace\\current' (Windows)
 *    Output: { name: 'bar', root: 'C:\\workspace\\current\\foo\\bar' }
 *
 * 5. Input: '/root/path/to/foo', cwd: '/home/user' (Unix absolute)
 *    Output: { name: 'foo', root: '/root/path/to/foo' }
 *    Input: 'C:\\projects\\my-app', cwd: 'D:\\workspace' (Windows absolute)
 *    Output: { name: 'my-app', root: 'C:\\projects\\my-app' }
 *
 * 6. Input: '.', cwd: '/home/user/projects/my-app' (Unix current dir)
 *    Output: { name: 'my-app', root: '/home/user/projects/my-app' }
 *    Input: '.', cwd: 'C:\\Users\\Developer\\Projects\\WindowsApp' (Windows current dir)
 *    Output: { name: 'WindowsApp', root: 'C:\\Users\\Developer\\Projects\\WindowsApp' }
 *
 * 7. Input: '\\\\server\\share\\project', cwd: 'C:\\workspace' (Windows UNC)
 *    Output: { name: 'project', root: '\\\\server\\share\\project' }
 *
 * 8. Input: 'path\\to/project', cwd: '/home/user' (Mixed separators)
 *    Output: { name: 'project', root: '/home/user/path/to/project' }
 */
export function formatProjectName(
    input: string,
    cwd?: string
): ProjectNameResult {
    const workingDir = cwd || process.cwd();
 
    let cleanInput = input;
    if (input !== '/' && input !== '\\' && input.length > 1) {
        cleanInput = input.replace(/[\\/]+$/, '');
    }
 
    if (cleanInput === '.') {
        return {
            name: basename(workingDir),
            root: workingDir
        };
    }
 
    if (cleanInput === '' || cleanInput === '/' || cleanInput === '\\') {
        if (cleanInput === '/') {
            return {
                name: 'esmx-project',
                root: '/'
            };
        }
        return {
            name: 'esmx-project',
            root: resolve(workingDir, 'esmx-project')
        };
    }
 
    let root: string;
    if (isAbsolute(cleanInput)) {
        root = normalize(cleanInput);
    } else {
        root = resolve(workingDir, cleanInput);
    }
 
    let name: string;
    if (cleanInput.startsWith('@')) {
        name = cleanInput;
    } else {
        name = basename(normalize(cleanInput)) || 'esmx-project';
    }
 
    return {
        name,
        root
    };
}