Skip to content

Commit

Permalink
chore(website): insert generated content in the right position (#6596)
Browse files Browse the repository at this point in the history
* chore(website): insert generated content in the right position

* More refactor

---------

Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
  • Loading branch information
Josh-Cena and bradzacher committed Mar 13, 2023
1 parent 2d8c196 commit 7298934
Showing 1 changed file with 83 additions and 98 deletions.
181 changes: 83 additions & 98 deletions packages/website/plugins/generated-rule-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,17 @@ export const generatedRuleDocs: Plugin = () => {
return;
}

// Workaround for root being un-narrowed inside closures
const children = root.children;

// 1. Remove the " 🛑 This file is source code, not the primary documentation location! 🛑"
root.children.splice(
root.children.findIndex(v => v.type === 'blockquote'),
children.splice(
children.findIndex(v => v.type === 'blockquote'),
1,
);

// 2. Add a description of the rule at the top of the file
root.children.unshift(
children.unshift(
{
children: [
{
Expand Down Expand Up @@ -86,75 +89,60 @@ export const generatedRuleDocs: Plugin = () => {
`,
type: 'jsx',
};
root.children.unshift(warningNode);
children.unshift(warningNode);
}

// 4. Make sure the appropriate headers exist to place content under
const [howToUseH2Index, optionsH2Index] = ((): [number, number] => {
let howToUseH2Index = root.children.findIndex(
createH2TextFilter('How to Use'),
);
let optionsH2Index = root.children.findIndex(
createH2TextFilter('Options'),
);
const relatedToH2Index = root.children.findIndex(
createH2TextFilter('Related To'),
);
let whenNotToUseItH2Index = root.children.findIndex(
createH2TextFilter('When Not To Use It'),
// eslint-disable-next-line prefer-const
let [howToUseH2Index, optionsH2Index] = ((): [number, number] => {
// The first two may be autogenerated. Inserting one heading requires
// shifting all following ones
const headingNames = [
'How to Use',
'Options',
'When Not To Use It',
'Related To',
];
const headingIndices = headingNames.map(text =>
children.findIndex(
(node: unist.Node): node is mdast.Heading =>
nodeIsHeading(node) &&
node.depth === 2 &&
node.children.length === 1 &&
node.children[0].type === 'text' &&
node.children[0].value === text,
),
);

if (meta.docs.extendsBaseRule) {
if (howToUseH2Index === -1) {
if (optionsH2Index !== -1) {
howToUseH2Index = optionsH2Index;
optionsH2Index += 1;

if (whenNotToUseItH2Index !== -1) {
whenNotToUseItH2Index += 1;
}
} else {
howToUseH2Index =
whenNotToUseItH2Index === -1
? root.children.length
: ++whenNotToUseItH2Index;
}

root.children.splice(howToUseH2Index, 0, {
function insertIfMissing(name: string): void {
const num = headingNames.indexOf(name);
if (headingIndices[num] === -1) {
const insertIndex =
headingIndices.find(v => v !== -1) ?? children.length;
children.splice(insertIndex, 0, {
children: [
{
type: 'text',
value: 'How to Use',
value: name,
},
],
depth: 2,
type: 'heading',
} as mdast.Heading);
headingIndices[num] = insertIndex;
for (let i = num + 1; i < headingIndices.length; i++) {
if (headingIndices[i] !== -1) {
headingIndices[i] += 1;
}
}
}
}

if (optionsH2Index === -1) {
optionsH2Index =
whenNotToUseItH2Index === -1
? relatedToH2Index === -1
? root.children.length
: relatedToH2Index
: whenNotToUseItH2Index;
root.children.splice(optionsH2Index, 0, {
children: [
{
type: 'text',
value: 'Options',
},
],
depth: 2,
type: 'heading',
} as mdast.Heading);

optionsH2Index += 1;
if (meta.docs.extendsBaseRule) {
insertIfMissing('How to Use');
}

return [howToUseH2Index, optionsH2Index];
insertIfMissing('Options');
return [headingIndices[0], headingIndices[1]];
})();

if (meta.docs.extendsBaseRule) {
Expand All @@ -163,7 +151,7 @@ export const generatedRuleDocs: Plugin = () => {
? meta.docs.extendsBaseRule
: file.stem;

root.children.splice(optionsH2Index + 1, 0, {
children.splice(optionsH2Index + 1, 0, {
children: [
{
value: 'See ',
Expand Down Expand Up @@ -208,23 +196,26 @@ export const generatedRuleDocs: Plugin = () => {
}`;
};

root.children.splice(howToUseH2Index + 1, 0, {
lang: 'js',
type: 'code',
meta: 'title=".eslintrc.cjs"',
value: `module.exports = ${getEslintrcString(true)};`,
} as mdast.Code);

root.children.splice(howToUseH2Index + 2, 0, {
value: `<try-in-playground eslintrcHash="${convertToPlaygroundHash(
getEslintrcString(false),
)}" />`,
type: 'jsx',
} as unist.Node);
children.splice(
howToUseH2Index + 1,
0,
{
lang: 'js',
type: 'code',
meta: 'title=".eslintrc.cjs"',
value: `module.exports = ${getEslintrcString(true)};`,
} as mdast.Code,
{
value: `<try-in-playground eslintrcHash="${convertToPlaygroundHash(
getEslintrcString(false),
)}" />`,
type: 'jsx',
} as unist.Node,
);
} else {
// For non-extended rules, the code snippet is placed before the first h2
// (i.e. at the end of the initial explanation)
const firstH2Index = root.children.findIndex(
const firstH2Index = children.findIndex(
child => nodeIsHeading(child) && child.depth === 2,
);

Expand All @@ -233,22 +224,27 @@ export const generatedRuleDocs: Plugin = () => {
"@typescript-eslint/${file.stem}": "error"
}
}`;
root.children.splice(firstH2Index, 0, {
lang: 'js',
type: 'code',
meta: 'title=".eslintrc.cjs"',
value: `module.exports = ${getEslintrcString};`,
} as mdast.Code);
children.splice(
firstH2Index,
0,
{
lang: 'js',
type: 'code',
meta: 'title=".eslintrc.cjs"',
value: `module.exports = ${getEslintrcString};`,
} as mdast.Code,
{
value: `<try-in-playground eslintrcHash="${convertToPlaygroundHash(
getEslintrcString,
)}" />`,
type: 'jsx',
} as unist.Node,
);

root.children.splice(firstH2Index + 1, 0, {
value: `<try-in-playground eslintrcHash="${convertToPlaygroundHash(
getEslintrcString,
)}" />`,
type: 'jsx',
} as unist.Node);
optionsH2Index += 2;

if (meta.schema.length === 0) {
root.children.splice(optionsH2Index + 1, 0, {
children.splice(optionsH2Index + 1, 0, {
children: [
{
type: 'text',
Expand All @@ -273,8 +269,8 @@ export const generatedRuleDocs: Plugin = () => {
}
: meta.schema;

root.children.splice(
optionsH2Index + 2,
children.splice(
optionsH2Index + 1,
0,
{
children: [
Expand Down Expand Up @@ -324,7 +320,7 @@ export const generatedRuleDocs: Plugin = () => {
}

// 5. Add a link to view the rule's source and test code
root.children.push(
children.push(
{
children: [
{
Expand Down Expand Up @@ -384,7 +380,7 @@ export const generatedRuleDocs: Plugin = () => {

// 6. Also add a notice about coming from ESLint core for extension rules
if (meta.docs.extendsBaseRule) {
root.children.push({
children.push({
children: [
{
type: 'jsx',
Expand Down Expand Up @@ -428,17 +424,6 @@ function nodeIsHeading(node: unist.Node): node is mdast.Heading {
return node.type === 'heading';
}

function createH2TextFilter(
text: string,
): (node: unist.Node) => node is mdast.Heading {
return (node: unist.Node): node is mdast.Heading =>
nodeIsHeading(node) &&
node.depth === 2 &&
node.children.length === 1 &&
node.children[0].type === 'text' &&
node.children[0].value === text;
}

function getUrlForRuleTest(ruleName: string): string {
for (const localPath of [
`tests/rules/${ruleName}.test.ts`,
Expand Down

0 comments on commit 7298934

Please sign in to comment.