Skip to content

chore(queries): organize and test #366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 0 additions & 1 deletion src/generators/addon-verify/constants.mjs

This file was deleted.

2 changes: 1 addition & 1 deletion src/generators/addon-verify/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { join } from 'node:path';

import { visit } from 'unist-util-visit';

import { EXTRACT_CODE_FILENAME_COMMENT } from './constants.mjs';
import { generateFileList } from './utils/generateFileList.mjs';
import {
generateSectionFolderName,
isBuildableSection,
normalizeSectionName,
} from './utils/section.mjs';
import { EXTRACT_CODE_FILENAME_COMMENT } from '../../utils/queries/regex.mjs';

/**
* This generator generates a file list from code blocks extracted from
Expand Down
4 changes: 0 additions & 4 deletions src/generators/api-links/constants.mjs

This file was deleted.

4 changes: 1 addition & 3 deletions src/generators/api-links/utils/extractExports.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import { visit } from 'estree-util-visit';

import { CONSTRUCTOR_EXPRESSION } from '../constants.mjs';

/**
* @see https://github.com/estree/estree/blob/master/es5.md#assignmentexpression
*
Expand Down Expand Up @@ -99,7 +97,7 @@ function handleExpression(node, basename, nameToLineNumberMap) {
case 'Identifier': {
exports.identifiers.push(value.name);

if (CONSTRUCTOR_EXPRESSION.test(value.name[0])) {
if (/^[A-Z]/.test(value.name)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep regexes in constants for easily finding regexes in one place

Copy link
Member Author

@avivkeller avivkeller Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even for these, single-character ones? Or, are you referring to all the RegExps?

exports.ctors.push(value.name);
}

Expand Down
7 changes: 2 additions & 5 deletions src/generators/json-simple/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { join } from 'node:path';

import { remove } from 'unist-util-remove';

import createQueries from '../../utils/queries/index.mjs';
import { isHeading, isStabilityNode } from '../../utils/queries/unist.mjs';

/**
* This generator generates a simplified JSON version of the API docs and returns it as a string
Expand Down Expand Up @@ -41,10 +41,7 @@ export default {

// Removes numerous nodes from the content that should not be on the "body"
// of the JSON version of the API docs as they are already represented in the metadata
remove(content, [
createQueries.UNIST.isStabilityNode,
createQueries.UNIST.isHeading,
]);
remove(content, [isStabilityNode, isHeading]);

return { ...node, content };
});
Expand Down
12 changes: 8 additions & 4 deletions src/generators/jsx-ast/utils/buildContent.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import createPropertyTable from './buildPropertyTable.mjs';
import { DOC_NODE_BLOB_BASE_URL } from '../../../constants.mjs';
import { enforceArray } from '../../../utils/array.mjs';
import { sortChanges } from '../../../utils/generators.mjs';
import createQueries from '../../../utils/queries/index.mjs';
import {
isStabilityNode,
isHeading,
isTypedList,
} from '../../../utils/queries/unist.mjs';
import { JSX_IMPORTS } from '../../web/constants.mjs';
import {
STABILITY_LEVELS,
Expand Down Expand Up @@ -219,17 +223,17 @@ export const processEntry = (entry, remark) => {
const content = structuredClone(entry.content);

// Visit and transform stability nodes
visit(content, createQueries.UNIST.isStabilityNode, transformStabilityNode);
visit(content, isStabilityNode, transformStabilityNode);

// Visit and transform headings with metadata and links
visit(content, createQueries.UNIST.isHeading, (...args) =>
visit(content, isHeading, (...args) =>
transformHeadingNode(entry, remark, ...args)
);

// Transform typed lists into property tables
visit(
content,
createQueries.UNIST.isTypedList,
isTypedList,
(node, idx, parent) => (parent.children[idx] = createPropertyTable(node))
);

Expand Down
9 changes: 4 additions & 5 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 { TYPED_LIST_STARTERS } from '../../../utils/queries/regex.mjs';
import { isTypedList } from '../../../utils/queries/unist.mjs';

/**
* Determines if a node looks like part of a type annotation.
Expand Down Expand Up @@ -51,9 +52,7 @@ export const extractPropertyName = children => {

// Text with a prefix like "Type:", "Param:", etc.
if (first.type === 'text') {
const starterMatch = first.value.match(
createQueries.QUERIES.typedListStarters
);
const starterMatch = first.value.match(TYPED_LIST_STARTERS);
if (starterMatch) {
// If the starter is 'Type', we don't have a property.
const label = starterMatch[1] !== 'Type' && starterMatch[1];
Expand Down Expand Up @@ -133,7 +132,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(isTypedList),
});
}

Expand Down
4 changes: 2 additions & 2 deletions src/generators/jsx-ast/utils/buildSignature.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { highlightToHast } from '@node-core/rehype-shiki';
import { h as createElement } from 'hastscript';

import createQueries from '../../../utils/queries/index.mjs';
import { isTypedList } from '../../../utils/queries/unist.mjs';
import { parseListItem } from '../../legacy-json/utils/parseList.mjs';
import parseSignature from '../../legacy-json/utils/parseSignature.mjs';

Expand Down 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(isTypedList);

// Parse parameters from the list, if found
const params =
Expand Down
15 changes: 10 additions & 5 deletions src/generators/legacy-html/utils/buildContent.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import { SKIP, visit } from 'unist-util-visit';

import buildExtraContent from './buildExtraContent.mjs';
import { DOC_NODE_BLOB_BASE_URL } from '../../../constants.mjs';
import createQueries from '../../../utils/queries/index.mjs';
import { LINKS_WITH_TYPES } from '../../../utils/queries/regex.mjs';
import {
isHeading,
isHtmlWithType,
isStabilityNode,
} from '../../../utils/queries/unist.mjs';

/**
* Builds a Markdown heading for a given node
Expand Down Expand Up @@ -71,7 +76,7 @@ const buildStability = ({ children, data }, index, parent) => {
*/
const buildHtmlTypeLink = node => {
node.value = node.value.replace(
createQueries.QUERIES.linksWithTypes,
LINKS_WITH_TYPES,
(_, type, link) => `<a href="${link}" class="type">&lt;${type}&gt;</a>`
);
};
Expand Down Expand Up @@ -223,16 +228,16 @@ export default (headNodes, metadataEntries, remark) => {
const content = structuredClone(entry.content);

// Parses the Heading nodes into Heading elements
visit(content, createQueries.UNIST.isHeading, buildHeading);
visit(content, isHeading, buildHeading);

// Parses the Blockquotes into Stability elements
// This is treated differently as we want to preserve the position of a Stability Index
// within the content, so we can't just remove it and append it to the metadata
visit(content, createQueries.UNIST.isStabilityNode, buildStability);
visit(content, isStabilityNode, buildStability);

// Parses the type references that got replaced into Markdown links (raw)
// into actual HTML links, these then get parsed into HAST nodes on `runSync`
visit(content, createQueries.UNIST.isHtmlWithType, buildHtmlTypeLink);
visit(content, isHtmlWithType, buildHtmlTypeLink);

// Splits the content into the Heading node and the rest of the content
const [headingNode, ...restNodes] = content.children;
Expand Down
16 changes: 0 additions & 16 deletions src/generators/legacy-json/constants.mjs
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
// Grabs a method's name
export const NAME_EXPRESSION = /^['`"]?([^'`": {]+)['`"]?\s*:?\s*/;

// Denotes a method's type
export const TYPE_EXPRESSION = /^\{([^}]+)\}\s*/;

// Checks if there's a leading hyphen
export const LEADING_HYPHEN = /^-\s*/;

// Grabs the default value if present
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 = /\((.+)\);?$/;

// The plurals associated with each section type.
export const SECTION_TYPE_PLURALS = {
module: 'modules',
Expand Down
14 changes: 7 additions & 7 deletions src/generators/legacy-json/utils/parseList.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import parseSignature from './parseSignature.mjs';
import {
TYPED_LIST_STARTERS,
DEFAULT_EXPRESSION,
LEADING_HYPHEN,
NAME_EXPRESSION,
TYPE_EXPRESSION,
} from '../constants.mjs';
import parseSignature from './parseSignature.mjs';
import createQueries from '../../../utils/queries/index.mjs';
} from '../../../utils/queries/regex.mjs';
import { isTypedList } from '../../../utils/queries/unist.mjs';
import { transformNodesToString } from '../../../utils/unist.mjs';

/**
Expand Down Expand Up @@ -46,7 +46,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(isTypedList);

// Extract and clean raw text from the node, excluding nested lists
current.textRaw = transformTypeReferences(
Expand All @@ -58,7 +58,7 @@ export function parseListItem(child) {
let text = current.textRaw;

// Identify return items or extract key properties (name, type, default) from the text
const starter = text.match(createQueries.QUERIES.typedListStarters);
const starter = text.match(TYPED_LIST_STARTERS);
if (starter) {
current.name =
starter[1] === 'Returns' ? 'return' : starter[1].toLowerCase();
Expand All @@ -71,7 +71,7 @@ export function parseListItem(child) {
text = extractPattern(text, DEFAULT_EXPRESSION, 'default', current);

// Set the remaining text as the description, removing any leading hyphen
current.desc = text.replace(LEADING_HYPHEN, '').trim() || undefined;
current.desc = text.replace(/^-\s*/, '').trim() || undefined;

