Skip to content

Commit b9cc8e4

Browse files
feat: extract all Electron specififc logic to plugins
* Website URL * Repo URL * Filename (now api.json) * Process information BREAKING CHANGE
1 parent d2e86df commit b9cc8e4

12 files changed

+337
-157
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ yarn global add electron-docs-parser
99
cd ~/projects/path/to/electron/repo
1010
electron-docs-parser --dir ./
1111

12-
# You now have ./electron-api.json with the entire Electron API
12+
# You now have ./api.json with the entire Electron API
1313
```
1414

1515
## How it Works

src/DocsParser.ts

Lines changed: 99 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,43 @@ import {
2323
headingsAndContent,
2424
findConstructorHeader,
2525
consumeTypedKeysList,
26-
findProcess,
2726
} from './markdown-helpers';
28-
import { WEBSITE_BASE_DOCS_URL, REPO_BASE_DOCS_URL } from './constants';
2927
import { extendError } from './helpers';
3028
import {
3129
parseMethodBlocks,
3230
_headingToMethodBlock,
3331
parsePropertyBlocks,
3432
parseEventBlocks,
3533
} from './block-parsers';
34+
import { DocsParserPlugin } from './DocsParserPlugin';
3635

3736
export class DocsParser {
3837
constructor(
39-
private baseElectronDir: string,
38+
private baseDir: string,
4039
private moduleVersion: string,
4140
private apiFiles: string[],
4241
private structureFiles: string[],
42+
private plugins: DocsParserPlugin<any>[] = [],
4343
) {}
4444

45+
private getRelatveDocsPath = (filePath: string) =>
46+
path.relative(this.baseDir, filePath).split('.')[0];
47+
48+
private extendAPI = <
49+
T extends
50+
| ModuleDocumentationContainer
51+
| ClassDocumentationContainer
52+
| ElementDocumentationContainer
53+
>(
54+
api: T,
55+
tokens: Token[],
56+
): T => {
57+
for (const plugin of this.plugins) {
58+
if (plugin.extendAPI) Object.assign(api, plugin.extendAPI(api, tokens) || {});
59+
}
60+
return api;
61+
};
62+
4563
private async parseBaseContainers(
4664
filePath: string,
4765
fileContents: string,
@@ -53,7 +71,7 @@ export class DocsParser {
5371
isClass: boolean;
5472
}[]
5573
> {
56-
const relativeDocsPath = path.relative(this.baseElectronDir, filePath).split('.')[0];
74+
const relativeDocsPath = this.getRelatveDocsPath(filePath);
5775
const isStructure = relativeDocsPath.includes('structures');
5876
const headings = headingsAndContent(tokens);
5977
expect(headings).to.not.have.lengthOf(
@@ -105,11 +123,19 @@ export class DocsParser {
105123
extends: extendsMatch ? extendsMatch[1] : undefined,
106124
description,
107125
slug: path.basename(filePath, '.md'),
108-
websiteUrl: `${WEBSITE_BASE_DOCS_URL}/${relativeDocsPath}`,
109-
repoUrl: `${REPO_BASE_DOCS_URL(this.moduleVersion)}/${relativeDocsPath}.md`,
110126
version: this.moduleVersion,
111127
},
112128
});
129+
const added = parsedContainers[parsedContainers.length - 1];
130+
for (const plugin of this.plugins)
131+
Object.assign(
132+
added.container,
133+
plugin.extendContainer
134+
? plugin.extendContainer(added.container, {
135+
relativeDocsPath,
136+
})
137+
: {},
138+
);
113139
}
114140
}
115141

@@ -147,7 +173,6 @@ export class DocsParser {
147173
'HTMLElement documentation should not be considered a class',
148174
);
149175
}
150-
const electronProcess = findProcess(tokens);
151176
if (isClass) {
152177
// Instance name will be taken either from an example in a method declaration or the camel
153178
// case version of the class name
@@ -161,60 +186,78 @@ export class DocsParser {
161186
const constructorMethod = _headingToMethodBlock(findConstructorHeader(tokens));
162187

163188
// This is a class
164-
parsed.push({
165-
...container,
166-
type: 'Class',
167-
process: electronProcess,
168-
constructorMethod: constructorMethod
169-
? {
170-
signature: constructorMethod.signature,
171-
parameters: constructorMethod.parameters,
172-
}
173-
: null,
174-
// ### Static Methods
175-
staticMethods: parseMethodBlocks(findContentInsideHeader(tokens, 'Static Methods', 3)),
176-
// ### Static Properties
177-
staticProperties: parsePropertyBlocks(
178-
findContentInsideHeader(tokens, 'Static Properties', 3),
179-
),
180-
// ### Instance Methods
181-
instanceMethods: parseMethodBlocks(
182-
findContentInsideHeader(tokens, 'Instance Methods', 3),
189+
parsed.push(
190+
this.extendAPI(
191+
{
192+
...container,
193+
type: 'Class',
194+
constructorMethod: constructorMethod
195+
? {
196+
signature: constructorMethod.signature,
197+
parameters: constructorMethod.parameters,
198+
}
199+
: null,
200+
// ### Static Methods
201+
staticMethods: parseMethodBlocks(
202+
findContentInsideHeader(tokens, 'Static Methods', 3),
203+
),
204+
// ### Static Properties
205+
staticProperties: parsePropertyBlocks(
206+
findContentInsideHeader(tokens, 'Static Properties', 3),
207+
),
208+
// ### Instance Methods
209+
instanceMethods: parseMethodBlocks(
210+
findContentInsideHeader(tokens, 'Instance Methods', 3),
211+
),
212+
// ### Instance Properties
213+
instanceProperties: parsePropertyBlocks(
214+
findContentInsideHeader(tokens, 'Instance Properties', 3),
215+
),
216+
// ### Instance Events
217+
instanceEvents: parseEventBlocks(
218+
findContentInsideHeader(tokens, 'Instance Events', 3),
219+
),
220+
instanceName,
221+
},
222+
tokens,
183223
),
184-
// ### Instance Properties
185-
instanceProperties: parsePropertyBlocks(
186-
findContentInsideHeader(tokens, 'Instance Properties', 3),
187-
),
188-
// ### Instance Events
189-
instanceEvents: parseEventBlocks(findContentInsideHeader(tokens, 'Instance Events', 3)),
190-
instanceName,
191-
});
224+
);
192225
} else {
193226
// This is a module
194227
if (isElement) {
195-
parsed.push({
196-
...container,
197-
type: 'Element',
198-
process: electronProcess,
199-
// ## Methods
200-
methods: parseMethodBlocks(findContentInsideHeader(tokens, 'Methods', 2)),
201-
// ## Properties
202-
properties: parsePropertyBlocks(findContentInsideHeader(tokens, 'Tag Attributes', 2)),
203-
// ## Events
204-
events: parseEventBlocks(findContentInsideHeader(tokens, 'DOM Events', 2)),
205-
});
228+
parsed.push(
229+
this.extendAPI(
230+
{
231+
...container,
232+
type: 'Element',
233+
// ## Methods
234+
methods: parseMethodBlocks(findContentInsideHeader(tokens, 'Methods', 2)),
235+
// ## Properties
236+
properties: parsePropertyBlocks(
237+
findContentInsideHeader(tokens, 'Tag Attributes', 2),
238+
),
239+
// ## Events
240+
events: parseEventBlocks(findContentInsideHeader(tokens, 'DOM Events', 2)),
241+
},
242+
tokens,
243+
),
244+
);
206245
} else {
207-
parsed.push({
208-
...container,
209-
type: 'Module',
210-
process: electronProcess,
211-
// ## Methods
212-
methods: parseMethodBlocks(findContentInsideHeader(tokens, 'Methods', 2)),
213-
// ## Properties
214-
properties: parsePropertyBlocks(findContentInsideHeader(tokens, 'Properties', 2)),
215-
// ## Events
216-
events: parseEventBlocks(findContentInsideHeader(tokens, 'Events', 2)),
217-
});
246+
parsed.push(
247+
this.extendAPI(
248+
{
249+
...container,
250+
type: 'Module',
251+
// ## Methods
252+
methods: parseMethodBlocks(findContentInsideHeader(tokens, 'Methods', 2)),
253+
// ## Properties
254+
properties: parsePropertyBlocks(findContentInsideHeader(tokens, 'Properties', 2)),
255+
// ## Events
256+
events: parseEventBlocks(findContentInsideHeader(tokens, 'Events', 2)),
257+
},
258+
tokens,
259+
),
260+
);
218261
}
219262
}
220263
}

src/DocsParserPlugin.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {
2+
StructureDocumentationContainer,
3+
BaseDocumentationContainer,
4+
ClassDocumentationContainer,
5+
ElementDocumentationContainer,
6+
ModuleDocumentationContainer,
7+
} from './ParsedDocumentation';
8+
import Token = require('markdown-it/lib/token');
9+
10+
export interface ExtendOptions {
11+
relativeDocsPath: string;
12+
}
13+
14+
export abstract class DocsParserPlugin<Options> {
15+
constructor(protected readonly options: Options) {}
16+
17+
abstract extendContainer?(
18+
container: BaseDocumentationContainer,
19+
opts: ExtendOptions,
20+
): object | void;
21+
22+
abstract extendAPI?(
23+
api: ClassDocumentationContainer | ElementDocumentationContainer | ModuleDocumentationContainer,
24+
tokens: Token[],
25+
): object | void;
26+
}

src/ParsedDocumentation.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,9 @@ export declare type BaseDocumentationContainer = {
7272
description: string;
7373
version: string;
7474
slug: string;
75-
websiteUrl: string;
76-
repoUrl: string;
77-
};
78-
export declare type ProcessBlock = {
79-
main: boolean;
80-
renderer: boolean;
8175
};
8276
export declare type ModuleDocumentationContainer = {
8377
type: 'Module';
84-
process: ProcessBlock;
8578
methods: MethodDocumentationBlock[];
8679
events: EventDocumentationBlock[];
8780
properties: PropertyDocumentationBlock[];
@@ -107,7 +100,6 @@ export declare type StructureDocumentationContainer = {
107100
} & BaseDocumentationContainer;
108101
export declare type ClassDocumentationContainer = {
109102
type: 'Class';
110-
process: ProcessBlock;
111103
constructorMethod: Pick<MethodDocumentationBlock, 'signature' | 'parameters'> | null;
112104
instanceName: string;
113105
staticMethods: MethodDocumentationBlock[];
@@ -121,7 +113,6 @@ export declare type ClassDocumentationContainer = {
121113
} & BaseDocumentationContainer;
122114
export declare type ElementDocumentationContainer = {
123115
type: 'Element';
124-
process: ProcessBlock;
125116
constructorMethod?: undefined;
126117
methods: MethodDocumentationBlock[];
127118
events: EventDocumentationBlock[];

src/__tests__/markdown-helpers.spec.ts

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
getTopLevelGenericType,
1212
findFirstHeading,
1313
consumeTypedKeysList,
14-
findProcess,
1514
} from '../markdown-helpers';
1615
import { DocumentationTag } from '../ParsedDocumentation';
1716

@@ -388,50 +387,4 @@ foo`),
388387
);
389388
});
390389
});
391-
392-
describe('findProcess()', () => {
393-
it('should be available in main processe only', () => {
394-
var proc = findProcess(getTokens('Process: [Main](../glossary.md#main-process)'));
395-
expect(proc.main).toEqual(true);
396-
expect(proc.renderer).toEqual(false);
397-
});
398-
399-
it('should be available in renderer processe only', () => {
400-
var proc = findProcess(getTokens('Process: [Renderer](../glossary.md#renderer-process)'));
401-
expect(proc.main).toEqual(false);
402-
expect(proc.renderer).toEqual(true);
403-
});
404-
405-
it('should be available in both processes', () => {
406-
var proc = findProcess(
407-
getTokens(
408-
'Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)',
409-
),
410-
);
411-
expect(proc.main).toEqual(true);
412-
expect(proc.renderer).toEqual(true);
413-
});
414-
415-
it('should be available in both processes', () => {
416-
var proc = findProcess(
417-
getTokens(
418-
'Process: [Renderer](../glossary.md#renderer-process), [Main](../glossary.md#main-process)',
419-
),
420-
);
421-
expect(proc.main).toEqual(true);
422-
expect(proc.renderer).toEqual(true);
423-
});
424-
425-
it('should be available in both processes', () => {
426-
var proc = findProcess(getTokens(''));
427-
expect(proc.main).toEqual(true);
428-
expect(proc.renderer).toEqual(true);
429-
});
430-
431-
it('should be available in both processes', () => {
432-
var proc = findProcess([]);
433-
expect(proc.main).toEqual(true);
434-
expect(proc.renderer).toEqual(true);
435-
});
436-
});
437390
});

0 commit comments

Comments
 (0)