mirror of
https://github.com/documentationjs/documentation.git
synced 2026-01-18 14:17:30 +00:00
GFM output is currently broken (since v13.2.2),
which prevents tables from being written to markdown.
This is because as of [remark v13.0.0][1], GFM support was added
to the remark-gfm pacakge.
6b5bc2548d
fixed parsing GFM, however, it didn't add GFM support for markdown
output.
[1]: https://github.com/remarkjs/remark/releases/tag/13.0.0
Fixes: f4a46b134f58639f352b3024801c3d98f901d66a
420 lines
11 KiB
JavaScript
420 lines
11 KiB
JavaScript
/* global jasmine */
|
|
|
|
import path from 'path';
|
|
import os from 'os';
|
|
import { exec } from 'child_process';
|
|
import tmp from 'tmp';
|
|
import fs from 'fs-extra';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
function documentation(args, options, parseJSON) {
|
|
if (!options) {
|
|
options = {};
|
|
}
|
|
if (!options.cwd) {
|
|
options.cwd = __dirname;
|
|
}
|
|
|
|
options.maxBuffer = 1024 * 1024;
|
|
|
|
args.unshift('node ' + path.join(__dirname, '..', 'bin', 'documentation.js'));
|
|
|
|
return new Promise((resolve, reject) => {
|
|
exec(args.join(' '), options, function (err, stdout, stderr) {
|
|
if (err) {
|
|
err.stderr = stderr;
|
|
return reject(err);
|
|
}
|
|
if (parseJSON === false) {
|
|
resolve(stdout);
|
|
} else {
|
|
try {
|
|
resolve(JSON.parse(stdout));
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function normalize(result) {
|
|
result.forEach(function (item) {
|
|
item.context.file = '[path]';
|
|
});
|
|
return result;
|
|
}
|
|
|
|
test('documentation binary', async function () {
|
|
const data = await documentation(['build fixture/simple.input.js'], {});
|
|
expect(data.length).toBe(1);
|
|
});
|
|
|
|
test.skip('defaults to parsing package.json main', async function () {
|
|
const data = await documentation(['build'], {
|
|
cwd: path.join(__dirname, '..')
|
|
});
|
|
expect(data.length).toBeTruthy();
|
|
});
|
|
|
|
test('accepts config file', async function () {
|
|
const data = await documentation([
|
|
'build fixture/sorting/input.js -c fixture/config.json'
|
|
]);
|
|
expect(normalize(data)).toMatchSnapshot();
|
|
});
|
|
|
|
test('accepts config file - reports failures', async function () {
|
|
try {
|
|
await documentation(
|
|
['build fixture/sorting/input.js -c fixture/config-bad.yml'],
|
|
{},
|
|
false
|
|
);
|
|
} catch (stderr) {
|
|
expect(stderr).toMatchSnapshot();
|
|
}
|
|
});
|
|
|
|
test('accepts config file - reports parse failures', async function () {
|
|
try {
|
|
await documentation(
|
|
['build fixture/sorting/input.js -c fixture/config-malformed.json'],
|
|
{},
|
|
false
|
|
);
|
|
} catch (stderr) {
|
|
expect(stderr.stderr.match(/SyntaxError/g)).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('--shallow option', async function () {
|
|
const data = await documentation([
|
|
'build --shallow fixture/internal.input.js'
|
|
]);
|
|
expect(data.length).toBe(0);
|
|
});
|
|
|
|
test('when a file is specified both in a glob and explicitly, it is only documented once', async function () {
|
|
const data = await documentation([
|
|
'build fixture/simple.input.js fixture/simple.input.*'
|
|
]);
|
|
expect(data.length).toBe(1);
|
|
});
|
|
|
|
test('extension option', async function () {
|
|
const data = await documentation([
|
|
'build fixture/extension/index.otherextension ' +
|
|
'--requireExtension=otherextension --parseExtension=otherextension'
|
|
]);
|
|
expect(data.length).toBe(1);
|
|
});
|
|
|
|
test('extension option', function () {
|
|
return documentation(['build fixture/extension.jsx']);
|
|
});
|
|
|
|
describe('invalid arguments', function () {
|
|
test('bad -f option', async function () {
|
|
try {
|
|
await documentation(
|
|
['build -f DOES-NOT-EXIST fixture/internal.input.js'],
|
|
{},
|
|
false
|
|
);
|
|
} catch (err) {
|
|
expect(err).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('html with no destination', async function () {
|
|
try {
|
|
await documentation(['build -f html fixture/internal.input.js']);
|
|
} catch (err) {
|
|
expect(
|
|
err
|
|
.toString()
|
|
.match(
|
|
/The HTML output mode requires a destination directory set with -o/
|
|
)
|
|
).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('bad command', async function () {
|
|
try {
|
|
await documentation(['-f html fixture/internal.input.js'], {}, false);
|
|
} catch (err) {
|
|
expect(err.code).toBeTruthy();
|
|
}
|
|
});
|
|
});
|
|
|
|
const semver =
|
|
/\bv?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?\b/gi;
|
|
test('--config', async function () {
|
|
const dst = path.join(os.tmpdir(), (Date.now() + Math.random()).toString());
|
|
fs.mkdirSync(dst);
|
|
const outputIndex = path.join(dst, 'index.html');
|
|
const data = await documentation(
|
|
[
|
|
'build -c fixture/html/documentation.yml -f html fixture/html/nested.input.js -o ' +
|
|
dst
|
|
],
|
|
{},
|
|
false
|
|
);
|
|
let output = fs.readFileSync(outputIndex, 'utf8');
|
|
const version = (await import('../package.json')).default.version;
|
|
output = output.replace(new RegExp(version.replace(/\./g, '\\.'), 'g'), '');
|
|
expect(output).toMatchSnapshot();
|
|
});
|
|
|
|
test('--version', async function () {
|
|
const output = await documentation(['--version'], {}, false);
|
|
expect(output).toBeTruthy();
|
|
});
|
|
|
|
describe('lint command', function () {
|
|
test('generates lint output', async function () {
|
|
try {
|
|
await documentation(['lint fixture/lint/lint.input.js'], {}, false);
|
|
} catch (err) {
|
|
const data = err.stderr.toString().split('\n').slice(2).join('\n');
|
|
expect(data).toMatchSnapshot();
|
|
}
|
|
});
|
|
|
|
test('generates no output on a good file', async function () {
|
|
const data = await documentation(
|
|
['lint fixture/simple.input.js'],
|
|
{},
|
|
false
|
|
);
|
|
expect(data).toBe('');
|
|
});
|
|
|
|
test('exposes syntax error on a bad file', async function () {
|
|
try {
|
|
await documentation(
|
|
['lint fixture/bad/syntax.input', '--parseExtension input'],
|
|
{},
|
|
false
|
|
);
|
|
} catch (err) {
|
|
expect(err.code > 0).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('lint with no inputs', async function () {
|
|
try {
|
|
await documentation(
|
|
['lint'],
|
|
{
|
|
cwd: path.join(__dirname, 'fixture/bad')
|
|
},
|
|
false
|
|
);
|
|
} catch (err) {
|
|
expect(err.code > 0).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('generates lint output with shallow', async function () {
|
|
const data = await documentation(
|
|
['lint fixture/lint/lint.input.shallow.js --shallow'],
|
|
{},
|
|
false
|
|
);
|
|
expect(data).toBe('');
|
|
});
|
|
});
|
|
|
|
test('given no files', async function () {
|
|
try {
|
|
await documentation(['build']);
|
|
} catch (err) {
|
|
expect(
|
|
err
|
|
.toString()
|
|
.match(
|
|
/documentation was given no files and was not run in a module directory/
|
|
)
|
|
).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('with an invalid command', async function () {
|
|
try {
|
|
await documentation(['invalid'], {}, false);
|
|
} catch (err) {
|
|
expect(err).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test.skip('--access flag', async function () {
|
|
const data = await documentation(
|
|
['build --shallow fixture/internal.input.js -a public'],
|
|
{},
|
|
false
|
|
);
|
|
expect(data).toBe('[]');
|
|
});
|
|
|
|
test.skip('--infer-private flag', async function () {
|
|
const data = await documentation(
|
|
['build fixture/infer-private.input.js --infer-private ^_'],
|
|
{},
|
|
false
|
|
);
|
|
// This uses JSON.parse with a reviver used as a visitor.
|
|
JSON.parse(data, function (n, v) {
|
|
// Make sure we do not see any names that match `^_`.
|
|
if (n === 'name') {
|
|
expect(typeof v).toBe('string');
|
|
expect(!/_$/.test.skip(v)).toBeTruthy();
|
|
}
|
|
return v;
|
|
});
|
|
});
|
|
|
|
test.skip('write to file', async function () {
|
|
const dst = path.join(os.tmpdir(), (Date.now() + Math.random()).toString());
|
|
|
|
const data = await documentation(
|
|
['build --shallow fixture/internal.input.js -o ' + dst],
|
|
{},
|
|
false
|
|
);
|
|
expect(data).toBe('');
|
|
expect(fs.existsSync(dst)).toBeTruthy();
|
|
});
|
|
|
|
test.skip('write to html', async function () {
|
|
const dstDir = path.join(
|
|
os.tmpdir(),
|
|
(Date.now() + Math.random()).toString()
|
|
);
|
|
fs.mkdirSync(dstDir);
|
|
|
|
const data = await documentation(
|
|
['build --shallow fixture/internal.input.js -f html -o ' + dstDir],
|
|
{},
|
|
false
|
|
);
|
|
expect(data).toBe('');
|
|
expect(fs.existsSync(path.join(dstDir, 'index.html'))).toBeTruthy();
|
|
});
|
|
|
|
test.skip('write to html with custom theme', async function () {
|
|
const dstDir = path.join(
|
|
os.tmpdir(),
|
|
(Date.now() + Math.random()).toString()
|
|
);
|
|
fs.mkdirSync(dstDir);
|
|
|
|
const data = await documentation(
|
|
[
|
|
'build -t fixture/custom_theme --shallow fixture/internal.input.js -f html -o ' +
|
|
dstDir
|
|
],
|
|
{},
|
|
false
|
|
);
|
|
expect(data).toBe('');
|
|
expect(fs.readFileSync(path.join(dstDir, 'index.html'), 'utf8')).toBeTruthy();
|
|
});
|
|
|
|
test.skip('write to html, highlightAuto', function () {
|
|
const fixture = 'fixture/auto_lang_hljs/multilanguage.input.js';
|
|
const config = 'fixture/auto_lang_hljs/config.yml';
|
|
const dstDir = path.join(
|
|
os.tmpdir(),
|
|
(Date.now() + Math.random()).toString()
|
|
);
|
|
|
|
fs.mkdirSync(dstDir);
|
|
|
|
return documentation(
|
|
['build --shallow ' + fixture + ' -c ' + config + ' -f html -o ' + dstDir],
|
|
{},
|
|
false
|
|
).then(() => {
|
|
const result = fs.readFileSync(path.join(dstDir, 'index.html'), 'utf8');
|
|
expect(
|
|
result.indexOf('<span class="hljs-number">42</span>') > 0
|
|
).toBeTruthy();
|
|
expect(
|
|
result.indexOf('<span class="hljs-selector-attr">[data-foo]</span>') > 0
|
|
).toBeTruthy();
|
|
expect(
|
|
result.indexOf('<span class="hljs-attr">data-foo</span>') > 0
|
|
).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
test.skip('fatal error', async function () {
|
|
try {
|
|
await documentation(
|
|
['build --shallow fixture/bad/syntax.input --parseExtension input'],
|
|
{},
|
|
false
|
|
);
|
|
} catch (err) {
|
|
expect(err.toString().match(/Unexpected token/)).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('build GFM (e.g. markdown tables) for -f md', async function () {
|
|
const data = await documentation(
|
|
['build', 'fixture/html/nested.input.js', '--shallow', '-f', 'md'],
|
|
{},
|
|
false
|
|
);
|
|
expect(data).toMatchSnapshot();
|
|
expect(data).toMatch(
|
|
`| Col 1 | Col 2 | Col 3 |
|
|
| ----- | ----- | ----- |
|
|
| Dat 1 | Dat 2 | Dat 3 |
|
|
| Dat 4 | Dat 5 | Dat 6 |`
|
|
);
|
|
});
|
|
|
|
test.skip('build --document-exported', async function () {
|
|
const data = await documentation(
|
|
['build fixture/document-exported.input.js --document-exported -f md'],
|
|
{},
|
|
false
|
|
);
|
|
expect(data).toMatchSnapshot();
|
|
});
|
|
|
|
test.skip('build large file without error (no deoptimized styling error)', function () {
|
|
const dstFile =
|
|
path.join(os.tmpdir(), (Date.now() + Math.random()).toString()) + '.js';
|
|
let contents = '';
|
|
for (let i = 0; i < 4e4; i++) {
|
|
contents += '/* - */\n';
|
|
}
|
|
fs.writeFileSync(dstFile, contents, 'utf8');
|
|
|
|
return documentation(['build ' + dstFile], {}, false).then(() => {
|
|
fs.unlinkSync(dstFile);
|
|
});
|
|
});
|
|
|
|
test.skip('should use browser resolve', async function () {
|
|
const data = await documentation(['build fixture/resolve/index.js']);
|
|
expect(normalize(data)).toMatchSnapshot();
|
|
});
|
|
|
|
test.skip('should use node resolve', async function () {
|
|
const data = await documentation([
|
|
'build fixture/resolve/index.js --resolve node'
|
|
]);
|
|
expect(normalize(data)).toMatchSnapshot();
|
|
});
|