-
Notifications
You must be signed in to change notification settings - Fork 45
Expand file tree
/
Copy pathmarkdown.mjs
More file actions
104 lines (83 loc) · 3.35 KB
/
markdown.mjs
File metadata and controls
104 lines (83 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
'use strict';
import { coerce } from 'semver';
import { loadFromURL } from '../utils/parser.mjs';
import createQueries from '../utils/queries/index.mjs';
import { getRemark } from '../utils/remark.mjs';
// A ReGeX for retrieving Node.js version headers from the CHANGELOG.md
const NODE_VERSIONS_REGEX = /\* \[Node\.js ([0-9.]+)\]\S+ (.*)\r?\n/g;
// A ReGeX for retrieving the list items in the index document
const LIST_ITEM_REGEX = /\* \[(.*?)\]\((.*?)\.md\)/g;
// A ReGeX for checking if a Node.js version is an LTS release
const NODE_LTS_VERSION_REGEX = /Long Term Support/i;
/**
* Creates an API doc parser for a given Markdown API doc file
*
* @param {import('../linter/types').Linter} [linter]
*/
const createParser = linter => {
// Creates an instance of the Remark processor with GFM support
const remarkProcessor = getRemark();
const { updateStabilityPrefixToLink } = createQueries();
/**
* Parses a given API doc file into a AST tree
*
* @param {import('vfile').VFile | Promise<import('vfile').VFile>} apiDoc
* @returns {Promise<ParserOutput<import('mdast').Root>>}
*/
const parseApiDoc = async apiDoc => {
// We allow the API doc VFile to be a Promise of a VFile also,
// hence we want to ensure that it first resolves before we pass it to the parser
const resolvedApiDoc = await Promise.resolve(apiDoc);
// Normalizes all the Stability Index prefixes with Markdown links
updateStabilityPrefixToLink(resolvedApiDoc);
// Parses the API doc into an AST tree using `unified` and `remark`
const apiDocTree = remarkProcessor.parse(resolvedApiDoc);
linter?.lint(resolvedApiDoc, apiDocTree);
return {
file: {
stem: resolvedApiDoc.stem,
basename: resolvedApiDoc.basename,
},
tree: apiDocTree,
};
};
/**
* This method allows to parse multiple API doc files at once
* and it simply wraps parseApiDoc with the given API docs
*
* @param {Array<import('vfile').VFile | Promise<import('vfile').VFile>>} apiDocs List of API doc files to be parsed
* @returns {Promise<Array<ParserOutput<import('mdast').Root>>>}
*/
const parseApiDocs = async apiDocs => {
// We do a Promise.all, to ensure that each API doc is resolved asynchronously
// but all need to be resolved first before we return the result to the caller
return Promise.all(apiDocs.map(parseApiDoc));
};
return { parseApiDocs, parseApiDoc };
};
/**
* Retrieves all Node.js major versions from the provided CHANGELOG.md file
* and returns an array of objects containing the version and LTS status.
* @param {string|URL} path Path to changelog
* @returns {Promise<Array<ApiDocReleaseEntry>>}
*/
export const parseChangelog = async path => {
const changelog = await loadFromURL(path);
const nodeMajors = Array.from(changelog.matchAll(NODE_VERSIONS_REGEX));
return nodeMajors.map(match => ({
version: coerce(match[1]),
isLts: NODE_LTS_VERSION_REGEX.test(match[2]),
}));
};
/**
* Retrieves all the document titles for sidebar generation.
*
* @param {string|URL} path Path to changelog
* @returns {Promise<Array<{ section: string, api: string }>>}
*/
export const parseIndex = async path => {
const index = await loadFromURL(path);
const items = Array.from(index.matchAll(LIST_ITEM_REGEX));
return items.map(([, section, api]) => ({ section, api }));
};
export default createParser;