Skip to content

Commit 2317a89

Browse files
committed
Fix regression caused by spaces in the jsdoc binary path. jsdoc2md/jsdoc-to-markdown#307
Add Windows testing to CI
1 parent dceef69 commit 2317a89

File tree

9 files changed

+109
-54
lines changed

9 files changed

+109
-54
lines changed

.github/workflows/node.js.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ name: Node.js CI
44

55
on:
66
push:
7-
branches: [ master ]
7+
branches: [ master, next ]
88
pull_request:
99
branches: [ master ]
1010

@@ -15,7 +15,7 @@ jobs:
1515

1616
strategy:
1717
matrix:
18-
os: [ubuntu-latest] # Remove windows as tests fail on `\r\n` style newlines
18+
os: [ubuntu-latest, windows-latest]
1919
node-version: [12, 14, 16, 18, 20, 22, 23]
2020

2121
steps:
@@ -26,5 +26,6 @@ jobs:
2626
node-version: ${{ matrix.node-version }}
2727
cache: 'npm'
2828
- run: npm install
29-
- run: npm i -g @75lb/nature
29+
- run: npm i -D @75lb/nature
3030
- run: npm run test:ci
31+

dist/index.cjs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class JsdocCommand {
100100
}
101101
}
102102

103-
const exec = util.promisify(cp.exec);
103+
util.promisify(cp.exec);
104104

