Skip to content

Commit 1ca9473

Browse files
committed
review
Signed-off-by: flakey5 <[email protected]>
1 parent 84583d9 commit 1ca9473

File tree

11 files changed

+120
-97
lines changed

11 files changed

+120
-97
lines changed

bin/cli.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import { coerce } from 'semver';
99
import { DOC_NODE_CHANGELOG_URL, DOC_NODE_VERSION } from '../src/constants.mjs';
1010
import createGenerator from '../src/generators.mjs';
1111
import generators from '../src/generators/index.mjs';
12-
import { createMarkdownLoader } from '../src/loader.mjs';
13-
import { createMarkdownParser } from '../src/parser.mjs';
12+
import createMarkdownLoader from '../src/loaders/markdown.mjs';
13+
import createMarkdownParser from '../src/parsers/markdown.mjs';
1414
import createNodeReleases from '../src/releases.mjs';
1515

1616
const availableGenerators = Object.keys(generators);

src/generators.mjs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
'use strict';
22

3-
import availableGenerators from './generators/index.mjs';
3+
import publicGenerators from './generators/index.mjs';
4+
import astJs from './generators/ast-js/index.mjs';
5+
6+
const availableGenerators = {
7+
...publicGenerators,
8+
// This one is a little special since we don't want it to run unless we need
9+
// it and we also don't want it to be publicly accessible through the CLI.
10+
'ast-js': astJs,
11+
};
412

