Skip to content

feat: add support for Nushell #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions os/env/path-extender-posix/path-extender-posix.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1147,3 +1147,175 @@ end
# pnpm end`)
})
})

describe('Nushell', () => {
let configFile!: string
beforeAll(() => {
process.env.NU_VERSION = '0.92.2'
})
beforeEach(() => {
configFile = path.join(homeDir, '.config/nushell/env.nu')
})
it('should append to empty shell script', async () => {
fs.mkdirSync('.config/nushell', { recursive: true })
fs.writeFileSync(configFile, '', 'utf8')
const report = await addDirToPosixEnvPath(pnpmHomeDir, {
proxyVarName: 'PNPM_HOME',
configSectionName: 'pnpm',
})
expect(report).toStrictEqual({
configFile: {
path: configFile,
changeType: 'appended',
},
oldSettings: ``,
newSettings: `$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )`,
})
const configContent = fs.readFileSync(configFile, 'utf8')
expect(configContent).toEqual(`
# pnpm
$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )
# pnpm end
`)
})
it('should append to empty shell script without using a proxy varialbe', async () => {
fs.mkdirSync('.config/nushell', { recursive: true })
fs.writeFileSync(configFile, '', 'utf8')
const report = await addDirToPosixEnvPath(pnpmHomeDir, {
configSectionName: 'pnpm',
})
expect(report).toStrictEqual({
configFile: {
path: configFile,
changeType: 'appended',
},
oldSettings: ``,
newSettings: `$env.PATH = ($env.PATH | split row (char esep) | prepend ${pnpmHomeDir} )`,
})
const configContent = fs.readFileSync(configFile, 'utf8')
expect(configContent).toEqual(`
# pnpm
$env.PATH = ($env.PATH | split row (char esep) | prepend ${pnpmHomeDir} )
# pnpm end
`)
})
it('should add the new dir to the end of PATH', async () => {
fs.mkdirSync('.config/nushell', { recursive: true })
fs.writeFileSync(configFile, '', 'utf8')
const report = await addDirToPosixEnvPath(pnpmHomeDir, {
proxyVarName: 'PNPM_HOME',
configSectionName: 'pnpm',
position: 'end',
})
expect(report).toStrictEqual({
configFile: {
path: configFile,
changeType: 'appended',
},
oldSettings: ``,
newSettings: `$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | append $env.PNPM_HOME )`,
})
const configContent = fs.readFileSync(configFile, 'utf8')
expect(configContent).toEqual(`
# pnpm
$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | append $env.PNPM_HOME )
# pnpm end
`)
})
it('should create a shell script', async () => {
const report = await addDirToPosixEnvPath(pnpmHomeDir, {
proxyVarName: 'PNPM_HOME',
configSectionName: 'pnpm',
})
expect(report).toStrictEqual({
configFile: {
path: configFile,
changeType: 'created',
},
oldSettings: ``,
newSettings: `$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )`
})
const configContent = fs.readFileSync(configFile, 'utf8')
expect(configContent).toEqual(`# pnpm
$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )
# pnpm end
`)
})
it('should make no changes to a shell script that already has the necessary configurations', async () => {
fs.mkdirSync('.config/nushell', { recursive: true })
fs.writeFileSync(configFile, `
# pnpm
$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )
# pnpm end`, 'utf8')
const report = await addDirToPosixEnvPath(pnpmHomeDir, {
proxyVarName: 'PNPM_HOME',
configSectionName: 'pnpm',
})
expect(report).toStrictEqual({
configFile: {
path: configFile,
changeType: 'skipped',
},
oldSettings: `$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )`,
newSettings: `$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )`
})
const configContent = fs.readFileSync(configFile, 'utf8')
expect(configContent).toEqual(`
# pnpm
$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )
# pnpm end`)
})
it('should fail if the shell already has PNPM_HOME set to a different directory', async () => {
fs.mkdirSync('.config/nushell', { recursive: true })
fs.writeFileSync(configFile, `
# pnpm
$env.PNPM_HOME = "pnpm_home"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )
# pnpm end`, 'utf8')
await expect(
addDirToPosixEnvPath(pnpmHomeDir, {
proxyVarName: 'PNPM_HOME',
configSectionName: 'pnpm',
})
).rejects.toThrowError(/The config file at/)
})
it('should not fail if setup is forced', async () => {
fs.mkdirSync('.config/nushell', { recursive: true })
fs.writeFileSync(configFile, `
# pnpm
$env.PNPM_HOME = "pnpm_home"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )
# pnpm end`, 'utf8')
const report = await addDirToPosixEnvPath(pnpmHomeDir, {
proxyVarName: 'PNPM_HOME',
overwrite: true,
configSectionName: 'pnpm',
})
expect(report).toStrictEqual({
configFile: {
path: configFile,
changeType: 'modified',
},
oldSettings: `$env.PNPM_HOME = "pnpm_home"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )`,
newSettings: `$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )`
})
const configContent = fs.readFileSync(configFile, 'utf8')
expect(configContent).toEqual(`
# pnpm
$env.PNPM_HOME = "${pnpmHomeDir}"
$env.PATH = ($env.PATH | split row (char esep) | prepend $env.PNPM_HOME )
# pnpm end`)
})
})
29 changes: 27 additions & 2 deletions os/env/path-extender-posix/path-extender-posix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface AddDirToPosixEnvPathOpts {
configSectionName: string
}