// Parse nested lists (options) recursively if present
if (subList) {
Expand Down
2 changes: 1 addition & 1 deletion src/generators/legacy-json/utils/parseSignature.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import { PARAM_EXPRESSION } from '../constants.mjs';
import { PARAM_EXPRESSION } from '../../../utils/queries/regex.mjs';

const OPTIONAL_LEVEL_CHANGES = { '[': 1, ']': -1 };

Expand Down
34 changes: 19 additions & 15 deletions src/generators/metadata/utils/parse.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ import { SKIP, visit } from 'unist-util-visit';
import createMetadata from '../../../metadata.mjs';
import createNodeSlugger from '../../../utils/parser/slugger.mjs';
import createQueries from '../../../utils/queries/index.mjs';
import {
isLinkReference,
isMarkdownUrl,
isHeading,
isStabilityNode,
isYamlNode,
isTextWithType,
isTextWithUnixManual,
} from '../../../utils/queries/unist.mjs';
import { getRemark } from '../../../utils/remark.mjs';

/**
Expand Down Expand Up @@ -54,7 +63,7 @@ export const parseApiDoc = ({ file, tree }) => {
const headingNodes = selectAll('heading', tree);

// Handles Markdown link references and updates them to be plain links
visit(tree, createQueries.UNIST.isLinkReference, node =>
visit(tree, isLinkReference, node =>
updateLinkReference(node, markdownDefinitions)
);

Expand All @@ -64,9 +73,7 @@ export const parseApiDoc = ({ file, tree }) => {

// Handles the normalisation URLs that reference to API doc files with .md extension
// to replace the .md into .html, since the API doc files get eventually compiled as HTML
visit(tree, createQueries.UNIST.isMarkdownUrl, node =>
updateMarkdownLink(node)
);
visit(tree, isMarkdownUrl, node => updateMarkdownLink(node));

// If the document has no headings but it has content, we add a fake heading to the top
// so that our parsing logic can work correctly, and generate content for the whole file
Expand All @@ -79,7 +86,7 @@ export const parseApiDoc = ({ file, tree }) => {
// (so all elements after a Heading until the next Heading)
// and then it creates and updates a Metadata entry for each API doc entry
// and then generates the final content for each API doc entry and pushes it to the collection
visit(tree, createQueries.UNIST.isHeading, (headingNode, index) => {
visit(tree, isHeading, (headingNode, index) => {
// Creates a new Metadata entry for the current API doc file
const apiEntryMetadata = createMetadata(nodeSlugger);

Expand All @@ -90,8 +97,7 @@ export const parseApiDoc = ({ file, tree }) => {
// This is used for ensuring that we don't include items that would
// belong only to the next heading to the current Heading metadata
// Note that if there is no next heading, we use the current node as the next one
const nextHeadingNode =
findAfter(tree, index, createQueries.UNIST.isHeading) ?? headingNode;
const nextHeadingNode = findAfter(tree, index, isHeading) ?? headingNode;

// This is the cutover index of the subtree that we should get
// of all the Nodes within the AST tree that belong to this section
Expand All @@ -109,34 +115,32 @@ export const parseApiDoc = ({ file, tree }) => {

// Visits all Stability Index nodes from the current subtree if there's any
// and then apply the Stability Index metadata to the current metadata entry
visit(subTree, createQueries.UNIST.isStabilityNode, node =>
visit(subTree, isStabilityNode, node =>
addStabilityMetadata(node, apiEntryMetadata)
);

// Visits all HTML nodes from the current subtree and if there's any that matches
// our YAML metadata structure, it transforms into YAML metadata
// and then apply the YAML Metadata to the current Metadata entry
visit(subTree, createQueries.UNIST.isYamlNode, node => {
visit(subTree, isYamlNode, node => {
// TODO: Is there always only one YAML node?
apiEntryMetadata.setYamlPosition(node.position);
addYAMLMetadata(node, apiEntryMetadata);
});

// Visits all Text nodes from the current subtree and if there's any that matches
// any API doc type reference and then updates the type reference to be a Markdown link
visit(subTree, createQueries.UNIST.isTextWithType, (node, _, parent) =>
visit(subTree, isTextWithType, (node, _, parent) =>
updateTypeReference(node, parent)
);

// Visits all Unix manual references, and replaces them with links
visit(
subTree,
createQueries.UNIST.isTextWithUnixManual,
(node, _, parent) => updateUnixManualReference(node, parent)
visit(subTree, isTextWithUnixManual, (node, _, parent) =>
updateUnixManualReference(node, parent)
);

// Removes already parsed items from the subtree so that they aren't included in the final content
remove(subTree, [createQueries.UNIST.isYamlNode]);
remove(subTree, [isYamlNode]);

// Applies the AST transformations to the subtree based on the API doc entry Metadata
// Note that running the transformation on the subtree isn't costly as it is a reduced tree
Expand Down
4 changes: 0 additions & 4 deletions src/linter/constants.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
'use strict';

export const INTRODUCED_IN_REGEX = /<!--\s?introduced_in=.*-->/;

export const LLM_DESCRIPTION_REGEX = /<!--\s?llm_description=.*-->/;

export const LINT_MESSAGES = {
missingIntroducedIn: "Missing 'introduced_in' field in the API doc entry",
invalidChangeProperty: 'Invalid change property type',
Expand Down
6 changes: 2 additions & 4 deletions src/linter/rules/duplicate-stability-nodes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { visit } from 'unist-util-visit';

import createQueries from '../../utils/queries/index.mjs';
import { STABILITY_INDEX } from '../../utils/queries/regex.mjs';
import { LINT_MESSAGES } from '../constants.mjs';

/**
Expand Down Expand Up @@ -33,9 +33,7 @@ export const duplicateStabilityNodes = context => {
) {
const text = paragraph.children[0];
if (text.type === 'text') {
const match = text.value.match(
createQueries.QUERIES.stabilityIndex
);
const match = text.value.match(STABILITY_INDEX);
if (match) {
const stability = parseFloat(match[1]);

Expand Down
4 changes: 2 additions & 2 deletions src/linter/rules/invalid-change-version.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
extractYamlContent,
normalizeYamlSyntax,
} from '../../utils/parser/index.mjs';
import createQueries from '../../utils/queries/index.mjs';
import { isYamlNode } from '../../utils/queries/unist.mjs';
import { LINT_MESSAGES } from '../constants.mjs';
import {
createYamlIssueReporter,
Expand Down Expand Up @@ -94,7 +94,7 @@ export const extractVersions = ({ context, node, createYamlIssue }) => {
* @returns {void}
*/
export const invalidChangeVersion = context => {
visit(context.tree, createQueries.UNIST.isYamlNode, node => {
visit(context.tree, isYamlNode, node => {
const yamlContent = extractYamlContent(node);

const normalizedYaml = normalizeYamlSyntax(yamlContent);
Expand Down
Loading
Loading