105105
class Explain extends JsdocCommand {
106106
async getOutput () {
@@ -120,18 +120,39 @@ class Explain extends JsdocCommand {
120120
}
121121

122122
async _runJsdoc () {
123-
const cmd = this.options.source.length
124-
? `node ${this.jsdocPath} ${toSpawnArgs(this.jsdocOptions).join(' ')} -X ${this.tempFileSet.files.join(' ')}`
125-
: `node ${this.jsdocPath} ${toSpawnArgs(this.jsdocOptions).join(' ')} -X ${this.inputFileSet.files.join(' ')}`;
126-
123+
const jsdocArgs = [
124+
this.jsdocPath,
125+
...toSpawnArgs(this.jsdocOptions),
126+
'-X',
127+
...(this.options.source.length ? this.tempFileSet.files : this.inputFileSet.files)
128+
];
127129
let jsdocOutput = { stdout: '', stderr: '' };
130+
131+
const code = await new Promise((resolve, reject) => {
132+
const handle = cp.spawn('node', jsdocArgs);
133+
handle.stdout.setEncoding('utf8');
134+
handle.stderr.setEncoding('utf8');
135+
handle.stdout.on('data', chunk => {
136+
jsdocOutput.stdout += chunk;
137+
});
138+
handle.stderr.on('data', chunk => {
139+
jsdocOutput.stderr += chunk;
140+
});
141+
handle.on('exit', (code) => {
142+
resolve(code);
143+
});
144+
handle.on('error', reject);
145+
});
128146
try {
129-
jsdocOutput = await exec(cmd, { maxBuffer: 1024 * 1024 * 100 }); /* 100MB */
130-
const explainOutput = JSON.parse(jsdocOutput.stdout);
131-
if (this.options.cache) {
132-
await this.cache.write(this.cacheKey, explainOutput);
147+
if (code > 0) {
148+
throw new Error('jsdoc exited with non-zero code: ' + code)
149+
} else {
150+
const explainOutput = JSON.parse(jsdocOutput.stdout);
151+
if (this.options.cache) {
152+
await this.cache.write(this.cacheKey, explainOutput);
153+
}
154+
return explainOutput
133155
}
134-
return explainOutput
135156
} catch (err) {
136157
const firstLineOfStdout = jsdocOutput.stdout.split(/\r?\n/)[0];
137158
const jsdocErr = new Error(jsdocOutput.stderr.trim() || firstLineOfStdout || 'Jsdoc failed.');

lib/explain.js

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,39 @@ class Explain extends JsdocCommand {
2323
}
2424

2525
async _runJsdoc () {
26-
const cmd = this.options.source.length
27-
? `node ${this.jsdocPath} ${toSpawnArgs(this.jsdocOptions).join(' ')} -X ${this.tempFileSet.files.join(' ')}`
28-
: `node ${this.jsdocPath} ${toSpawnArgs(this.jsdocOptions).join(' ')} -X ${this.inputFileSet.files.join(' ')}`
29-
26+
const jsdocArgs = [
27+
this.jsdocPath,
28+
...toSpawnArgs(this.jsdocOptions),
29+
'-X',
30+
...(this.options.source.length ? this.tempFileSet.files : this.inputFileSet.files)
31+
]
3032
let jsdocOutput = { stdout: '', stderr: '' }
33+
34+
const code = await new Promise((resolve, reject) => {
35+
const handle = cp.spawn('node', jsdocArgs)
36+
handle.stdout.setEncoding('utf8')
37+
handle.stderr.setEncoding('utf8')
38+
handle.stdout.on('data', chunk => {
39+
jsdocOutput.stdout += chunk
40+
})
41+
handle.stderr.on('data', chunk => {
42+
jsdocOutput.stderr += chunk
43+
})
44+
handle.on('exit', (code) => {
45+
resolve(code)
46+
})
47+
handle.on('error', reject)
48+
})
3149
try {
32-
jsdocOutput = await exec(cmd, { maxBuffer: 1024 * 1024 * 100 }) /* 100MB */
33-
const explainOutput = JSON.parse(jsdocOutput.stdout)
34-
if (this.options.cache) {
35-
await this.cache.write(this.cacheKey, explainOutput)
50+
if (code > 0) {
51+
throw new Error('jsdoc exited with non-zero code: ' + code)
52+
} else {
53+
const explainOutput = JSON.parse(jsdocOutput.stdout)
54+
if (this.options.cache) {
55+
await this.cache.write(this.cacheKey, explainOutput)
56+
}
57+
return explainOutput
3658
}
37-
return explainOutput
3859
} catch (err) {
3960
const firstLineOfStdout = jsdocOutput.stdout.split(/\r?\n/)[0]
4061
const jsdocErr = new Error(jsdocOutput.stderr.trim() || firstLineOfStdout || 'Jsdoc failed.')

package-lock.json

Lines changed: 15 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
},
2727
"scripts": {
2828
"test": "npm run dist && npm run test:ci",
29-
"test:ci": "75lb-nature test-runner test/*.js",
29+
"test:ci": "75lb-nature test-runner test/caching.js test/explain.js test/render.js",
3030
"dist": "75lb-nature cjs-build index.js",
3131
"docs": "75lb-nature jsdoc2md index.js lib/*.js > docs/api.md"
3232
},

test/caching.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ test.set('.explain({ files, cache: true })', async function () {
1111
const f = new Fixture('class-all')
1212
jsdoc.cache.dir = 'tmp/test/cache1'
1313
await jsdoc.cache.clear()
14-
const output = await jsdoc.explain({ files: f.sourcePath, cache: true })
15-
const cachedFiles = readdirSync(jsdoc.cache.dir)
16-
.map(file => path.resolve(jsdoc.cache.dir, file))
14+
let output = await jsdoc.explain({ files: f.sourcePath, cache: true })
15+
output = Fixture.normaliseNewLines(output)
16+
const cachedFiles = readdirSync(jsdoc.cache.dir).map(file => path.resolve(jsdoc.cache.dir, file))
1717
a.equal(cachedFiles.length, 1)
1818
a.deepEqual(output, f.getExpectedOutput(output))
19-
const cachedData = JSON.parse(readFileSync(cachedFiles[0], 'utf8'))
19+
let cachedData = JSON.parse(readFileSync(cachedFiles[0], 'utf8'))
20+
cachedData = Fixture.normaliseNewLines(cachedData)
2021
Fixture.removeFileSpecificData(cachedData)
2122
a.deepEqual(
2223
cachedData,

test/explain.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ const [test, only, skip] = [new Map(), new Map(), new Map()]
77

88
test.set('.explain({ files })', async function () {
99
const f = new Fixture('class-all')
10-
const output = await jsdoc.explain({ files: f.sourcePath })
10+
let output = await jsdoc.explain({ files: f.sourcePath })
11+
output = Fixture.normaliseNewLines(output)
1112
a.deepEqual(output, f.getExpectedOutput(output))
1213
})
1314

1415
test.set('.explain({ source })', async function () {
1516
const f = new Fixture('class-all')
16-
const output = await jsdoc.explain({ source: f.getSource() })
17+
let output = await jsdoc.explain({ source: f.getSource() })
18+
output = Fixture.normaliseNewLines(output)
1719
a.deepEqual(output, f.getExpectedOutput(output))
1820
})
1921

@@ -47,4 +49,12 @@ test.set('.explain({ files }): files is empty', async function () {
4749
)
4850
})
4951

52+
test.set('Spaces in jsdoc command path', async function () {
53+
process.env.JSDOC_PATH = 'test/fixture/folder with spaces/fake-jsdoc.js'
54+
const f = new Fixture('class-all')
55+
let output = await jsdoc.explain({ files: f.sourcePath })
56+
a.equal(output.length, 4)
57+
process.env.JSDOC_PATH = ''
58+
})
59+
5060
export { test, only, skip }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log(JSON.stringify(process.argv))

test/lib/fixture.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ class Fixture {
4444
}
4545
})
4646
}
47+
48+
static normaliseNewLines (doclets) {
49+
const input = JSON.stringify(doclets, null, ' ')
50+
/* Normalise all newlines to posix style to avoid differences while testing on Windows */
51+
let result = input.replace(/\\r?\\n/gm, '\\n')
52+
/* Additional check for naked \r characters created by jsdoc */
53+
/* See: https://github.com/jsdoc2md/dmd/issues/102 */
54+
result = result.replace(/\\r(?!\\n)/g, '\\n')
55+
return JSON.parse(result)
56+
}
4757
}
4858

4959
export default Fixture

0 commit comments

Comments
 (0)