export type ShellType = 'zsh' | 'bash' | 'fish' | 'ksh' | 'dash' | 'sh'
export type ShellType = 'zsh' | 'bash' | 'fish' | 'ksh' | 'dash' | 'sh' | 'nu'

export type ConfigFileChangeType = 'skipped' | 'appended' | 'modified' | 'created'

Expand Down Expand Up @@ -50,6 +50,7 @@ function detectCurrentShell () {
if (process.env.ZSH_VERSION) return 'zsh'
if (process.env.BASH_VERSION) return 'bash'
if (process.env.FISH_VERSION) return 'fish'
if (process.env.NU_VERSION) return 'nu'
return typeof process.env.SHELL === 'string' ? path.basename(process.env.SHELL) : null
}

Expand All @@ -69,8 +70,11 @@ async function updateShell (
case 'fish': {
return setupFishShell(pnpmHomeDir, opts)
}
case 'nu': {
return setupNuShell(pnpmHomeDir, opts)
}
const supportedShellsMsg = 'Supported shell languages are bash, zsh, fish, ksh, dash, and sh.'
}
const supportedShellsMsg = 'Supported shell languages are bash, zsh, fish, ksh, dash, sh, and nushell.'
if (!currentShell) throw new PnpmError('UNKNOWN_SHELL', 'Could not infer shell type.', {
hint: `Set the SHELL environment variable to your active shell.
${supportedShellsMsg}`
Expand Down Expand Up @@ -158,6 +162,27 @@ end`
}
}

async function setupNuShell (dir: string, opts: AddDirToPosixEnvPathOpts): Promise<PathExtenderPosixReport> {
const configFile = path.join(os.homedir(), '.config/nushell/env.nu')
let newSettings!: string
const addingCommand = (opts.position ?? "start") === "start" ? "prepend" : "append"
if (opts.proxyVarName) {
newSettings = `$env.${opts.proxyVarName} = "${dir}"
$env.PATH = ($env.PATH | split row (char esep) | ${addingCommand} $env.${opts.proxyVarName} )`
} else {
newSettings = `$env.PATH = ($env.PATH | split row (char esep) | ${addingCommand} ${dir} )`
}
const content = wrapSettings(opts.configSectionName, newSettings)
const { changeType, oldSettings } = await updateShellConfig(configFile, content, opts)
return {
configFile: {
path: configFile,
changeType,
},
oldSettings,
newSettings,
}
}
function wrapSettings (sectionName: string, settings: string): string {
return `# ${sectionName}
${settings}
Expand Down
Loading