Skip to content

Commit 23d5f17

Browse files
committed
more code review
1 parent be82e33 commit 23d5f17

File tree

8 files changed

+158
-98
lines changed

8 files changed

+158
-98
lines changed

src/generators/jsx/constants.mjs

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
1-
// Maps Node.js API stability indices (0-3) to UI component stability levels.
1+
/**
2+
* UI classes for Node.js API stability levels
3+
*
4+
* @see https://nodejs.org/api/documentation.html#stability-index
5+
*/
26
export const STABILITY_LEVELS = [
37
'danger', // (0) Deprecated
48
'warning', // (1) Experimental
59
'success', // (2) Stable
610
'info', // (3) Legacy
711
];
812

9-
// Maps HTML tags to corresponding component names in @node-core/ui-components.
13+
/**
14+
* HTML tag to UI component mappings
15+
*/
1016
export const TAG_TRANSFORMS = {
1117
pre: 'CodeBox',
1218
blockquote: 'Blockquote',
1319
};
1420

15-
// Maps API heading types to their CircularIcon props.
16-
export const ICON_SYMBOL_MAP = {
21+
/**
22+
* @see transformer.mjs's TODO comment
23+
*/
24+
export const TYPE_TRANSFORMS = {
25+
raw: 'text',
26+
};
27+
28+
/**
29+
* API type icon configurations
30+
*/
31+
export const API_ICONS = {
1732
event: { symbol: 'E', color: 'red' },
1833
method: { symbol: 'M', color: 'red' },
1934
property: { symbol: 'P', color: 'red' },
@@ -23,29 +38,78 @@ export const ICON_SYMBOL_MAP = {
2338
ctor: { symbol: 'C', color: 'red' },
2439
};
2540

26-
// Maps API lifecycle change type identifiers to their human-readable labels.
27-
export const CHANGE_TYPES = {
41+
/**
42+
* API lifecycle change labels
43+
*/
44+
export const LIFECYCLE_LABELS = {
2845
added_in: 'Added in',
2946
deprecated_in: 'Deprecated in',
3047
removed_in: 'Removed in',
3148
introduced_in: 'Introduced in',
3249
};
3350

34-
export const AST_NODES = {
51+
// TODO(@avivkeller): These should be inherited from @node-core/website-i18n
52+
export const INTERNATIONALIZABLE = {
53+
sourceCode: 'Source Code: ',
54+
};
55+
56+
/**
57+
* Abstract Syntax Tree node type constants
58+
*/
59+
export const AST_NODE_TYPES = {
3560
MDX: {
36-
// https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxtextelement
61+
/**
62+
* Text-level JSX element
63+
*
64+
* @see https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxtextelement
65+
*/
3766
JSX_INLINE_ELEMENT: 'mdxJsxTextElement',
38-
// https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxflowelement
67+
68+
/**
69+
* Block-level JSX element
70+
*
71+
* @see https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxflowelement
72+
*/
3973
JSX_BLOCK_ELEMENT: 'mdxJsxFlowElement',
40-
// https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxattribute
74+
75+
/**
76+
* JSX attribute
77+
*
78+
* @see https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxattribute
79+
*/
4180
JSX_ATTRIBUTE: 'mdxJsxAttribute',
42-
// https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxattributevalueexpression
81+
82+
/**
83+
* JSX expression attribute
84+
*
85+
* @see https://github.com/syntax-tree/mdast-util-mdx-jsx#mdxjsxattributevalueexpression
86+
*/
4387
JSX_ATTRIBUTE_EXPRESSION: 'mdxJsxAttributeValueExpression',
4488
},
4589
ESTREE: {
46-
// https://github.com/estree/estree/blob/master/es5.md#programs
90+
/**
91+
* AST Program node
92+
*
93+
* @see https://github.com/estree/estree/blob/master/es5.md#programs
94+
*/
4795
PROGRAM: 'Program',
48-
// https://github.com/estree/estree/blob/master/es5.md#expressionstatement
96+
97+
/**
98+
* Expression statement
99+
*
100+
* @see https://github.com/estree/estree/blob/master/es5.md#expressionstatement
101+
*/
49102
EXPRESSION_STATEMENT: 'ExpressionStatement',
50103
},
104+
// TODO(@avivkeller): These should be inherited from the elements themselves
105+
JSX: {
106+
ALERT_BOX: 'AlertBox',
107+
CHANGE_HISTORY: 'ChangeHistory',
108+
CIRCULAR_ICON: 'CircularIcon',
109+
NAV_BAR: 'NavBar',
110+
ARTICLE: 'Article',
111+
SIDE_BAR: 'SideBar',
112+
META_BAR: 'MetaBar',
113+
FOOTER: 'Footer',
114+
},
51115
};

src/generators/jsx/index.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default {
2424
*
2525
* @param {Input} entries
2626
* @param {Partial<GeneratorOptions>} options
27-
* @returns {Promise<string[]>} Array of generated content
27+
* @returns {Promise<Array<string>>} Array of generated content
2828
*/
2929
async generate(entries, { releases, version }) {
3030
const remarkRecma = getRemarkRecma();

src/generators/jsx/utils/ast.mjs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@
22

33
import { u as createTree } from 'unist-builder';
44
import { valueToEstree } from 'estree-util-value-to-estree';
5-
import { AST_NODES } from '../constants.mjs';
5+
import { AST_NODE_TYPES } from '../constants.mjs';
6+
7+
/**
8+
* @typedef {Object} JSXOptions
9+
* @property {boolean} [inline] - Whether the element is inline
10+
* @property {(string | Array<import('unist').Node>)} [children] - Child content or nodes
11+
*/
612

713
/**
814
* Creates an MDX JSX element with support for complex attribute values.
915
*
1016
* @param {string} name - The name of the JSX element
11-
* @param {{
12-
* inline?: boolean,
13-
* children?: string | import('unist').Node[],
14-
* [key: string]: any
15-
* }} [options={}] - Options including type, children, and JSX attributes
17+
* @param {JSXOptions & Record<string, any>} [options={}] - Options including type, children, and JSX attributes
1618
* @returns {import('unist').Node} The created MDX JSX element node
1719
*/
1820
export const createJSXElement = (
@@ -26,8 +28,8 @@ export const createJSXElement = (
2628
: children;
2729

2830
const elementType = inline
29-
? AST_NODES.MDX.JSX_INLINE_ELEMENT
30-
: AST_NODES.MDX.JSX_BLOCK_ELEMENT;
31+
? AST_NODE_TYPES.MDX.JSX_INLINE_ELEMENT
32+
: AST_NODE_TYPES.MDX.JSX_BLOCK_ELEMENT;
3133

3234
const attrs = Object.entries(attributes).map(([key, value]) =>
3335
createAttributeNode(key, value)
@@ -50,15 +52,15 @@ export const createJSXElement = (
5052
function createAttributeNode(name, value) {
5153
// Use expression for objects and arrays
5254
if (value !== null && typeof value === 'object') {
53-
return createTree(AST_NODES.MDX.JSX_ATTRIBUTE, {
55+
return createTree(AST_NODE_TYPES.MDX.JSX_ATTRIBUTE, {
5456
name,
55-
value: createTree(AST_NODES.MDX.JSX_ATTRIBUTE_EXPRESSION, {
57+
value: createTree(AST_NODE_TYPES.MDX.JSX_ATTRIBUTE_EXPRESSION, {
5658
data: {
5759
estree: {
58-
type: AST_NODES.ESTREE.PROGRAM,
60+
type: AST_NODE_TYPES.ESTREE.PROGRAM,
5961
body: [
6062
{
61-
type: AST_NODES.ESTREE.EXPRESSION_STATEMENT,
63+
type: AST_NODE_TYPES.ESTREE.EXPRESSION_STATEMENT,
6264
expression: valueToEstree(value),
6365
},
6466
],
@@ -70,8 +72,8 @@ function createAttributeNode(name, value) {
7072

7173
// For primitives, use simple string conversion.
7274
// If undefined, pass nothing.
73-
return createTree(AST_NODES.MDX.JSX_ATTRIBUTE, {
75+
return createTree(AST_NODE_TYPES.MDX.JSX_ATTRIBUTE, {
7476
name,
75-
value: value === undefined ? value : String(value),
77+
value: value == null ? value : String(value),
7678
});
7779
}

src/generators/jsx/utils/buildBarProps.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import readingTime from 'reading-time';
22
import { visit } from 'unist-util-visit';
3+
import { DOC_API_BLOB_EDIT_BASE_URL } from '../../../constants.mjs';
34

45
/**
56
* Builds sidebar navigation for API documentation pages
@@ -47,6 +48,6 @@ export const buildMetaBarProps = (head, entries) => {
4748
addedIn: head.introduced_in || head.added_in || '',
4849
readingTime: readingTime(textContent).text,
4950
viewAs: [['JSON', `${head.api}.json`]],
50-
editThisPage: `${head.edit_link}`,
51+
editThisPage: `${DOC_API_BLOB_EDIT_BASE_URL}${head.api}.md`,
5152
};
5253
};

src/generators/jsx/utils/buildContent.mjs

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,24 @@ import { SKIP, visit } from 'unist-util-visit';
77
import createQueries from '../../../utils/queries/index.mjs';
88
import { createJSXElement } from './ast.mjs';
99
import {
10-
ICON_SYMBOL_MAP,
10+
API_ICONS,
11+
AST_NODE_TYPES,
1112
STABILITY_LEVELS,
12-
CHANGE_TYPES,
13+
LIFECYCLE_LABELS,
14+
INTERNATIONALIZABLE,
1315
} from '../constants.mjs';
1416
import { DOC_NODE_BLOB_BASE_URL } from '../../../constants.mjs';
1517
import { enforceArray, sortChanges } from '../../../utils/generators.mjs';
1618
import { buildMetaBarProps } from './buildBarProps.mjs';
1719

18-
/**
19-
* Transforms a stability node into an AlertBox JSX element
20-
*
21-
* @param {import('mdast').Blockquote} node - The stability node to transform
22-
* @param {number} index - The index of the node in its parent's children array
23-
* @param {import('unist').Parent} parent - The parent node containing the stability node
24-
* @returns {[typeof SKIP]} Visitor instruction to skip the node
25-
*/
26-
const transformStabilityNode = ({ data }, index, parent) => {
27-
parent.children[index] = createJSXElement('AlertBox', {
28-
children: data.description,
29-
level: STABILITY_LEVELS[data.index],
30-
title: data.index,
31-
});
32-
33-
return [SKIP];
34-
};
35-
3620
/**
3721
* Creates a history of changes for an API element
38-
*
3922
* @param {ApiDocMetadataEntry} entry - The metadata entry containing change information
4023
* @returns {import('unist').Node|null} JSX element representing change history or null if no changes
4124
*/
4225
const createChangeElement = entry => {
43-
// Collect changes from version fields (added, deprecated, etc.)
44-
const changeEntries = Object.entries(CHANGE_TYPES)
26+
// Collect lifecycle changes (added, deprecated, etc.)
27+
const changeEntries = Object.entries(LIFECYCLE_LABELS)
4528
// Do we have this field?
4629
.filter(([field]) => entry[field])
4730
// Get the versions as an array
@@ -59,6 +42,7 @@ const createChangeElement = entry => {
5942
label: change.description,
6043
url: change['pr-url'],
6144
}));
45+
6246
changeEntries.push(...explicitChanges);
6347
}
6448

@@ -67,14 +51,13 @@ const createChangeElement = entry => {
6751
}
6852

6953
// Sort by version, newest first and create the JSX element
70-
return createJSXElement('ChangeHistory', {
54+
return createJSXElement(AST_NODE_TYPES.JSX.CHANGE_HISTORY, {
7155
changes: sortChanges(changeEntries, 'versions'),
7256
});
7357
};
7458

7559
/**
7660
* Creates a source link element if a source link is available
77-
*
7861
* @param {string|undefined} sourceLink - The source link path
7962
* @returns {import('hastscript').Element|null} The source link element or null if no source link
8063
*/
@@ -84,7 +67,7 @@ const createSourceLink = sourceLink => {
8467
}
8568

8669
return createElement('span', [
87-
'Source Code: ',
70+
INTERNATIONALIZABLE.sourceCode,
8871
createElement(
8972
'a',
9073
{ href: `${DOC_NODE_BLOB_BASE_URL}${sourceLink}` },
@@ -93,9 +76,25 @@ const createSourceLink = sourceLink => {
9376
]);
9477
};
9578

79+
/**
80+
* Transforms a stability node into an AlertBox JSX element
81+
* @param {import('mdast').Blockquote} node - The stability node to transform
82+
* @param {number} index - The index of the node in its parent's children array
83+
* @param {import('unist').Parent} parent - The parent node containing the stability node
84+
* @returns {[typeof SKIP]} Visitor instruction to skip the node
85+
*/
86+
const transformStabilityNode = ({ data }, index, parent) => {
87+
parent.children[index] = createJSXElement(AST_NODE_TYPES.JSX.ALERT_BOX, {
88+
children: data.description,
89+
level: STABILITY_LEVELS[data.index],
90+
title: data.index,
91+
});
92+
93+
return [SKIP];
94+
};
95+
9696
/**
9797
* Enhances a heading node with metadata, source links, and styling
98-
*
9998
* @param {ApiDocMetadataEntry} entry - The API metadata entry
10099
* @param {import('mdast').Heading} node - The heading node to transform
101100
* @param {number} index - The index of the node in its parent's children array
@@ -106,14 +105,15 @@ const transformHeadingNode = (entry, node, index, parent) => {
106105
const { data, children } = node;
107106
const headerChildren = [
108107
createElement(`h${data.depth + 1}`, [
109-
createElement(`a.mark#${data.slug}`, { href: `#${data.slug}` }, children),
108+
createElement(`a#${data.slug}`, { href: `#${data.slug}` }, children),
110109
]),
111110
];
112111

113112
// Add type icon if available
114-
const iconSymbol = ICON_SYMBOL_MAP[data.type];
115-
if (iconSymbol) {
116-
headerChildren.unshift(createJSXElement('CircularIcon', iconSymbol));
113+
if (data.type in API_ICONS) {
114+
headerChildren.unshift(
115+
createJSXElement(AST_NODE_TYPES.JSX.CIRCULAR_ICON, API_ICONS[data.type])
116+
);
117117
}
118118

119119
// Add change history if available
@@ -136,7 +136,6 @@ const transformHeadingNode = (entry, node, index, parent) => {
136136

137137
/**
138138
* Processes an API documentation entry by applying transformations to its content
139-
*
140139
* @param {ApiDocMetadataEntry} entry - The API metadata entry to process
141140
* @returns {import('unist').Node} The processed content
142141
*/
@@ -155,31 +154,29 @@ const processEntry = entry => {
155154

156155
/**
157156
* Creates the overall content structure with processed entries
158-
*
159157
* @param {Array<ApiDocMetadataEntry>} entries - API documentation metadata entries
160-
* @param {Object} sideBarProps - Props for the sidebar component
161-
* @param {Object} metaBarProps - Props for the meta bar component
158+
* @param {Record<string, any>} sideBarProps - Props for the sidebar component
159+
* @param {Record<string, any>} metaBarProps - Props for the meta bar component
162160
* @returns {import('unist').Node} The root node of the content tree
163161
*/
164162
const createContentStructure = (entries, sideBarProps, metaBarProps) => {
165163
return createTree('root', [
166-
createJSXElement('NavBar'),
167-
createJSXElement('Article', {
164+
createJSXElement(AST_NODE_TYPES.JSX.NAV_BAR),
165+
createJSXElement(AST_NODE_TYPES.JSX.ARTICLE, {
168166
children: [
169-
createJSXElement('SideBar', sideBarProps),
167+
createJSXElement(AST_NODE_TYPES.JSX.SIDE_BAR, sideBarProps),
170168
createElement('div', [
171169
createElement('main', entries.map(processEntry)),
172-
createJSXElement('MetaBar', metaBarProps),
170+
createJSXElement(AST_NODE_TYPES.JSX.META_BAR, metaBarProps),
173171
]),
174-
createJSXElement('Footer'),
172+
createJSXElement(AST_NODE_TYPES.JSX.FOOTER),
175173
],
176174
}),
177175
]);
178176
};
179177

180178
/**
181179
* Transforms API metadata entries into processed MDX content
182-
*
183180
* @param {Array<ApiDocMetadataEntry>} metadataEntries - API documentation metadata entries
184181
* @param {ApiDocMetadataEntry} head - Main API metadata entry with version information
185182
* @param {Object} sideBarProps - Props for the sidebar component

0 commit comments

Comments
 (0)