Skip to content

Commit 3c5bd98

Browse files
committed
Load configs referenced by "extends"
1 parent cae36e8 commit 3c5bd98

File tree

8 files changed

+162
-11
lines changed

8 files changed

+162
-11
lines changed

tsdoc-config/src/ConfigLoader.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3+
import * as resolve from 'resolve';
34
import { TSDocConfigFile } from './TSDocConfigFile';
45

56
interface IPackageJson {
@@ -70,14 +71,41 @@ export class ConfigLoader {
7071
return undefined;
7172
}
7273

74+
private static _loadAndExtend(configFilePath: string, alreadyVisitedPaths: Set<string>): TSDocConfigFile {
75+
const hashKey: string = fs.realpathSync(configFilePath);
76+
if (alreadyVisitedPaths.has(hashKey)) {
77+
throw new Error('Circular reference encountered for "extends" field of ' + configFilePath);
78+
}
79+
alreadyVisitedPaths.add(hashKey);
80+
81+
const configFile: TSDocConfigFile = TSDocConfigFile.loadFromFile(configFilePath);
82+
83+
const configFileFolder: string = path.dirname(configFile.filePath);
84+
85+
for (const extendsField of configFile.extendsPaths) {
86+
const resolvedExtendsPath: string = resolve.sync(extendsField, { basedir: configFileFolder });
87+
if (!fs.existsSync(resolvedExtendsPath)) {
88+
throw new Error('Unable to resolve "extends" field of ' + configFilePath);
89+
}
90+
91+
const baseConfigFile: TSDocConfigFile = ConfigLoader._loadAndExtend(resolvedExtendsPath, alreadyVisitedPaths);
92+
configFile.addExtendsFile(baseConfigFile);
93+
}
94+
95+
return configFile;
96+
}
97+
7398
public static tryLoadFromPackageFolder(packageFolder: string): TSDocConfigFile | undefined {
7499

75100
const rootConfigFilePath: string | undefined = ConfigLoader._tryGetValidPath(packageFolder);
76101

77102
if (!rootConfigFilePath) {
103+
// There is no tsdoc-config.json for this project
78104
return undefined;
79105
}
80106

81-
return TSDocConfigFile.loadFromFile(rootConfigFilePath);
107+
const alreadyVisitedPaths: Set<string> = new Set<string>();
108+
109+
return ConfigLoader._loadAndExtend(rootConfigFilePath, alreadyVisitedPaths);
82110
}
83111
}

