mirror of
https://github.com/reactjs/react.dev.git
synced 2026-02-25 05:03:07 +00:00
In https://github.com/facebook/react/pull/34462 for example, we found an issue where the compiler was incorrectly validating an example straight from the docs. In order to find more issues like this + also provide more feedback to doc authors on valid/invalid patterns, this PR adds a new local eslint rule which validates all markdown codeblocks containing components/hooks with React Compiler. An autofixer is also provided. To express that a codeblock has an expected error, we can use the following metadata: ```ts // pseudo type def type MarkdownCodeBlockMetadata = { expectedErrors?: { 'react-compiler'?: number[]; }; }; ``` and can be used like so: ```` ```js {expectedErrors: {'react-compiler': [4]}} // ❌ setState directly in render function Component({value}) { const [count, setCount] = useState(0); setCount(value); // error on L4 return <div>{count}</div>; } ``` ```` Because this is defined as a local rule, we don't have the same granular reporting that `eslint-plugin-react-hooks` yet. I can look into that later but for now this first PR just sets us up with something basic.
78 lines
2.0 KiB
JavaScript
78 lines
2.0 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
function getRelativeLine(loc) {
|
|
return loc?.start?.line ?? loc?.line ?? 1;
|
|
}
|
|
|
|
function getRelativeColumn(loc) {
|
|
return loc?.start?.column ?? loc?.column ?? 0;
|
|
}
|
|
|
|
function getRelativeEndLine(loc, fallbackLine) {
|
|
if (loc?.end?.line != null) {
|
|
return loc.end.line;
|
|
}
|
|
if (loc?.line != null) {
|
|
return loc.line;
|
|
}
|
|
return fallbackLine;
|
|
}
|
|
|
|
function getRelativeEndColumn(loc, fallbackColumn) {
|
|
if (loc?.end?.column != null) {
|
|
return loc.end.column;
|
|
}
|
|
if (loc?.column != null) {
|
|
return loc.column;
|
|
}
|
|
return fallbackColumn;
|
|
}
|
|
|
|
/**
|
|
* @param {import('./markdown').MarkdownCodeBlock} block
|
|
* @param {Array<{detail: any, loc: any, message: string}>} diagnostics
|
|
* @returns {Array<{detail: any, message: string, relativeStartLine: number, markdownLoc: {start: {line: number, column: number}, end: {line: number, column: number}}}>}
|
|
*/
|
|
function normalizeDiagnostics(block, diagnostics) {
|
|
return diagnostics.map(({detail, loc, message}) => {
|
|
const relativeStartLine = Math.max(getRelativeLine(loc), 1);
|
|
const relativeStartColumn = Math.max(getRelativeColumn(loc), 0);
|
|
const relativeEndLine = Math.max(
|
|
getRelativeEndLine(loc, relativeStartLine),
|
|
relativeStartLine
|
|
);
|
|
const relativeEndColumn = Math.max(
|
|
getRelativeEndColumn(loc, relativeStartColumn),
|
|
relativeStartColumn
|
|
);
|
|
|
|
const markdownStartLine = block.codeStartLine + relativeStartLine - 1;
|
|
const markdownEndLine = block.codeStartLine + relativeEndLine - 1;
|
|
|
|
return {
|
|
detail,
|
|
message,
|
|
relativeStartLine,
|
|
markdownLoc: {
|
|
start: {
|
|
line: markdownStartLine,
|
|
column: relativeStartColumn,
|
|
},
|
|
end: {
|
|
line: markdownEndLine,
|
|
column: relativeEndColumn,
|
|
},
|
|
},
|
|
};
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
normalizeDiagnostics,
|
|
};
|