From 68296f97acbe792549c1e0f0043527727d2eb901 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Fri, 14 Jun 2024 17:02:41 +0200 Subject: [PATCH 01/11] Add patterns index validation --- package.json | 1 + scripts/commands/checkPatternsIndex.ts | 183 +++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 scripts/commands/checkPatternsIndex.ts diff --git a/package.json b/package.json index c0083f9d93f..a3dcededb9f 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "check:internal-links": "node -r esbuild-register scripts/commands/checkInternalLinks.ts", "check:external-links": "node -r esbuild-register scripts/commands/checkExternalLinks.ts", "check:pages-render": "node -r esbuild-register scripts/commands/checkPagesRender.ts", + "check:patterns-index": "node -r esbuild-register scripts/commands/checkPatternsIndex.ts", "check:orphan-pages": "node -r esbuild-register scripts/commands/checkOrphanPages.ts", "check:qiskit-bot": "node -r esbuild-register scripts/commands/checkQiskitBotFiles.ts", "check:stale-images": "node -r esbuild-register scripts/commands/checkStaleImages.ts", diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts new file mode 100644 index 00000000000..bb9b904fbaa --- /dev/null +++ b/scripts/commands/checkPatternsIndex.ts @@ -0,0 +1,183 @@ +// This code is a Qiskit project. +// +// (C) Copyright IBM 2024. +// +// This code is licensed under the Apache License, Version 2.0. You may +// obtain a copy of this license in the LICENSE file in the root directory +// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +// +// Any modifications or derivative works of this code must retain this +// copyright notice, and modified files need to carry a notice indicating +// that they have been altered from the originals. + +import { readFile } from "fs/promises"; + +const IGNORE_URL = ["/guides/qiskit-serverless"]; + +const INDEX_PAGES = [ + "docs/guides/map-problem-to-circuits.mdx", + "docs/guides/optimize-for-hardware.mdx", + "docs/guides/execute-on-hardware.mdx", + "docs/guides/postprocess-results.mdx", +]; + +const TOC_PATH = `docs/guides/_toc.json`; + +async function getIndexPages(indexPage: string): Promise<string[]> { + const rawIndex = await readFile(indexPage, "utf-8"); + const result: string[] = []; + for (const line of rawIndex.split("\n")) { + // The index represents an unordered list of entries starting with `*`. + if (!line.trimStart().startsWith("* ")) { + continue; + } + + const module = extractPageSlug(line); + if (module) { + result.push(module); + } + } + + return result; +} + +function extractPageSlug(text: string): string | undefined { + const re = /\((.*)\)/gm; + // Ex: '* [Circuit library](./circuit-library)'. + const match = re.exec(text); + if (!match) { + return; + } + const pageSlug = match[1]; + if (pageSlug.startsWith("http") || pageSlug.startsWith("/")) { + return pageSlug; + } + return `/guides/${pageSlug.split("/").pop()}`; +} + +function getTocSectionPageNames(sectionNode: any): string[] { + let results = []; + if (sectionNode.url) { + results.push(sectionNode.url); + } + + if (sectionNode.children) { + for (const child of sectionNode.children) { + results = [...results, ...getTocSectionPageNames(child)]; + } + } + + return results; +} + +async function getToolsTocEntriesToCheck(): Promise<string[]> { + const toc = JSON.parse(await readFile(TOC_PATH, "utf-8")); + const toolsNode = toc.children.find((child: any) => child.title == "Tools"); + const toolsPages = getTocSectionPageNames(toolsNode); + return toolsPages.filter((page) => !IGNORE_URL.includes(page)); +} + +async function getPagesAndDuplicatesErrors( + src: string, + entries: string[], +): Promise<[string[], string[]]> { + const toolsPages: string[] = []; + const errors = []; + for (const entry of entries) { + if (toolsPages.includes(entry)) { + errors.push(`❌ ${src}: The entry ${entry} is duplicated`); + } else { + toolsPages.push(entry); + } + } + + return [toolsPages, errors]; +} + +function printErrors( + duplicatesErrors: string[], + extraIndexEntriesErrors: string[], + extraToolsEntriesErrors: string[], +): void { + if (duplicatesErrors.length > 0) { + duplicatesErrors.forEach((error) => console.error(error)); + console.error(`\nRemove all duplicated entries on the indices.`); + console.error("--------\n"); + } + + if (extraIndexEntriesErrors.length > 0) { + extraIndexEntriesErrors.forEach((error) => console.error(error)); + console.error(`\nMake sure all pages have an entry in the Tools menu.`); + console.error("--------\n"); + } + + if (extraToolsEntriesErrors.length > 0) { + extraToolsEntriesErrors.forEach((error) => console.error(error)); + console.error( + "\nAdd the entries in one of the following index pages, or add the URL to the `IGNORE_URL` list at the beginning of `/scripts/commands/checkPatternsIndex.tsx` if it's not used in Workflow:", + ); + INDEX_PAGES.forEach((index) => console.error(`\t➡️ ${index}`)); + } + + if ( + duplicatesErrors.length > 0 || + extraIndexEntriesErrors.length > 0 || + extraToolsEntriesErrors.length > 0 + ) { + process.exit(1); + } +} + +async function main() { + const duplicatesErrors: string[] = []; + const extraIndexEntriesErrors: string[] = []; + const extraToolsEntriesErrors: string[] = []; + + const toolsEntries = await getToolsTocEntriesToCheck(); + let [toolsPages, toolsErrors] = await getPagesAndDuplicatesErrors( + TOC_PATH, + toolsEntries, + ); + duplicatesErrors.push(...toolsErrors); + + for (const indexPage of INDEX_PAGES) { + const indexEntries = await getIndexPages(indexPage); + let [indexPages, indexErrors] = await getPagesAndDuplicatesErrors( + indexPage, + indexEntries, + ); + duplicatesErrors.push(...indexErrors); + + const ExtraIndexPages = indexPages.filter( + (page) => !toolsPages.includes(page), + ); + if (ExtraIndexPages.length > 0) { + ExtraIndexPages.forEach((page) => + extraIndexEntriesErrors.push( + `❌ ${indexPage}: The entry ${page} doesn't appear in the \`Tools\` menu.`, + ), + ); + } + + toolsPages = toolsPages.filter((page) => !indexPages.includes(page)); + } + + if (toolsPages.length > 0) { + toolsPages.forEach((page) => + extraToolsEntriesErrors.push( + `❌ The entry ${page} is not present on any index page`, + ), + ); + } + + printErrors( + duplicatesErrors, + extraIndexEntriesErrors, + extraToolsEntriesErrors, + ); + console.log("\n✅ No missing or duplicated pages were found\n"); +} + +main().then(() => process.exit()); + +// TODO: Allow that the guides/ folder don't exist From b0e6b834d4b77c99859c0687954820d64cbfb3b9 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Fri, 14 Jun 2024 18:13:05 +0200 Subject: [PATCH 02/11] rename functions and add comments --- scripts/commands/checkPatternsIndex.ts | 27 +++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index bb9b904fbaa..13fa7352796 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -23,7 +23,7 @@ const INDEX_PAGES = [ const TOC_PATH = `docs/guides/_toc.json`; -async function getIndexPages(indexPage: string): Promise<string[]> { +async function getIndexEntries(indexPage: string): Promise<string[]> { const rawIndex = await readFile(indexPage, "utf-8"); const result: string[] = []; for (const line of rawIndex.split("\n")) { @@ -77,7 +77,7 @@ async function getToolsTocEntriesToCheck(): Promise<string[]> { return toolsPages.filter((page) => !IGNORE_URL.includes(page)); } -async function getPagesAndDuplicatesErrors( +async function deduplicateEntriesAndGetErrors( src: string, entries: string[], ): Promise<[string[], string[]]> { @@ -133,23 +133,23 @@ async function main() { const extraIndexEntriesErrors: string[] = []; const extraToolsEntriesErrors: string[] = []; - const toolsEntries = await getToolsTocEntriesToCheck(); - let [toolsPages, toolsErrors] = await getPagesAndDuplicatesErrors( + const allToolsEntries = await getToolsTocEntriesToCheck(); + let [toolsEntries, toolsErrors] = await deduplicateEntriesAndGetErrors( TOC_PATH, - toolsEntries, + allToolsEntries, ); duplicatesErrors.push(...toolsErrors); for (const indexPage of INDEX_PAGES) { - const indexEntries = await getIndexPages(indexPage); - let [indexPages, indexErrors] = await getPagesAndDuplicatesErrors( + const allIndexEntries = await getIndexEntries(indexPage); + let [indexEntries, indexErrors] = await deduplicateEntriesAndGetErrors( indexPage, - indexEntries, + allIndexEntries, ); duplicatesErrors.push(...indexErrors); - const ExtraIndexPages = indexPages.filter( - (page) => !toolsPages.includes(page), + const ExtraIndexPages = indexEntries.filter( + (page) => !toolsEntries.includes(page), ); if (ExtraIndexPages.length > 0) { ExtraIndexPages.forEach((page) => @@ -159,11 +159,12 @@ async function main() { ); } - toolsPages = toolsPages.filter((page) => !indexPages.includes(page)); + // Remove index entries from the tools entries list + toolsEntries = toolsEntries.filter((page) => !indexEntries.includes(page)); } - if (toolsPages.length > 0) { - toolsPages.forEach((page) => + if (toolsEntries.length > 0) { + toolsEntries.forEach((page) => extraToolsEntriesErrors.push( `❌ The entry ${page} is not present on any index page`, ), From 511922c30a3e7b9f3dc7b8d51782d5821b6e4455 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Fri, 14 Jun 2024 18:27:07 +0200 Subject: [PATCH 03/11] skip check if reorg is not done --- .github/workflows/main.yml | 2 ++ package.json | 2 +- scripts/commands/checkPatternsIndex.ts | 14 ++++++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 734b31ec92f..6ff86b63a2c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,6 +32,8 @@ jobs: run: npm run check:spelling - name: Check Qiskit bot config run: npm run check:qiskit-bot + - name: Check Patterns index + run: npm run check:patterns-index - name: Internal link checker run: npm run check:internal-links - name: Check orphaned pages diff --git a/package.json b/package.json index a3dcededb9f..302c2e9175c 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Qiskit Development Team", "license": "Apache-2.0", "scripts": { - "check": "npm run check:qiskit-bot && npm run check:metadata && npm run check:spelling && npm run check:internal-links && npm run check:orphan-pages && npm run check:fmt", + "check": "npm run check:qiskit-bot && npm run check:patterns-index && npm run check:metadata && npm run check:spelling && npm run check:internal-links && npm run check:orphan-pages && npm run check:fmt", "check:metadata": "node -r esbuild-register scripts/commands/checkMetadata.ts", "check:spelling": "cspell --relative --no-progress docs/**/*.md* docs/api/**/*.md* --config cspell/cSpell.json", "check:fmt": "prettier --check .", diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index 13fa7352796..f22045a717f 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -11,6 +11,7 @@ // that they have been altered from the originals. import { readFile } from "fs/promises"; +import { pathExists } from "../lib/fs"; const IGNORE_URL = ["/guides/qiskit-serverless"]; @@ -94,7 +95,7 @@ async function deduplicateEntriesAndGetErrors( return [toolsPages, errors]; } -function printErrors( +function maybePrintErrorsAndFail( duplicatesErrors: string[], extraIndexEntriesErrors: string[], extraToolsEntriesErrors: string[], @@ -129,6 +130,15 @@ function printErrors( } async function main() { + // Todo: Remove this conditional once the migration is done. This is used only to avoid + // the script crashing if the file's structure doesn't exist. + if (!(await pathExists(TOC_PATH))) { + console.log( + `🚧 Check skipped because the migration hasn't been completed.\n`, + ); + process.exit(0); + } + const duplicatesErrors: string[] = []; const extraIndexEntriesErrors: string[] = []; const extraToolsEntriesErrors: string[] = []; @@ -171,7 +181,7 @@ async function main() { ); } - printErrors( + maybePrintErrorsAndFail( duplicatesErrors, extraIndexEntriesErrors, extraToolsEntriesErrors, From 409887345eeb18e59ea06ee3a1245145c8745f93 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Fri, 14 Jun 2024 19:47:57 +0200 Subject: [PATCH 04/11] refactor script --- scripts/commands/checkPatternsIndex.ts | 104 +++++++++++++++---------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index f22045a717f..580575d2cd3 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -33,9 +33,9 @@ async function getIndexEntries(indexPage: string): Promise<string[]> { continue; } - const module = extractPageSlug(line); - if (module) { - result.push(module); + const slug = extractPageSlug(line); + if (slug) { + result.push(slug); } } @@ -47,7 +47,8 @@ function extractPageSlug(text: string): string | undefined { // Ex: '* [Circuit library](./circuit-library)'. const match = re.exec(text); if (!match) { - return; + // Nested sections don't have any link + return undefined; } const pageSlug = match[1]; if (pageSlug.startsWith("http") || pageSlug.startsWith("/")) { @@ -78,21 +79,54 @@ async function getToolsTocEntriesToCheck(): Promise<string[]> { return toolsPages.filter((page) => !IGNORE_URL.includes(page)); } -async function deduplicateEntriesAndGetErrors( +async function getDeduplicateEntriesAndAddErrors( src: string, - entries: string[], -): Promise<[string[], string[]]> { - const toolsPages: string[] = []; - const errors = []; + errors: string[], +): Promise<string[]> { + const entries = + src == TOC_PATH + ? await getToolsTocEntriesToCheck() + : await getIndexEntries(src); + const deduplicatedPages: string[] = []; + for (const entry of entries) { - if (toolsPages.includes(entry)) { + if (deduplicatedPages.includes(entry)) { errors.push(`❌ ${src}: The entry ${entry} is duplicated`); } else { - toolsPages.push(entry); + deduplicatedPages.push(entry); } } - return [toolsPages, errors]; + return deduplicatedPages; +} + +function addExtraIndexPagesErrors( + indexPage: string, + indexEntries: string[], + toolsEntries: string[], + errors: string[], +): void { + const ExtraIndexPages = indexEntries.filter( + (page) => !toolsEntries.includes(page), + ); + if (ExtraIndexPages.length > 0) { + ExtraIndexPages.forEach((page) => + errors.push( + `❌ ${indexPage}: The entry ${page} doesn't appear in the \`Tools\` menu.`, + ), + ); + } +} + +function addExtraToolsEntriesErrors( + toolsEntries: string[], + errors: string[], +): void { + if (toolsEntries.length > 0) { + toolsEntries.forEach((page) => + errors.push(`❌ The entry ${page} is not present on any index page`), + ); + } } function maybePrintErrorsAndFail( @@ -100,16 +134,20 @@ function maybePrintErrorsAndFail( extraIndexEntriesErrors: string[], extraToolsEntriesErrors: string[], ): void { + let allGood = true; + if (duplicatesErrors.length > 0) { duplicatesErrors.forEach((error) => console.error(error)); console.error(`\nRemove all duplicated entries on the indices.`); console.error("--------\n"); + allGood = false; } if (extraIndexEntriesErrors.length > 0) { extraIndexEntriesErrors.forEach((error) => console.error(error)); console.error(`\nMake sure all pages have an entry in the Tools menu.`); console.error("--------\n"); + allGood = false; } if (extraToolsEntriesErrors.length > 0) { @@ -118,13 +156,10 @@ function maybePrintErrorsAndFail( "\nAdd the entries in one of the following index pages, or add the URL to the `IGNORE_URL` list at the beginning of `/scripts/commands/checkPatternsIndex.tsx` if it's not used in Workflow:", ); INDEX_PAGES.forEach((index) => console.error(`\t➡️ ${index}`)); + allGood = false; } - if ( - duplicatesErrors.length > 0 || - extraIndexEntriesErrors.length > 0 || - extraToolsEntriesErrors.length > 0 - ) { + if (!allGood) { process.exit(1); } } @@ -143,43 +178,28 @@ async function main() { const extraIndexEntriesErrors: string[] = []; const extraToolsEntriesErrors: string[] = []; - const allToolsEntries = await getToolsTocEntriesToCheck(); - let [toolsEntries, toolsErrors] = await deduplicateEntriesAndGetErrors( + let toolsEntries = await getDeduplicateEntriesAndAddErrors( TOC_PATH, - allToolsEntries, + duplicatesErrors, ); - duplicatesErrors.push(...toolsErrors); for (const indexPage of INDEX_PAGES) { - const allIndexEntries = await getIndexEntries(indexPage); - let [indexEntries, indexErrors] = await deduplicateEntriesAndGetErrors( + const indexEntries = await getDeduplicateEntriesAndAddErrors( indexPage, - allIndexEntries, + duplicatesErrors, ); - duplicatesErrors.push(...indexErrors); - - const ExtraIndexPages = indexEntries.filter( - (page) => !toolsEntries.includes(page), + addExtraIndexPagesErrors( + indexPage, + indexEntries, + toolsEntries, + extraIndexEntriesErrors, ); - if (ExtraIndexPages.length > 0) { - ExtraIndexPages.forEach((page) => - extraIndexEntriesErrors.push( - `❌ ${indexPage}: The entry ${page} doesn't appear in the \`Tools\` menu.`, - ), - ); - } // Remove index entries from the tools entries list toolsEntries = toolsEntries.filter((page) => !indexEntries.includes(page)); } - if (toolsEntries.length > 0) { - toolsEntries.forEach((page) => - extraToolsEntriesErrors.push( - `❌ The entry ${page} is not present on any index page`, - ), - ); - } + addExtraToolsEntriesErrors(toolsEntries, extraToolsEntriesErrors); maybePrintErrorsAndFail( duplicatesErrors, From 51fa929a2dd8dbcae7607a8c0d9051275ff3a7a0 Mon Sep 17 00:00:00 2001 From: Arnau Casau <47946624+arnaucasau@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:11:32 +0200 Subject: [PATCH 05/11] Remove todo --- scripts/commands/checkPatternsIndex.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index 580575d2cd3..7e608c6d110 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -210,5 +210,3 @@ async function main() { } main().then(() => process.exit()); - -// TODO: Allow that the guides/ folder don't exist From 18bce22f6d7d3aa7c7b62b03cabdab8a09311448 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Tue, 18 Jun 2024 15:28:53 +0200 Subject: [PATCH 06/11] incorporate feedback --- scripts/commands/checkPatternsIndex.ts | 120 ++++++++++++------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index 7e608c6d110..e4af7406137 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -12,8 +12,9 @@ import { readFile } from "fs/promises"; import { pathExists } from "../lib/fs"; +import type { TocEntry } from "../lib/api/generateToc"; -const IGNORE_URL = ["/guides/qiskit-serverless"]; +const IGNORED_URLS = ["/guides/qiskit-serverless"]; const INDEX_PAGES = [ "docs/guides/map-problem-to-circuits.mdx", @@ -22,13 +23,15 @@ const INDEX_PAGES = [ "docs/guides/postprocess-results.mdx", ]; -const TOC_PATH = `docs/guides/_toc.json`; +const TOC_PATH = "docs/guides/_toc.json"; -async function getIndexEntries(indexPage: string): Promise<string[]> { - const rawIndex = await readFile(indexPage, "utf-8"); +async function getIndexEntries(indexPath: string): Promise<string[]> { + const rawIndex = await readFile(indexPath, "utf-8"); const result: string[] = []; + // The index page has several unordered lists starting with *, each with links to other pages. + // We want to get every slug from those lists. Note that we don't care which list the slugs show + // up in - we only care if the slug shows up at all anywhere. for (const line of rawIndex.split("\n")) { - // The index represents an unordered list of entries starting with `*`. if (!line.trimStart().startsWith("* ")) { continue; } @@ -54,10 +57,11 @@ function extractPageSlug(text: string): string | undefined { if (pageSlug.startsWith("http") || pageSlug.startsWith("/")) { return pageSlug; } - return `/guides/${pageSlug.split("/").pop()}`; + const page = pageSlug.split("/").pop(); + return `/guides/${page}`; } -function getTocSectionPageNames(sectionNode: any): string[] { +function getTocSectionPageNames(sectionNode: TocEntry): string[] { let results = []; if (sectionNode.url) { results.push(sectionNode.url); @@ -74,59 +78,50 @@ function getTocSectionPageNames(sectionNode: any): string[] { async function getToolsTocEntriesToCheck(): Promise<string[]> { const toc = JSON.parse(await readFile(TOC_PATH, "utf-8")); - const toolsNode = toc.children.find((child: any) => child.title == "Tools"); + const toolsNode = toc.children.find( + (child: TocEntry) => child.title == "Tools", + ); const toolsPages = getTocSectionPageNames(toolsNode); - return toolsPages.filter((page) => !IGNORE_URL.includes(page)); + return toolsPages.filter((page) => !IGNORED_URLS.includes(page)); } -async function getDeduplicateEntriesAndAddErrors( +async function deduplicateEntries( src: string, - errors: string[], -): Promise<string[]> { - const entries = - src == TOC_PATH - ? await getToolsTocEntriesToCheck() - : await getIndexEntries(src); - const deduplicatedPages: string[] = []; + entries: string[], +): Promise<[Set<string>, string[]]> { + const deduplicatedPages: Set<string> = new Set(); + const errors: string[] = []; for (const entry of entries) { - if (deduplicatedPages.includes(entry)) { + if (deduplicatedPages.has(entry)) { errors.push(`❌ ${src}: The entry ${entry} is duplicated`); } else { - deduplicatedPages.push(entry); + deduplicatedPages.add(entry); } } - return deduplicatedPages; + return [deduplicatedPages, errors]; } -function addExtraIndexPagesErrors( +function getExtraIndexPagesErrors( indexPage: string, - indexEntries: string[], - toolsEntries: string[], - errors: string[], -): void { - const ExtraIndexPages = indexEntries.filter( - (page) => !toolsEntries.includes(page), + indexEntries: Set<string>, + toolsEntries: Set<string>, +): string[] { + const extraIndexPages = [...indexEntries].filter( + (page) => !toolsEntries.has(page), + ); + + return extraIndexPages.map( + (page) => + `❌ ${indexPage}: The entry ${page} doesn't appear in the \`Tools\` menu.`, ); - if (ExtraIndexPages.length > 0) { - ExtraIndexPages.forEach((page) => - errors.push( - `❌ ${indexPage}: The entry ${page} doesn't appear in the \`Tools\` menu.`, - ), - ); - } } -function addExtraToolsEntriesErrors( - toolsEntries: string[], - errors: string[], -): void { - if (toolsEntries.length > 0) { - toolsEntries.forEach((page) => - errors.push(`❌ The entry ${page} is not present on any index page`), - ); - } +function getExtraToolsEntriesErrors(toolsEntries: Set<string>): string[] { + return [...toolsEntries].map( + (page) => `❌ The entry ${page} is not present on any index page`, + ); } function maybePrintErrorsAndFail( @@ -138,7 +133,9 @@ function maybePrintErrorsAndFail( if (duplicatesErrors.length > 0) { duplicatesErrors.forEach((error) => console.error(error)); - console.error(`\nRemove all duplicated entries on the indices.`); + console.error( + `\nRemove all duplicated entries on the indices and Tools menu, which is set in docs/guides/_toc.json.`, + ); console.error("--------\n"); allGood = false; } @@ -153,7 +150,7 @@ function maybePrintErrorsAndFail( if (extraToolsEntriesErrors.length > 0) { extraToolsEntriesErrors.forEach((error) => console.error(error)); console.error( - "\nAdd the entries in one of the following index pages, or add the URL to the `IGNORE_URL` list at the beginning of `/scripts/commands/checkPatternsIndex.tsx` if it's not used in Workflow:", + "\nAdd the entries in one of the following index pages, or add the URL to the `IGNORED_URLS` list at the beginning of `/scripts/commands/checkPatternsIndex.tsx` if it's not used in Workflow:", ); INDEX_PAGES.forEach((index) => console.error(`\t➡️ ${index}`)); allGood = false; @@ -174,32 +171,33 @@ async function main() { process.exit(0); } - const duplicatesErrors: string[] = []; - const extraIndexEntriesErrors: string[] = []; - const extraToolsEntriesErrors: string[] = []; - - let toolsEntries = await getDeduplicateEntriesAndAddErrors( + const toolsAllEntries = await getToolsTocEntriesToCheck(); + let [toolsEntries, duplicatesErrors] = await deduplicateEntries( TOC_PATH, - duplicatesErrors, + toolsAllEntries, ); + let extraIndexEntriesErrors: string[] = []; for (const indexPage of INDEX_PAGES) { - const indexEntries = await getDeduplicateEntriesAndAddErrors( + const indexAllEntries = await getIndexEntries(indexPage); + let [indexEntries, indexDuplicatedErrors] = await deduplicateEntries( indexPage, - duplicatesErrors, - ); - addExtraIndexPagesErrors( - indexPage, - indexEntries, - toolsEntries, - extraIndexEntriesErrors, + indexAllEntries, ); + duplicatesErrors = [...duplicatesErrors, ...indexDuplicatedErrors]; + + extraIndexEntriesErrors = [ + ...extraIndexEntriesErrors, + ...getExtraIndexPagesErrors(indexPage, indexEntries, toolsEntries), + ]; // Remove index entries from the tools entries list - toolsEntries = toolsEntries.filter((page) => !indexEntries.includes(page)); + toolsEntries = new Set( + [...toolsEntries].filter((page) => !indexEntries.has(page)), + ); } - addExtraToolsEntriesErrors(toolsEntries, extraToolsEntriesErrors); + const extraToolsEntriesErrors = getExtraToolsEntriesErrors(toolsEntries); maybePrintErrorsAndFail( duplicatesErrors, From 9d7a7b0341788e8b8af83a66b9f104c2dd30f696 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Tue, 18 Jun 2024 15:31:30 +0200 Subject: [PATCH 07/11] comment --- scripts/commands/checkPatternsIndex.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index e4af7406137..c5fdd520a71 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -134,7 +134,7 @@ function maybePrintErrorsAndFail( if (duplicatesErrors.length > 0) { duplicatesErrors.forEach((error) => console.error(error)); console.error( - `\nRemove all duplicated entries on the indices and Tools menu, which is set in docs/guides/_toc.json.`, + `\nRemove all duplicated entries on the indices and in the Tools menu, which is set in docs/guides/_toc.json.`, ); console.error("--------\n"); allGood = false; From a56ce22f36495b7abfd4f5526efdd20d460891ca Mon Sep 17 00:00:00 2001 From: Arnau Casau <47946624+arnaucasau@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:32:01 +0200 Subject: [PATCH 08/11] Update scripts/commands/checkPatternsIndex.ts Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> --- scripts/commands/checkPatternsIndex.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index c5fdd520a71..50feb924829 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -142,7 +142,7 @@ function maybePrintErrorsAndFail( if (extraIndexEntriesErrors.length > 0) { extraIndexEntriesErrors.forEach((error) => console.error(error)); - console.error(`\nMake sure all pages have an entry in the Tools menu.`); + console.error(`\nMake sure all pages have an entry in the Tools menu, which is set in docs/guides/_toc.json.`); console.error("--------\n"); allGood = false; } From 2a41ee71fe234c08e55b1c43e0309690964840d8 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Tue, 18 Jun 2024 15:37:50 +0200 Subject: [PATCH 09/11] lint --- scripts/commands/checkPatternsIndex.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index 50feb924829..0c4db3c5c4f 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -142,7 +142,9 @@ function maybePrintErrorsAndFail( if (extraIndexEntriesErrors.length > 0) { extraIndexEntriesErrors.forEach((error) => console.error(error)); - console.error(`\nMake sure all pages have an entry in the Tools menu, which is set in docs/guides/_toc.json.`); + console.error( + `\nMake sure all pages have an entry in the Tools menu, which is set in docs/guides/_toc.json.`, + ); console.error("--------\n"); allGood = false; } From a6f0e183e332245d67ebd10c9c113b27ff384034 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Tue, 18 Jun 2024 21:05:53 +0200 Subject: [PATCH 10/11] feedback Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> --- scripts/commands/checkPatternsIndex.ts | 33 +++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index 0c4db3c5c4f..faedc7e1b58 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -69,7 +69,7 @@ function getTocSectionPageNames(sectionNode: TocEntry): string[] { if (sectionNode.children) { for (const child of sectionNode.children) { - results = [...results, ...getTocSectionPageNames(child)]; + results.push(...getTocSectionPageNames(child)); } } @@ -86,7 +86,7 @@ async function getToolsTocEntriesToCheck(): Promise<string[]> { } async function deduplicateEntries( - src: string, + filePath: string, entries: string[], ): Promise<[Set<string>, string[]]> { const deduplicatedPages: Set<string> = new Set(); @@ -94,7 +94,7 @@ async function deduplicateEntries( for (const entry of entries) { if (deduplicatedPages.has(entry)) { - errors.push(`❌ ${src}: The entry ${entry} is duplicated`); + errors.push(`❌ ${filePath}: The entry ${entry} is duplicated`); } else { deduplicatedPages.add(entry); } @@ -108,18 +108,18 @@ function getExtraIndexPagesErrors( indexEntries: Set<string>, toolsEntries: Set<string>, ): string[] { - const extraIndexPages = [...indexEntries].filter( - (page) => !toolsEntries.has(page), - ); - - return extraIndexPages.map( - (page) => - `❌ ${indexPage}: The entry ${page} doesn't appear in the \`Tools\` menu.`, - ); + return [...indexEntries] + .filter((page) => !toolsEntries.has(page)) + .map( + (page) => + `❌ ${indexPage}: The entry ${page} doesn't appear in the \`Tools\` menu.`, + ); } -function getExtraToolsEntriesErrors(toolsEntries: Set<string>): string[] { - return [...toolsEntries].map( +function getExtraToolsEntriesErrors( + remainingToolsEntries: Set<string>, +): string[] { + return [...remainingToolsEntries].map( (page) => `❌ The entry ${page} is not present on any index page`, ); } @@ -186,12 +186,11 @@ async function main() { indexPage, indexAllEntries, ); - duplicatesErrors = [...duplicatesErrors, ...indexDuplicatedErrors]; + duplicatesErrors.push(...indexDuplicatedErrors); - extraIndexEntriesErrors = [ - ...extraIndexEntriesErrors, + extraIndexEntriesErrors.push( ...getExtraIndexPagesErrors(indexPage, indexEntries, toolsEntries), - ]; + ); // Remove index entries from the tools entries list toolsEntries = new Set( From c3ff441a988ac60cfa710b661e5cb84a646a9a33 Mon Sep 17 00:00:00 2001 From: Arnau Casau <arnaucasau@gmail.com> Date: Tue, 18 Jun 2024 21:22:58 +0200 Subject: [PATCH 11/11] use delete in the toolsEntries Set --- scripts/commands/checkPatternsIndex.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/commands/checkPatternsIndex.ts b/scripts/commands/checkPatternsIndex.ts index faedc7e1b58..4675040d289 100644 --- a/scripts/commands/checkPatternsIndex.ts +++ b/scripts/commands/checkPatternsIndex.ts @@ -192,10 +192,11 @@ async function main() { ...getExtraIndexPagesErrors(indexPage, indexEntries, toolsEntries), ); - // Remove index entries from the tools entries list - toolsEntries = new Set( - [...toolsEntries].filter((page) => !indexEntries.has(page)), - ); + toolsEntries.forEach((page) => { + if (indexEntries.has(page)) { + toolsEntries.delete(page); + } + }); } const extraToolsEntriesErrors = getExtraToolsEntriesErrors(toolsEntries);