Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/generators/jsx-ast/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,5 @@ export const TYPES_WITH_METHOD_SIGNATURES = [
'method',
'classMethod',
];

export const TRIMMABLE_PADDING_REGEX = /^[\s:]+/;
2 changes: 1 addition & 1 deletion src/generators/jsx-ast/utils/buildContent.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ export const processEntry = (entry, remark) => {
// Transform typed lists into property tables
visit(
content,
createQueries.UNIST.isTypedList,
createQueries.UNIST.isStronglyTypedList,
(node, idx, parent) => (parent.children[idx] = createPropertyTable(node))
);

Expand Down
8 changes: 6 additions & 2 deletions src/generators/jsx-ast/utils/buildPropertyTable.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { h as createElement } from 'hastscript';

import createQueries from '../../../utils/queries/index.mjs';
import { TRIMMABLE_PADDING_REGEX } from '../constants.mjs';

/**
* Determines if a node looks like part of a type annotation.
Expand Down Expand Up @@ -124,7 +125,10 @@ export const parseListIntoProperties = node => {

// Clean up leading whitespace in remaining description
if (children[0]?.type === 'text') {
children[0].value = children[0].value.trimStart();
children[0].value = children[0].value.replace(
TRIMMABLE_PADDING_REGEX,
''
);
}

properties.push({
Expand All @@ -133,7 +137,7 @@ export const parseListIntoProperties = node => {
// The remaining children are the description
desc: children,
// Is there a list within this list?
sublist: sublists.find(createQueries.UNIST.isTypedList),
sublist: sublists.find(createQueries.UNIST.isLooselyTypedList),
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/generators/jsx-ast/utils/buildSignature.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const getFullName = ({ name, text }, fallback = name) => {
*/
export default ({ children }, { data }, idx) => {
// Try to locate the parameter list immediately following the heading
const listIdx = children.findIndex(createQueries.UNIST.isTypedList);
const listIdx = children.findIndex(createQueries.UNIST.isStronglyTypedList);

// Parse parameters from the list, if found
const params =
Expand Down
2 changes: 1 addition & 1 deletion src/generators/legacy-json/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const DEFAULT_EXPRESSION = /\s*\*\*Default:\*\*\s*([^]+)$/i;

// Grabs the parameters from a method's signature
// ex/ 'new buffer.Blob([sources[, options]])'.match(PARAM_EXPRESSION) === ['([sources[, options]])', '[sources[, options]]']
export const PARAM_EXPRESSION = /\((.+)\);?$/;
export const PARAM_EXPRESSION = /\(([^)]+)\);?$/;

// The plurals associated with each section type.
export const SECTION_TYPE_PLURALS = {
Expand Down
26 changes: 13 additions & 13 deletions src/generators/legacy-json/utils/__tests__/parseList.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ import {
parseList,
} from '../parseList.mjs';

const validTypedList = [
{ type: 'inlineCode', value: 'option' }, // inline code
{ type: 'text', value: ' ' }, // space
{
type: 'link',
children: [{ type: 'text', value: '<boolean>' }], // link with < value
},
{ type: 'text', value: ' option description' },
];

describe('transformTypeReferences', () => {
it('replaces template syntax with curly braces', () => {
const result = transformTypeReferences('`<string>`');
Expand Down Expand Up @@ -90,7 +100,7 @@ describe('parseList', () => {
children: [
{
type: 'paragraph',
children: [{ type: 'text', value: '{string} description' }],
children: validTypedList,
},
],
},
Expand Down Expand Up @@ -134,9 +144,7 @@ describe('parseList', () => {
children: [
{
type: 'paragraph',
children: [
{ type: 'text', value: 'param1 {string} first parameter' },
],
children: validTypedList,
},
// This is a nested typed list
{
Expand All @@ -146,15 +154,7 @@ describe('parseList', () => {
children: [
{
type: 'paragraph',
children: [
{ type: 'inlineCode', value: 'option' }, // inline code
{ type: 'text', value: ' ' }, // space
{
type: 'link',
children: [{ type: 'text', value: '<boolean>' }], // link with < value
},
{ type: 'text', value: ' option description' },
],
children: validTypedList,
},
],
},
Expand Down
21 changes: 13 additions & 8 deletions src/generators/legacy-json/utils/buildSection.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const createSectionBuilder = () => {

meta.changes = changes;

if (n_api_version?.length) {
if (typeof n_api_version === 'number' || n_api_version?.length) {
meta.napiVersion = enforceArray(n_api_version);
}

Expand Down Expand Up @@ -102,13 +102,18 @@ export const createSectionBuilder = () => {
* @param {Array} nodes - The remaining AST nodes.
* @param {import('../types.d.ts').HierarchizedEntry} entry - The entry providing stability information.
*/
const parseStability = (section, nodes, { stability }) => {
const stabilityInfo = stability.children.map(node => node.data)?.[0];
const parseStability = (section, nodes, { stability, content }) => {
const stabilityNode = stability.children[0];

if (stabilityInfo) {
section.stability = Number(stabilityInfo.index);
section.stabilityText = stabilityInfo.description;
nodes.shift(); // Remove stability node from processing
if (stabilityNode) {
section.stability = Number(stabilityNode.data.index);
section.stabilityText = stabilityNode.data.description;

const stabilityIdx = content.children.indexOf(stability.children[0]);

if (stabilityIdx) {
nodes.splice(stabilityIdx - 1, 1);
}
}
};

Expand Down Expand Up @@ -153,7 +158,7 @@ export const createSectionBuilder = () => {
* @param {import('../types.d.ts').Section} parent - The parent section.
*/
const addToParent = (section, parent) => {
const key = SECTION_TYPE_PLURALS[section.type] || 'miscs';
const key = SECTION_TYPE_PLURALS[section.type] || 'properties';

parent[key] ??= [];
parent[key].push(section);
Expand Down
20 changes: 13 additions & 7 deletions src/generators/legacy-json/utils/parseList.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const extractPattern = (text, pattern, key, current) => {
export function parseListItem(child) {
const current = {};

const subList = child.children.find(createQueries.UNIST.isTypedList);
const subList = child.children.find(createQueries.UNIST.isLooselyTypedList);

// Extract and clean raw text from the node, excluding nested lists
current.textRaw = transformTypeReferences(
Expand Down Expand Up @@ -89,10 +89,13 @@ export function parseListItem(child) {
* @param {import('@types/mdast').RootContent[]} nodes
*/
export function parseList(section, nodes) {
const list = nodes[0]?.type === 'list' ? nodes.shift() : null;
const listIdx = nodes.findIndex(createQueries.UNIST.isStronglyTypedList);
const list = nodes[listIdx];

const values = list ? list.children.map(parseListItem) : [];

let removeList = true;

// Update the section based on its type and parsed values
switch (section.type) {
case 'ctor':
Expand All @@ -109,7 +112,9 @@ export function parseList(section, nodes) {
case 'property':
// For properties, update type and other details if values exist
if (values.length) {
leftHandAssign(section, values[0]);
delete values[0].name;

Object.assign(section, values[0]);
}
break;

Expand All @@ -119,9 +124,10 @@ export function parseList(section, nodes) {
break;

default:
// If no specific handling, re-add the list for further processing
if (list) {
nodes.unshift(list);
}
removeList = false;
}

if (removeList && list) {
nodes.splice(listIdx, 1);
}
}
7 changes: 2 additions & 5 deletions src/metadata.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,8 @@ const createMetadata = slugger => {
*
* @param {StabilityIndexParent} stability The stability index node to be added
*/
addStability: stability => {
// We clone the stability to ensure that we don't accidentally override it
// with later mutations below on the `.create` method
internalMetadata.stability.children.push({ ...stability });
},
addStability: stability =>
internalMetadata.stability.children.push(stability),
/**
* Set the Metadata (from YAML if exists) properties to the current Metadata entry
* it also allows for extra data (such as Stability Index) and miscellaneous data to be set
Expand Down
9 changes: 6 additions & 3 deletions src/utils/parser/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,20 @@ const FUNCTION_CALL = '\\([^)]*\\)';
// Matches "bar":
// Group 1: foo[bar]
// Group 2: foo.bar
const PROPERTY = `${CAMEL_CASE}(?:(\\[${CAMEL_CASE}\\])|\\.(\\w+))`;
const PROPERTY = `${CAMEL_CASE}(?:(\\[[^\\]]+\\])|\\.(\\w+))`;

// An array of objects defining the different types of API doc headings we want to
// capture and their respective regex to match against the heading text.
// The regex are case-insensitive.
export const DOC_API_HEADING_TYPES = [
{
type: 'method',
regex: new RegExp(`^\`${PROPERTY}${FUNCTION_CALL}\`$`, 'i'),
regex: new RegExp(
`^\`(?:${PROPERTY}|(${CAMEL_CASE}))${FUNCTION_CALL}\`$`,
'i'
),
},
{ type: 'event', regex: /^Event: +`'?([^']+)'`$/i },
{ type: 'event', regex: /^Event: +`'?([^`]*?)'?`$/i },
{
type: 'class',
regex: new RegExp(
Expand Down
14 changes: 10 additions & 4 deletions src/utils/queries/__tests__/index.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,23 @@ describe('createQueries', () => {
});

describe('UNIST', () => {
describe('isTypedList', () => {
describe('isStronglyTypedList', () => {
it('returns false for non-list nodes', () => {
strictEqual(
createQueries.UNIST.isTypedList({ type: 'paragraph', children: [] }),
createQueries.UNIST.isStronglyTypedList({
type: 'paragraph',
children: [],
}),
false
);
});

it('returns false for empty lists', () => {
strictEqual(
createQueries.UNIST.isTypedList({ type: 'list', children: [] }),
createQueries.UNIST.isStronglyTypedList({
type: 'list',
children: [],
}),
false
);
});
Expand Down Expand Up @@ -211,7 +217,7 @@ describe('createQueries', () => {

cases.forEach(({ name, node, expected }) => {
it(`returns ${expected} for ${name}`, () => {
strictEqual(createQueries.UNIST.isTypedList(node), expected);
strictEqual(createQueries.UNIST.isStronglyTypedList(node), expected);
});
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/utils/queries/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
export const DOC_API_STABILITY_SECTION_REF_URL =
'documentation.html#stability-index';

export const VALID_JAVASCRIPT_PROPERTY = /^[.a-z0-9$_]+$/i;
export const VALID_JAVASCRIPT_PROPERTY = /^[.a-z0-9$_'-]+$/i;
72 changes: 22 additions & 50 deletions src/utils/queries/index.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
'use strict';

import { u as createTree } from 'unist-builder';
import { SKIP } from 'unist-util-visit';

import {
DOC_API_STABILITY_SECTION_REF_URL,
VALID_JAVASCRIPT_PROPERTY,
} from './constants.mjs';
import { DOC_API_STABILITY_SECTION_REF_URL } from './constants.mjs';
import {
extractYamlContent,
parseHeadingIntoMetadata,
Expand All @@ -16,6 +12,7 @@ import {
} from '../parser/index.mjs';
import { getRemark } from '../remark.mjs';
import { transformNodesToString } from '../unist.mjs';
import { isTypedList } from './utils.mjs';

/**
* Creates an instance of the Query Manager, which allows to do multiple sort
Expand Down Expand Up @@ -144,15 +141,8 @@ const createQueries = typeMap => {
description: matches[2].replace(/\n/g, ' ').trim(),
};

// Creates a new Tree node containing the Stability Index metadata
const stabilityIndexNode = createTree(
'root',
{ data: node.data },
node.children
);

// Adds the Stability Index metadata to the current Metadata entry
apiEntryMetadata?.addStability(stabilityIndexNode);
apiEntryMetadata?.addStability(node);
}

return [SKIP];
Expand Down Expand Up @@ -272,46 +262,28 @@ createQueries.UNIST = {
* @param {import('@types/mdast').List} list
* @returns {boolean}
*/
isTypedList: list => {
// Exit early if not a list node
if (list.type !== 'list') {
return false;
}

// Get the content nodes of the first list item's paragraph
const [node, ...contentNodes] =
list?.children?.[0]?.children?.[0]?.children ?? [];
isLooselyTypedList: list => Boolean(isTypedList(list)),

// Exit if no node
if (!node) {
return false;
}

const possibleProperty = node?.value?.trimStart();

// Check for other starters
if (possibleProperty?.match(createQueries.QUERIES.typedListStarters)) {
return true;
}

// Check for direct type link pattern (starts with '<')
if (node.type === 'link' && node.children?.[0]?.value?.[0] === '<') {
return true;
}

// Check for inline code + space + type link pattern
if (
node.type === 'inlineCode' &&
possibleProperty?.match(VALID_JAVASCRIPT_PROPERTY) &&
contentNodes[0]?.value?.trim() === '' &&
contentNodes[1]?.type === 'link' &&
contentNodes[1]?.children?.[0]?.value?.[0] === '<'
) {
return true;
/**
* @param {import('@types/mdast').List} list
* @returns {boolean}
*/
isStronglyTypedList: list => {
const confidence = isTypedList(list);

if (confidence === 1) {
// This is a loosely typed list, but we can still check if it is strongly typed.
const [, secondNode, thirdNode] =
list.children?.[0]?.children?.[0]?.children ?? [];

return (
secondNode?.value?.trim() === '' &&
thirdNode?.type === 'link' &&
thirdNode?.children?.[0]?.value?.[0] === '<'
);
}

// Not a typed list
return false;
return Boolean(confidence);
},
};

Expand Down
Loading
Loading