Skip to content
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

Fix Windows portability issues, move fakeJsdoc to jsdocStub #1

Merged
merged 3 commits into from
Dec 28, 2023
Merged
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
15 changes: 11 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,23 @@ export async function runJsdoc(argv, env, platform) {
return {exitCode}
}

/**
* The key for the command search path within process.env.
*
* On every system other than Windows, this will be "PATH". On Windows, this
* will be "Path".
*/
export const PATH_KEY = process.platform !== 'win32' ? 'PATH' : 'Path'

/**
* Returns the full path to the specified command
* @param {string} cmdName - command to find in env.PATH
* @param {string} cmdName - command to find in env[PATH_KEY]
* @param {object} env - environment variables, presumably process.env
* @param {string} env.PATH - the PATH environment variable
* @param {string} platform - the process.platform string
* @returns {Promise<string>} - path to the command
*/
export async function getPath(cmdName, env, platform) {
for (const p of env.PATH.split(path.delimiter)) {
for (const p of env[PATH_KEY].split(path.delimiter)) {
// pnpm will install both the original script and versions ending with .CMD
// and .ps1. We'll just default to .CMD.
const extension = (platform === 'win32') ? '.CMD' : ''
Expand All @@ -73,7 +80,7 @@ export async function getPath(cmdName, env, platform) {
return candidate
} catch { /* try next candidate */ }
}
return Promise.reject(`${cmdName} not found in PATH`)
return Promise.reject(`${cmdName} not found in ${PATH_KEY}`)
}

/**
Expand Down
3 changes: 2 additions & 1 deletion test/fixtures/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ export function fixtureEnv(fixtureName) {
const paths = [
path.join('usr', 'local', 'bin'), path.join('usr', 'bin'), 'bin'
]
return { PATH: paths.map(p => path.join(root, p)).join(path.delimiter) }
const pathKey = process.platform !== 'win32' ? 'PATH' : 'Path'
return {[pathKey]: paths.map(p => path.join(root, p)).join(path.delimiter)}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
:: https://stackoverflow.com/questions/5034076/what-does-dp0-mean-and-how-does-it-work
:: https://ss64.com/nt/
:: https://htipe.wordpress.com/2008/10/09/the-dp0-variable/
@echo off
node "%~dp0\jsdoc" %*
4 changes: 2 additions & 2 deletions test/getPath.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import { getPath } from '../lib'
import { getPath, PATH_KEY } from '../lib'
import { fixturePath, fixtureEnv } from './fixtures'
import { describe, expect, test } from 'vitest'
import path from 'node:path'
Expand All @@ -26,6 +26,6 @@ describe('getPath', () => {

test('rejects when command isn\'t found', async () => {
await expect(getPath('nonexistent', env, process.platform)).rejects
.toBe('nonexistent not found in PATH')
.toBe(`nonexistent not found in ${PATH_KEY}`)
})
})
27 changes: 12 additions & 15 deletions test/main.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,25 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import { getPath } from '../lib'
import { getPath, PATH_KEY } from '../lib'
import { fixturePath } from './fixtures'
import DestDirHelper from './DestDirHelper'
import { afterEach, describe, expect, test } from 'vitest'
import { spawn } from 'node:child_process'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

describe('jsdoc-cli-wrapper', () => {
const root = fixturePath('fakeJsdoc')
const root = fixturePath('jsdocStub')
const destDirHelper = new DestDirHelper()
const mainPath = fileURLToPath(new URL('../index.js', import.meta.url))

afterEach(async () => await destDirHelper.cleanup())

const spawnMain = async(testEnvPath, ...argv) => {
const origPath = process.env.PATH
process.env.PATH = testEnvPath

const result = await new Promise(resolve => {
const mainPath = new URL('../index.js', import.meta.url).pathname
const wrapper = spawn(mainPath, argv)
const spawnMain = (testEnvPath, ...argv) => {
return new Promise((resolve, reject) => {
const env = {...process.env, [PATH_KEY]: testEnvPath}
const wrapper = spawn(process.execPath, [mainPath, ...argv], {env})
let stdout = ''
let stderr = ''

Expand All @@ -36,23 +35,21 @@ describe('jsdoc-cli-wrapper', () => {
if (stderr) result.stderr = stderr
resolve(result)
})
wrapper.on('error', (err) => reject(err))
})

process.env.PATH = origPath
return result
}

const runMain = async (...argv) => {
const testEnvPath = [root, process.env.PATH].join(path.delimiter)
const testEnvPath = [root, process.env[PATH_KEY]].join(path.delimiter)
return spawnMain(testEnvPath, ...argv)
}

const runMainWithoutJsdoc = async (...argv) => {
let testEnvPath = process.env.PATH
let testEnvPath = process.env[PATH_KEY]

try {
const jsdocPath = await getPath('jsdoc', process.env, process.platform)
const jsdocDir = path.dirname(jsdocPath)
const jsdocDir = path.dirname(jsdocPath).replaceAll('\\', '\\\\')
const pat = new RegExp(`${path.delimiter}?${jsdocDir}${path.delimiter}?`)
testEnvPath = testEnvPath.replace(pat, '')
} catch { /* It's OK if it's not actually installed. */ }
Expand Down
8 changes: 4 additions & 4 deletions test/runJsdoc.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import { runJsdoc } from '../lib'
import { runJsdoc, PATH_KEY } from '../lib'
import { fixturePath } from './fixtures'
import DestDirHelper from './DestDirHelper'
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
import path from 'node:path'

describe('runJsdoc', () => {
const root = fixturePath('fakeJsdoc')
const env = { PATH: root }
const root = fixturePath('jsdocStub')
const env = { [PATH_KEY]: root }
const platform = process.platform
const destDirHelper = new DestDirHelper()

Expand All @@ -35,7 +35,7 @@ describe('runJsdoc', () => {
test('emits error if jsdoc not found', async () => {
const bogusPath = path.join(root, 'nonexistent')

await expect(runJsdoc(argv, {PATH: bogusPath}, platform))
await expect(runJsdoc(argv, {[PATH_KEY]: bogusPath}, platform))
.rejects.toContain('npm add -g jsdoc')
await expect(readIndexHtml()).resolves.toStrictEqual({
actualPath: origIndexPath, content: 'Old and Busted'
Expand Down