Skip to content

Commit

Permalink
feat: Support for extended config in typedoc.json
Browse files Browse the repository at this point in the history
Closes #493
Closes #1115

Co-Authored-By: Richie Bendall <richiebendall@gmail.com>
  • Loading branch information
Gerrit0 and Richienb committed Feb 28, 2020
1 parent 20db9a5 commit 07fb1ce
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 7 deletions.
44 changes: 38 additions & 6 deletions src/lib/utils/options/readers/typedoc.ts
Expand Up @@ -25,7 +25,7 @@ export class TypeDocReader implements OptionsReader {
*/
read(container: Options, logger: Logger): void {
const path = container.getValue('options');
const file = this.findTypedocFile(path, logger);
const file = this.findTypedocFile(path);

if (!file) {
if (!container.isDefault('options')) {
Expand All @@ -34,15 +34,43 @@ export class TypeDocReader implements OptionsReader {
return;
}

let data: any = require(file);
if (typeof data !== 'object') {
const seen = new Set<string>();
this.readFile(file, container, logger, seen);
}

/**
* Read the given options file + any extended files.
* @param file
* @param container
* @param logger
*/
private readFile(file: string, container: Options, logger: Logger, seen: Set<string>) {
if (seen.has(file)) {
logger.error(`Tried to load the options file ${file} multiple times.`);
return;
}
seen.add(file);

const data: unknown = require(file);

if (typeof data !== 'object' || !data) {
logger.error(`The file ${file} is not an object.`);
return;
}

if ('extends' in data) {
const extended: string[] = getStringArray(data['extends']);
for (const extendedFile of extended) {
// Extends is relative to the file it appears in.
this.readFile(Path.resolve(Path.dirname(file), extendedFile), container, logger, seen);
}
delete data['extends'];
}

// deprecate: data.src is alias to inputFiles as of 0.16, warn in 0.17, remove in 0.19
if ('src' in data && !('inputFiles' in data)) {
data.inputFiles = Array.isArray(data.src) ? data.src : [data.src];
delete data.src;
data['inputFiles'] = getStringArray(data['src']);
delete data['src'];
}

container.setValues(data).match({
Expand All @@ -63,7 +91,7 @@ export class TypeDocReader implements OptionsReader {
* @param logger
* @return the typedoc.(js|json) file path or undefined
*/
private findTypedocFile(path: string, logger: Logger): string | undefined {
private findTypedocFile(path: string): string | undefined {
path = Path.resolve(path);

return [
Expand All @@ -73,3 +101,7 @@ export class TypeDocReader implements OptionsReader {
].find(path => FS.existsSync(path) && FS.statSync(path).isFile());
}
}

function getStringArray(arg: unknown): string[] {
return Array.isArray(arg) ? arg.map(String) : [String(arg)];
}
3 changes: 3 additions & 0 deletions src/test/utils/options/readers/data/circular-extends.json
@@ -0,0 +1,3 @@
{
"extends": ["./circular-extends.json"]
}
4 changes: 4 additions & 0 deletions src/test/utils/options/readers/data/extends.json
@@ -0,0 +1,4 @@
{
"extends": "./src.json",
"name": "extends"
}
3 changes: 2 additions & 1 deletion src/test/utils/options/readers/data/src.json
@@ -1,3 +1,4 @@
{
"src": ["a"]
"src": ["a"],
"name": "src"
}
6 changes: 6 additions & 0 deletions src/test/utils/options/readers/typedoc.test.ts
Expand Up @@ -26,6 +26,11 @@ describe('Options - TypeDocReader', () => {
equal(options.getValue('inputFiles'), ['a']);
});

test('Supports extends', join(__dirname, 'data/extends.json'), () => {
equal(options.getValue('name'), 'extends');
equal(options.getValue('inputFiles'), ['a']);
});

function testError(name: string, file: string) {
it(name, () => {
options.reset();
Expand All @@ -39,6 +44,7 @@ describe('Options - TypeDocReader', () => {
testError('Errors if the file cannot be found', join(__dirname, 'data/non-existent-file.json'));
testError('Errors if the data is invalid', join(__dirname, 'data/invalid.json'));
testError('Errors if any set option errors', join(__dirname, 'data/unknown.json'));
testError('Errors if extends results in a loop', join(__dirname, 'data/circular-extends.json'));

it('Does not error if the option file cannot be found but was not set.', () => {
const options = new class LyingOptions extends Options {
Expand Down

0 comments on commit 07fb1ce

Please sign in to comment.