From 06083184494d18dc99e87633fe98c14527bf771b Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Fri, 30 Jun 2023 14:32:52 -0400 Subject: [PATCH] fix(nx-dev): skip docs for private package (#17843) --- .../documentation/internal-link-checker.ts | 34 ++++++- .../package-schemas/generatePackageSchemas.ts | 6 +- .../package-schemas/package-metadata.ts | 92 ++++++++++--------- 3 files changed, 87 insertions(+), 45 deletions(-) diff --git a/scripts/documentation/internal-link-checker.ts b/scripts/documentation/internal-link-checker.ts index 15b18c4b9b2f8..8bc61de1584a2 100644 --- a/scripts/documentation/internal-link-checker.ts +++ b/scripts/documentation/internal-link-checker.ts @@ -1,5 +1,6 @@ import { workspaceRoot } from '@nx/devkit'; import { XMLParser } from 'fast-xml-parser'; +import { existsSync, readJSONSync } from 'fs-extra'; import * as glob from 'glob'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; @@ -82,6 +83,33 @@ function readSiteMapLinks(filePath: string): string[] { return sitemap.urlset.url.map((obj) => obj.loc); } +/** + * This function checks if a link is for a private package. + * When link is for a private package, it is not included in the sitemap. + * However, some shared docs might be written for this private package during development. + * @param link e.g. /packages/vite/generators/configuration + * @returns true if the link is for a private package or NODE_ENV is not development, false otherwise. + */ +function checkLinkIsForPrivatePackage(link: string) { + // skip this check in dev mode + if (process.env.NODE_ENV === 'development') { + return false; + } + const pathSegments = link.split('/').filter(Boolean); + if (pathSegments[0] === 'packages') { + const packageJsonPath = join( + workspaceRoot, + pathSegments[0], + pathSegments[1], + 'package.json' + ); + if (existsSync(packageJsonPath)) { + return readJSONSync(packageJsonPath).private ?? false; + } + } + return false; +} + // Main const documentLinks = extractAllLinks(join(workspaceRoot, 'docs')); const sitemapLinks = readSiteMapIndex( @@ -91,8 +119,12 @@ const sitemapLinks = readSiteMapIndex( const errors: Array<{ file: string; link: string }> = []; for (let file in documentLinks) { for (let link of documentLinks[file]) { - if (!sitemapLinks.includes(['https://nx.dev', link].join(''))) + if ( + !sitemapLinks.includes(['https://nx.dev', link].join('')) && + !checkLinkIsForPrivatePackage(link) + ) { errors.push({ file, link }); + } } } diff --git a/scripts/documentation/package-schemas/generatePackageSchemas.ts b/scripts/documentation/package-schemas/generatePackageSchemas.ts index 3119ccf4f8e87..9cab633e63bec 100644 --- a/scripts/documentation/package-schemas/generatePackageSchemas.ts +++ b/scripts/documentation/package-schemas/generatePackageSchemas.ts @@ -10,7 +10,7 @@ import { } from '@nx/nx-dev/data-access-packages'; import { NxSchema, PackageMetadata } from '@nx/nx-dev/models-package'; import { generateJsonFile, generateMarkdownFile } from '../utils'; -import { getPackageMetadataList } from './package-metadata'; +import { findPackageMetadataList } from './package-metadata'; import { schemaResolver } from './schema.resolver'; function processSchemaData(data: NxSchema, path: string): NxSchema { @@ -37,7 +37,7 @@ export function generatePackageSchemas(): Promise { console.log(`${chalk.blue('i')} Generating Package Schemas`); const absoluteRoot = resolve(join(__dirname, '../../../')); - const packages = getPackageMetadataList(absoluteRoot, 'packages', 'docs').map( + const packages = findPackageMetadataList(absoluteRoot, 'packages').map( (packageMetadata) => { const getCurrentSchemaPath = pathResolver(absoluteRoot); if (!!packageMetadata.executors.length) { @@ -116,7 +116,7 @@ export function generatePackageSchemas(): Promise { const outputPath: string = join(absoluteRoot, 'docs', 'generated'); const outputPackagesPath: string = join(outputPath, 'packages'); - const fileGenerationPromises = []; + const fileGenerationPromises: Promise[] = []; // Generates all documents and schemas into their own directories per packages. packages.forEach((p) => { diff --git a/scripts/documentation/package-schemas/package-metadata.ts b/scripts/documentation/package-schemas/package-metadata.ts index 4bceb845bacdf..a28acb98e3410 100644 --- a/scripts/documentation/package-schemas/package-metadata.ts +++ b/scripts/documentation/package-schemas/package-metadata.ts @@ -94,15 +94,18 @@ function getSchemaList( /** * Generate the package metadata by exploring the directory path given. + * This function will look for all the packages in the given directory under packagesDirectory. + * It will then look for the package.json file and read the description and name of the package. + * It will also look for the generators.json and executors.json files and read the schema of each generator and executor. + * It will also look for the documents.json file and read the documents of each package. + * If the package is private and NODE_ENV is not development, it will not be included in the metadata. * @param absoluteRoot * @param packagesDirectory - * @param documentationDirectory * @returns Configuration */ -export function getPackageMetadataList( +export function findPackageMetadataList( absoluteRoot: string, - packagesDirectory: string = 'packages', - documentationDirectory: string = 'docs' + packagesDirectory: string = 'packages' ): PackageData[] { const packagesDir = resolve(join(absoluteRoot, packagesDirectory)); @@ -114,52 +117,59 @@ export function getPackageMetadataList( .itemList.map((item) => convertToDocumentMetadata(item)); // Do not use map.json, but add a documentation property on the package.json directly that can be easily resolved - return sync(`${packagesDir}/*`, { ignore: [`${packagesDir}/cli`] }).map( - (folderPath): PackageData => { + return sync(`${packagesDir}/*`, { ignore: [`${packagesDir}/cli`] }) + .map((folderPath: string): PackageData => { const folderName = folderPath.substring(packagesDir.length + 1); const relativeFolderPath = folderPath.replace(absoluteRoot, ''); const packageJson = readJsonSync( join(folderPath, 'package.json'), 'utf8' ); + const isPrivate = + packageJson.private && process.env.NODE_ENV !== 'development'; // skip this check in dev mode const hasDocumentation = additionalApiReferences.find( (pkg) => pkg.id === folderName ); - return { - githubRoot: 'https://github.com/nrwl/nx/blob/master', - name: folderName, - packageName: packageJson.name, - description: packageJson.description, - root: relativeFolderPath, - source: join(relativeFolderPath, '/src'), - documents: !!hasDocumentation - ? hasDocumentation.itemList.map((item) => ({ - ...item, - path: item.path, - file: item.file, - content: readFileSync(join('docs', item.file + '.md'), 'utf8'), - })) - : [], - generators: getSchemaList( - { - absoluteRoot, - folderName, + return isPrivate + ? null + : { + githubRoot: 'https://github.com/nrwl/nx/blob/master', + name: folderName, + packageName: packageJson.name, + description: packageJson.description, root: relativeFolderPath, - }, - 'generators.json', - ['generators'] - ), - executors: getSchemaList( - { - absoluteRoot, - folderName, - root: relativeFolderPath, - }, - 'executors.json', - ['executors', 'builders'] - ), - }; - } - ); + source: join(relativeFolderPath, '/src'), + documents: !!hasDocumentation + ? hasDocumentation.itemList.map((item) => ({ + ...item, + path: item.path, + file: item.file, + content: readFileSync( + join('docs', item.file + '.md'), + 'utf8' + ), + })) + : [], + generators: getSchemaList( + { + absoluteRoot, + folderName, + root: relativeFolderPath, + }, + 'generators.json', + ['generators'] + ), + executors: getSchemaList( + { + absoluteRoot, + folderName, + root: relativeFolderPath, + }, + 'executors.json', + ['executors', 'builders'] + ), + }; + }) + .filter(Boolean); }