513
/**
614
* @typedef {{ ast: import('./generators/types.d.ts').GeneratorMetadata<ApiDocMetadataEntry, ApiDocMetadataEntry>}} AstGenerator The AST "generator" is a facade for the AST tree and it isn't really a generator
@@ -23,7 +31,7 @@ import availableGenerators from './generators/index.mjs';
2331
* @param {ApiDocMetadataEntry} markdownInput The parsed API doc metadata entries
2432
* @param {Array<import('acorn').Program>} parsedJsFiles
2533
*/
26-
const createGenerator = (markdownInput, jsInput) => {
34+
const createGenerator = markdownInput => {
2735
/**
2836
* We store all the registered generators to be processed
2937
* within a Record, so we can access their results at any time whenever needed
@@ -33,7 +41,6 @@ const createGenerator = (markdownInput, jsInput) => {
3341
*/
3442
const cachedGenerators = {
3543
ast: Promise.resolve(markdownInput),
36-
'ast-js': Promise.resolve(jsInput),
3744
};
3845

3946
/**

src/generators/api-links/utils/checkIndirectReferences.mjs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { visit } from 'estree-util-visit';
22

33
/**
4-
*
5-
* @param program
4+
* @param {import('acorn').Program} program
65
* @param {import('../types.d.ts').ProgramExports} exports
76
* @param {Record<string, number>} nameToLineNumberMap
87
*/

src/generators/ast-js/index.mjs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { createJsLoader } from '../../loader.mjs';
2-
import { createJsParser } from '../../parser.mjs';
1+
import createJsLoader from '../../loaders/javascript.mjs';
2+
import createJsParser from '../../parsers/javascript.mjs';
33

44
/**
55
* This generator parses Javascript sources passed into the generator's input
@@ -29,12 +29,8 @@ export default {
2929
async generate(_, options) {
3030
const { loadFiles } = createJsLoader();
3131

32-
if (!options.input) {
33-
return [];
34-
}
35-
3632
// Load all of the Javascript sources into memory
37-
const sourceFiles = loadFiles(options.input);
33+
const sourceFiles = loadFiles(options.input ?? []);
3834

3935
const { parseJsSources } = createJsParser();
4036

src/generators/index.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import legacyJson from './legacy-json/index.mjs';
88
import legacyJsonAll from './legacy-json-all/index.mjs';
99
import addonVerify from './addon-verify/index.mjs';
1010
import apiLinks from './api-links/index.mjs';
11-
import astJs from './ast-js/index.mjs';
1211

1312
export default {
1413
'json-simple': jsonSimple,
@@ -19,5 +18,4 @@ export default {
1918
'legacy-json-all': legacyJsonAll,
2019
'addon-verify': addonVerify,
2120
'api-links': apiLinks,
22-
'ast-js': astJs,
2321
};

src/generators/types.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ declare global {
5959
*
6060
* The 'ast' generator is the top-level parser, and if 'ast' is passed to `dependsOn`, then the generator
6161
* will be marked as a top-level generator.
62+
*
63+
* The `ast-js` generator is the top-level parser for JavaScript files. It
64+
* passes the ASTs for any JavaScript files given in the input. Like `ast`,
65+
* any generator depending on it is marked as a top-level generator.
6266
*/
6367
dependsOn: keyof AvailableGenerators | 'ast' | 'ast-js';
6468

src/index.mjs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
export * as constants from './constants.mjs';
22
export { default as generators } from './generators/index.mjs';
33
export { default as createGenerator } from './generators.mjs';
4-
export * from './loader.mjs';
4+
export * from './loaders/markdown.mjs';
5+
export * from './loaders/javascript.mjs';
56
export { default as createMetadata } from './metadata.mjs';
6-
export * from './parser.mjs';
7+
export * from './parsers/markdown.mjs';
8+
export * from './parsers/javascript.mjs';
79
export { default as createQueries } from './queries.mjs';
810
export { default as createNodeReleases } from './releases.mjs';

src/loaders/javascript.mjs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
import { readFile } from 'node:fs/promises';
4+
import { extname } from 'node:path';
5+
6+
import { globSync } from 'glob';
7+
import { VFile } from 'vfile';
8+
9+
/**
10+
* This creates a "loader" for loading Javascript source files into VFiles.
11+
*/
12+
const createLoader = () => {
13+
/**
14+
* Loads the JavaScript source files and transforms them into VFiles
15+
*
16+
* @param {string | Array<string>} searchPath
17+
*/
18+
const loadFiles = searchPath => {
19+
const resolvedFiles = globSync(searchPath).filter(
20+
filePath => extname(filePath) === '.js'
21+
);
22+
23+
return resolvedFiles.map(async filePath => {
24+
const fileContents = await readFile(filePath, 'utf-8');
25+
26+
return new VFile({ path: filePath, value: fileContents });
27+
});
28+
};
29+
30+
return { loadFiles };
31+
};
32+
33+
export default createLoader;

src/loader.mjs renamed to src/loaders/markdown.mjs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { VFile } from 'vfile';
1111
* could be used for different things, but here we want to use it to load
1212
* Markdown files and transform them into VFiles
1313
*/
14-
export const createMarkdownLoader = () => {
14+
const createLoader = () => {
1515
/**
1616
* Loads API Doc files and transforms it into VFiles
1717
*
@@ -36,26 +36,4 @@ export const createMarkdownLoader = () => {
3636
return { loadFiles };
3737
};
3838

39-
/**
40-
* This creates a "loader" for loading Javascript source files into VFiles.
41-
*/
42-
export const createJsLoader = () => {
43-
/**
44-
* Loads the JavaScript source files and transforms them into VFiles
45-
*
46-
* @param {string | Array<string>} searchPath
47-
*/
48-
const loadFiles = searchPath => {
49-
const resolvedFiles = globSync(searchPath).filter(
50-
filePath => extname(filePath) === '.js'
51-
);
52-
53-
return resolvedFiles.map(async filePath => {
54-
const fileContents = await readFile(filePath, 'utf-8');
55-
56-
return new VFile({ path: filePath, value: fileContents });
57-
});
58-
};
59-
60-
return { loadFiles };
61-
};
39+
export default createLoader;

src/parsers/javascript.mjs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use strict';
2+
3+
import * as acorn from 'acorn';
4+
5+
/**
6+
* Creates a Javascript source parser for a given source file
7+
*/
8+
const createParser = () => {
9+
/**
10+
* Parses a given JavaScript file into an ESTree AST representation of it
11+
*
12+
* @param {import('vfile').VFile | Promise<import('vfile').VFile>} sourceFile
13+
* @returns {Promise<JsProgram>}
14+
*/
15+
const parseJsSource = async sourceFile => {
16+
// We allow the API doc VFile to be a Promise of a VFile also,
17+
// hence we want to ensure that it first resolves before we pass it to the parser
18+
const resolvedSourceFile = await Promise.resolve(sourceFile);
19+
20+
if (typeof resolvedSourceFile.value !== 'string') {
21+
throw new TypeError(
22+
`expected resolvedSourceFile.value to be string but got ${typeof resolvedSourceFile.value}`
23+
);
24+
}
25+
26+
const res = acorn.parse(resolvedSourceFile.value, {
27+
allowReturnOutsideFunction: true,
28+
ecmaVersion: 'latest',
29+
locations: true,
30+
});
31+
32+
return {
33+
...res,
34+
path: resolvedSourceFile.path,
35+
};
36+
};
37+
38+
/**
39+
* Parses multiple JavaScript files into ESTree ASTs by wrapping parseJsSource
40+
*
41+
* @param {Array<import('vfile').VFile | Promise<import('vfile').VFile>>} apiDocs List of API doc files to be parsed
42+
* @returns {Promise<Array<JsProgram>>}
43+
*/
44+
const parseJsSources = async apiDocs => {
45+
// We do a Promise.all, to ensure that each API doc is resolved asynchronously
46+
// but all need to be resolved first before we return the result to the caller
47+
const resolvedApiDocEntries = await Promise.all(apiDocs.map(parseJsSource));
48+
49+
return resolvedApiDocEntries;
50+
};
51+
52+
return { parseJsSource, parseJsSources };
53+
};
54+
55+
export default createParser;

0 commit comments

Comments
 (0)