tsdoc-config/src/TSDocConfigFile.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ interface IConfigJson {
3737
* @public
3838
*/
3939
export class TSDocConfigFile {
40+
private readonly _extendsFiles: TSDocConfigFile[] = [];
41+
4042
/**
4143
* The full path of the file.
4244
*/
@@ -48,16 +50,17 @@ export class TSDocConfigFile {
4850
public readonly tsdocSchema: string;
4951

5052
/**
51-
* Module paths for other config files that this file extends from.
53+
* The `extends` field from the `tsdoc-config.json` file. For the parsed file contents,
54+
* use the `extendsFiles` property instead.
5255
*/
53-
public readonly extends: ReadonlyArray<string>;
56+
public readonly extendsPaths: ReadonlyArray<string>;
5457

5558
public readonly tagDefinitions: ReadonlyArray<TSDocTagDefinition>;
5659

5760
private constructor(filePath: string, configJson: IConfigJson) {
5861
this.filePath = filePath;
5962
this.tsdocSchema = configJson.$schema;
60-
this.extends = configJson.extends || [];
63+
this.extendsPaths = configJson.extends || [];
6164
const tagDefinitions: TSDocTagDefinition[] = [];
6265

6366
for (const jsonTagDefinition of configJson.tagDefinitions || []) {
@@ -80,6 +83,13 @@ export class TSDocConfigFile {
8083
this.tagDefinitions = tagDefinitions;
8184
}
8285

86+
/**
87+
* Other config files that this file extends from.
88+
*/
89+
public get extendsFiles(): ReadonlyArray<TSDocConfigFile> {
90+
return this._extendsFiles;
91+
}
92+
8393
/**
8494
* Loads the contents of a single JSON input file.
8595
*
@@ -105,4 +115,11 @@ export class TSDocConfigFile {
105115

106116
return new TSDocConfigFile(fullJsonFilePath, configJson);
107117
}
118+
119+
/**
120+
* Adds an item to `TSDocConfigFile.extendsFiles`.
121+
*/
122+
public addExtendsFile(otherFile: TSDocConfigFile): void {
123+
this._extendsFiles.push(otherFile);
124+
}
108125
}

tsdoc-config/src/__tests__/ConfigLoader.test.ts

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ function getRelativePath(testPath: string): string {
1010
.join('/');
1111
}
1212

13+
expect.addSnapshotSerializer({
14+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
15+
test(value: any) {
16+
return value instanceof TSDocConfigFile;
17+
},
18+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
19+
print(value: any, serialize: (value: any) => string, indent: (str: string) => string): any {
20+
return serialize({
21+
tsdocSchema: value.tsdocSchema,
22+
filePath: getRelativePath(value.filePath),
23+
extendsPaths: value.extendsPaths,
24+
extendsFiles: value.extendsFiles,
25+
tagDefinitions: value.tagDefinitions
26+
});
27+
}
28+
});
29+
1330
test('Load p1', () => {
1431
const configFile: TSDocConfigFile | undefined = ConfigLoader.tryLoadFromPackageFolder(
1532
path.join(__dirname, 'assets/p1')
@@ -42,12 +59,11 @@ test('Load p5', () => {
4259
const configFile: TSDocConfigFile | undefined = ConfigLoader.tryLoadFromPackageFolder(
4360
path.join(__dirname, 'assets/p5')
4461
);
45-
expect(configFile).toMatchInlineSnapshot(
46-
{ filePath: expect.any(String) },
47-
`
62+
expect(configFile).toMatchInlineSnapshot(`
4863
Object {
49-
"extends": Array [],
50-
"filePath": Any<String>,
64+
"extendsFiles": Array [],
65+
"extendsPaths": Array [],
66+
"filePath": "assets/p5/tsdoc-config.json",
5167
"tagDefinitions": Array [
5268
TSDocTagDefinition {
5369
"allowMultiple": true,
@@ -73,6 +89,61 @@ test('Load p5', () => {
7389
],
7490
"tsdocSchema": "https://developer.microsoft.com/json-schemas/tsdoc/v1/tsdoc-config.schema.json",
7591
}
76-
`
92+
`);
93+
});
94+
test('Load p6', () => {
95+
const configFile: TSDocConfigFile | undefined = ConfigLoader.tryLoadFromPackageFolder(
96+
path.join(__dirname, 'assets/p6')
7797
);
98+
expect(configFile).toMatchInlineSnapshot(`
99+
Object {
100+
"extendsFiles": Array [
101+
Object {
102+
"extendsFiles": Array [],
103+
"extendsPaths": Array [],
104+
"filePath": "assets/p6/base1/tsdoc-config.json",
105+
"tagDefinitions": Array [
106+
TSDocTagDefinition {
107+
"allowMultiple": false,
108+
"standardization": "None",
109+
"syntaxKind": 2,
110+
"tagName": "@base1",
111+
"tagNameWithUpperCase": "@BASE1",
112+
},
113+
],
114+
"tsdocSchema": "https://developer.microsoft.com/json-schemas/tsdoc/v1/tsdoc-config.schema.json",
115+
},
116+
Object {
117+
"extendsFiles": Array [],
118+
"extendsPaths": Array [],
119+
"filePath": "assets/p6/base2/tsdoc-config.json",
120+
"tagDefinitions": Array [
121+
TSDocTagDefinition {
122+
"allowMultiple": false,
123+
"standardization": "None",
124+
"syntaxKind": 2,
125+
"tagName": "@base2",
126+
"tagNameWithUpperCase": "@BASE2",
127+
},
128+
],
129+
"tsdocSchema": "https://developer.microsoft.com/json-schemas/tsdoc/v1/tsdoc-config.schema.json",
130+
},
131+
],
132+
"extendsPaths": Array [
133+
"./base1/tsdoc-config.json",
134+
"./base2/tsdoc-config.json",
135+
],
136+
"filePath": "assets/p6/tsdoc-config.json",
137+
"tagDefinitions": Array [
138+
TSDocTagDefinition {
139+
"allowMultiple": false,
140+
"standardization": "None",
141+
"syntaxKind": 2,
142+
"tagName": "@root",
143+
"tagNameWithUpperCase": "@ROOT",
144+
},
145+
],
146+
"tsdocSchema": "https://developer.microsoft.com/json-schemas/tsdoc/v1/tsdoc-config.schema.json",
147+
}
148+
`);
78149
});
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"name": "p4",
2+
"name": "p5",
33
"version": "1.0.0"
44
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v1/tsdoc-config.schema.json",
3+
"tagDefinitions": [
4+
{
5+
"tagName": "@base1",
6+
"syntaxKind": "modifier"
7+
}
8+
]
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v1/tsdoc-config.schema.json",
3+
"tagDefinitions": [
4+
{
5+
"tagName": "@base2",
6+
"syntaxKind": "modifier"
7+
}
8+
]
9+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "p6",
3+
"version": "1.0.0"
4+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v1/tsdoc-config.schema.json",
3+
"extends": [
4+
"./base1/tsdoc-config.json",
5+
"./base2/tsdoc-config.json"
6+
],
7+
"tagDefinitions": [
8+
{
9+
"tagName": "@root",
10+
"syntaxKind": "modifier"
11+
}
12+
]
13+
}

0 commit comments

Comments
 (0)