diff --git a/package.json b/package.json index a06f230ec3..feef0d03be 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "lint": "nx run-many --target=lint --all --parallel", "depcheck": "ts-node -P ./scripts/tsconfig.scripts.json ./scripts/depcheck", "local-registry": "./scripts/local-registry.sh", - "documentation": "./scripts/documentation/documentation.sh && ./scripts/documentation/check-documentation.sh && yarn check-documentation-map && yarn check-internal-links", + "documentation": "ts-node -P scripts/tsconfig.scripts.json ./scripts/documentation/documentation.ts && yarn check-documentation-map && yarn check-internal-links", "submit-plugin": "node ./scripts/submit-plugin.js" }, "devDependencies": { @@ -209,7 +209,6 @@ "sass": "1.26.3", "sass-loader": "8.0.2", "semver": "7.3.4", - "shelljs": "^0.8.3", "source-map": "0.7.3", "source-map-loader": "0.2.4", "source-map-support": "0.5.16", diff --git a/scripts/check-versions.ts b/scripts/check-versions.ts index 5b09ae7829..9622091b51 100644 --- a/scripts/check-versions.ts +++ b/scripts/check-versions.ts @@ -16,8 +16,8 @@ import { join } from 'path'; import { gt } from 'semver'; import * as chalk from 'chalk'; import { dasherize } from '../packages/workspace/src/utils/strings'; -import * as shell from 'shelljs'; import * as glob from 'glob'; +import { execSync } from 'child_process'; const excluded = ['nxVersion']; const scoped = [ @@ -123,7 +123,9 @@ function getVersionData( } { try { const latest = JSON.parse( - shell.exec(`npm view ${p} version --json --silent`, { silent: true }) + execSync(`npm view ${p} version --json --silent`, { + stdio: ['ignore'], + }).toString('utf-8') ); if (gt(latest, v)) { return { package: p, outdated: true, invalid: false, latest, prev: v }; diff --git a/scripts/chmod.js b/scripts/chmod.js index c5b4871836..18c28b7946 100644 --- a/scripts/chmod.js +++ b/scripts/chmod.js @@ -1,3 +1,3 @@ -const shell = require('shelljs'); +const fs = require('fs'); -shell.chmod('+x', process.argv[2]); +fs.chmodSync(process.argv[2], 0o777); diff --git a/scripts/documentation/check-documentation.sh b/scripts/documentation/check-documentation.sh deleted file mode 100755 index 192796e2c6..0000000000 --- a/scripts/documentation/check-documentation.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -if [ -z "$(git status --porcelain ./docs)" ]; then - echo "šŸ“„ Documentation not modified"; - exit 0; -else - echo "šŸ“„ Documentation has been modified, you need to commit the changes."; - git status --porcelain ./docs - exit 1; -fi \ No newline at end of file diff --git a/scripts/documentation/documentation.sh b/scripts/documentation/documentation.sh deleted file mode 100755 index 058f070046..0000000000 --- a/scripts/documentation/documentation.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -set -e - -echo "Generating API documentation" -ts-node -r tsconfig-paths/register --project=scripts/tsconfig.scripts.json ./scripts/documentation/generate-executors-data.ts -ts-node -r tsconfig-paths/register --project=scripts/tsconfig.scripts.json ./scripts/documentation/generate-generators-data.ts -ts-node -r tsconfig-paths/register --project=scripts/tsconfig.scripts.json ./scripts/documentation/generate-cli-data.ts -echo 'Done generating all Documentation' diff --git a/scripts/documentation/documentation.ts b/scripts/documentation/documentation.ts new file mode 100644 index 0000000000..aceca0e2fb --- /dev/null +++ b/scripts/documentation/documentation.ts @@ -0,0 +1,51 @@ +import * as chalk from 'chalk'; +import { execSync } from 'child_process'; + +import { generateCLIDocumentation } from './generate-cli-data'; +import { generateExecutorsDocumentation } from './generate-executors-data'; +import { generateGeneratorsDocumentation } from './generate-generators-data'; + +async function generate() { + console.log(`${chalk.blue('i')} Generating Documentation`); + + await generateGeneratorsDocumentation(); + await generateExecutorsDocumentation(); + await generateCLIDocumentation(); + + console.log(`\n${chalk.green('šŸ—ø')} Generated Documentation\n`); +} + +function checkDocumentation() { + const output = execSync('git status --porcelain ./docs').toString('utf-8'); + + if (output) { + console.log( + `${chalk.red( + '!' + )} šŸ“„ Documentation has been modified, you need to commit the changes. ${chalk.red( + '!' + )} ` + ); + + console.log('\nChanged Docs:'); + execSync('git status --porcelain ./docs', { stdio: 'inherit' }); + + process.exit(1); + } else { + console.log('šŸ“„ Documentation not modified'); + } +} + +generate().then(() => { + checkDocumentation(); +}); + +function printInfo( + str: string, + newLine: boolean = true, + newLineAfter: boolean = true +) { + console.log( + `${newLine ? '\n' : ''}${chalk.blue('i')} ${str}${newLineAfter ? '\n' : ''}` + ); +} diff --git a/scripts/documentation/frameworks.ts b/scripts/documentation/frameworks.ts new file mode 100644 index 0000000000..c9925bce3f --- /dev/null +++ b/scripts/documentation/frameworks.ts @@ -0,0 +1,2 @@ +export const Frameworks = ['angular', 'react', 'node'] as const; +export type Framework = typeof Frameworks[number]; diff --git a/scripts/documentation/generate-cli-data.ts b/scripts/documentation/generate-cli-data.ts index 49c4b27a98..dbf6eb35cc 100644 --- a/scripts/documentation/generate-cli-data.ts +++ b/scripts/documentation/generate-cli-data.ts @@ -1,9 +1,10 @@ +import * as chalk from 'chalk'; import * as fs from 'fs-extra'; import * as path from 'path'; import { dedent } from 'tslint/lib/utils'; import { commandsObject } from '../../packages/workspace'; +import { Framework, Frameworks } from './frameworks'; import { generateMarkdownFile, sortAlphabeticallyFunction } from './utils'; - const importFresh = require('import-fresh'); const examples = { @@ -395,55 +396,59 @@ const sharedCommands = [ 'test', ]; -console.log('Generating Nx Commands Documentation'); -Promise.all( - ['angular', 'react', 'node'].map(async (framework) => { - const commandsOutputDirectory = path.join( - __dirname, - '../../docs/', - framework, - 'cli' - ); - fs.removeSync(commandsOutputDirectory); - function getCommands(command) { - return command.getCommandInstance().getCommandHandlers(); - } - async function parseCommandInstance(name, command) { - // It is not a function return a strip down version of the command - if ( - !( - command.builder && - command.builder.constructor && - command.builder.call && - command.builder.apply - ) - ) { +export async function generateCLIDocumentation() { + console.log(`\n${chalk.blue('i')} Generating Documentation for Nx Commands`); + + await Promise.all( + Frameworks.map(async (framework: Framework) => { + const commandsOutputDirectory = path.join( + __dirname, + '../../docs/', + framework, + 'cli' + ); + fs.removeSync(commandsOutputDirectory); + function getCommands(command) { + return command.getCommandInstance().getCommandHandlers(); + } + async function parseCommandInstance(name, command) { + // It is not a function return a strip down version of the command + if ( + !( + command.builder && + command.builder.constructor && + command.builder.call && + command.builder.apply + ) + ) { + return { + command: name, + description: command['description'], + }; + } + // Show all the options we can get from yargs + const builder = await command.builder( + importFresh('yargs')().resetOptions() + ); + const builderDescriptions = builder + .getUsageInstance() + .getDescriptions(); + const builderDefaultOptions = builder.getOptions().default; return { command: name, description: command['description'], + options: + Object.keys(builderDescriptions).map((key) => ({ + command: '--'.concat(key), + description: builderDescriptions[key] + ? builderDescriptions[key].replace('__yargsString__:', '') + : '', + default: builderDefaultOptions[key], + })) || null, }; } - // Show all the options we can get from yargs - const builder = await command.builder( - importFresh('yargs')().resetOptions() - ); - const builderDescriptions = builder.getUsageInstance().getDescriptions(); - const builderDefaultOptions = builder.getOptions().default; - return { - command: name, - description: command['description'], - options: - Object.keys(builderDescriptions).map((key) => ({ - command: '--'.concat(key), - description: builderDescriptions[key] - ? builderDescriptions[key].replace('__yargsString__:', '') - : '', - default: builderDefaultOptions[key], - })) || null, - }; - } - function generateMarkdown(command) { - let template = dedent` + function generateMarkdown(command) { + let template = dedent` # ${command.command} ${command.description} @@ -454,31 +459,31 @@ Promise.all( Install \`nx\` globally to invoke the command directly using \`nx\`, or use \`npm run nx\` or \`yarn nx\`.\n`; - if (examples[command.command] && examples[command.command].length > 0) { - template += `### Examples`; - examples[command.command].forEach((example) => { - template += dedent` + if (examples[command.command] && examples[command.command].length > 0) { + template += `### Examples`; + examples[command.command].forEach((example) => { + template += dedent` ${example.description}: \`\`\`bash nx ${example.command} \`\`\` `; - }); - } + }); + } - if (Array.isArray(command.options) && !!command.options.length) { - template += '\n## Options'; + if (Array.isArray(command.options) && !!command.options.length) { + template += '\n## Options'; - command.options - .sort((a, b) => - sortAlphabeticallyFunction( - a.command.replace('--', ''), - b.command.replace('--', '') + command.options + .sort((a, b) => + sortAlphabeticallyFunction( + a.command.replace('--', ''), + b.command.replace('--', '') + ) ) - ) - .forEach( - (option) => - (template += dedent` + .forEach( + (option) => + (template += dedent` ### ${option.command.replace('--', '')} ${ option.default === undefined || option.default === '' @@ -487,56 +492,57 @@ Promise.all( } ${option.description} `) - ); + ); + } + + return { + name: command.command + .replace(':', '-') + .replace(' ', '-') + .replace(/[\]\[.]+/gm, ''), + template, + }; } - return { - name: command.command - .replace(':', '-') - .replace(' ', '-') - .replace(/[\]\[.]+/gm, ''), - template, - }; - } + // TODO: Try to add option's type, examples, and group? + const nxCommands = getCommands(commandsObject); + await Promise.all( + Object.keys(nxCommands) + .filter((name) => !sharedCommands.includes(name)) + .map((name) => parseCommandInstance(name, nxCommands[name])) + .map(async (command) => generateMarkdown(await command)) + .map(async (templateObject) => + generateMarkdownFile(commandsOutputDirectory, await templateObject) + ) + ); - // TODO: Try to add option's type, examples, and group? - const nxCommands = getCommands(commandsObject); - await Promise.all( - Object.keys(nxCommands) - .filter((name) => !sharedCommands.includes(name)) - .map((name) => parseCommandInstance(name, nxCommands[name])) - .map(async (command) => generateMarkdown(await command)) - .map(async (templateObject) => - generateMarkdownFile(commandsOutputDirectory, await templateObject) - ) - ); + await Promise.all( + sharedCommands.map((command) => { + const sharedCommandsDirectory = path.join( + __dirname, + '../../docs/shared/cli' + ); + const sharedCommandsOutputDirectory = path.join( + __dirname, + '../../docs/', + framework, + 'cli' + ); + const templateObject = { + name: command, + template: fs + .readFileSync(path.join(sharedCommandsDirectory, `${command}.md`)) + .toString('utf-8'), + }; - await Promise.all( - sharedCommands.map((command) => { - const sharedCommandsDirectory = path.join( - __dirname, - '../../docs/shared/cli' - ); - const sharedCommandsOutputDirectory = path.join( - __dirname, - '../../docs/', - framework, - 'cli' - ); - const templateObject = { - name: command, - template: fs - .readFileSync(path.join(sharedCommandsDirectory, `${command}.md`)) - .toString('utf-8'), - }; + return generateMarkdownFile( + sharedCommandsOutputDirectory, + templateObject + ); + }) + ); + }) + ); - return generateMarkdownFile( - sharedCommandsOutputDirectory, - templateObject - ); - }) - ); - }) -).then(() => { - console.log('Finished generating Nx Commands Documentation'); -}); + console.log(`${chalk.green('šŸ—ø')} Generated Documentation for Nx Commands`); +} diff --git a/scripts/documentation/generate-executors-data.ts b/scripts/documentation/generate-executors-data.ts index 9b9b4ab5dc..614e11f0f8 100644 --- a/scripts/documentation/generate-executors-data.ts +++ b/scripts/documentation/generate-executors-data.ts @@ -18,6 +18,8 @@ import { Configuration, getPackageConfigurations, } from './get-package-configurations'; +import { Framework } from './frameworks'; +import * as chalk from 'chalk'; /** * @WhatItDoes: Generates default documentation from the builders' schema. @@ -69,7 +71,7 @@ function generateSchematicList( } function generateTemplate( - framework, + framework: Framework, builder ): { name: string; template: string } { const filename = framework === 'angular' ? 'angular.json' : 'workspace.json'; @@ -160,41 +162,62 @@ function generateTemplate( return { name: builder.name, template }; } -Promise.all( - getPackageConfigurations().map(({ framework, configs }) => { - return Promise.all( - configs - .filter((item) => item.hasBuilders) - .map((config) => { - Promise.all(generateSchematicList(config, registry)) - .then((builderList) => - builderList.map((b) => generateTemplate(framework, b)) - ) - .then((markdownList) => - Promise.all( - markdownList.map((template) => - generateMarkdownFile(config.builderOutput, template) - ) - ) - ) - .then(() => - console.log( - `Generated documentation for ${config.root} to ${config.output}` +export async function generateExecutorsDocumentation() { + console.log(`\n${chalk.blue('i')} Generating Documentation for Executors\n`); + + await Promise.all( + getPackageConfigurations().map(({ framework, configs }) => { + return Promise.all( + configs + .filter((item) => item.hasBuilders) + .map(async (config) => { + const buildersList = await Promise.all( + generateSchematicList(config, registry) + ); + + const markdownList = buildersList.map((b) => + generateTemplate(framework, b) + ); + + await Promise.all( + markdownList.map((template) => + generateMarkdownFile(config.builderOutput, template) ) ); - }) - ); - }) -).then(() => { - console.log('Done generating documentation for executors'); -}); -getPackageConfigurations().forEach(async ({ framework, configs }) => { - const builders = configs - .filter((item) => item.hasBuilders) - .map((item) => item.name); - await generateJsonFile( - path.join(__dirname, '../../docs', framework, 'executors.json'), - builders + console.log( + ` - ${chalk.blue( + config.framework + )} Documentation for ${chalk.magenta( + path.relative(process.cwd(), config.root) + )} generated at ${chalk.grey( + path.relative(process.cwd(), config.builderOutput) + )}` + ); + }) + ); + }) ); -}); + + console.log(); + await Promise.all( + getPackageConfigurations().map(async ({ framework, configs }) => { + const builders = configs + .filter((item) => item.hasBuilders) + .map((item) => item.name); + + await generateJsonFile( + path.join(__dirname, '../../docs', framework, 'executors.json'), + builders + ); + + console.log( + `${chalk.green('šŸ—ø')} Generated ${chalk.blue( + framework + )} executors.json at ${chalk.grey(`docs/${framework}/executors.json`)}` + ); + }) + ); + + console.log(`\n${chalk.green('šŸ—ø')} Generated Documentation for Executors`); +} diff --git a/scripts/documentation/generate-generators-data.ts b/scripts/documentation/generate-generators-data.ts index 902a9fa803..918385e57d 100644 --- a/scripts/documentation/generate-generators-data.ts +++ b/scripts/documentation/generate-generators-data.ts @@ -1,4 +1,5 @@ import * as fs from 'fs-extra'; +import * as chalk from 'chalk'; import * as path from 'path'; import { dedent } from 'tslint/lib/utils'; import { FileSystemSchematicJsonDescription } from '@angular-devkit/schematics/tools'; @@ -16,6 +17,7 @@ import { Configuration, getPackageConfigurations, } from './get-package-configurations'; +import { Framework } from './frameworks'; import { parseJsonSchemaToOptions } from './json-parser'; /** @@ -61,7 +63,7 @@ function generateSchematicList( } function generateTemplate( - framework: string, + framework: Framework, schematic ): { name: string; template: string } { const cliCommand = 'nx'; @@ -163,43 +165,63 @@ function generateTemplate( return { name: schematic.name, template }; } -Promise.all( - getPackageConfigurations().map(({ framework, configs }) => { - return Promise.all( - configs - .filter((item) => item.hasSchematics) - .map((config) => { - return Promise.all(generateSchematicList(config, registry)) - .then((schematicList) => { - return schematicList - .filter((s) => !s['hidden']) - .map((s) => generateTemplate(framework, s)); - }) - .then((markdownList) => - Promise.all( - markdownList.map((template) => - generateMarkdownFile(config.schematicOutput, template) - ) - ) - ) - .then(() => { - console.log( - `Documentation from ${config.root} generated to ${config.schematicOutput}` - ); - }); - }) - ); - }) -).then(() => { - console.log('Finished Generating Documentation for Generators'); -}); +export async function generateGeneratorsDocumentation() { + console.log(`\n${chalk.blue('i')} Generating Documentation for Generators\n`); -getPackageConfigurations().forEach(async ({ framework, configs }) => { - const schematics = configs - .filter((item) => item.hasSchematics) - .map((item) => item.name); - await generateJsonFile( - path.join(__dirname, '../../docs', framework, 'generators.json'), - schematics + await Promise.all( + getPackageConfigurations().map(({ framework, configs }) => { + return Promise.all( + configs + .filter((item) => item.hasSchematics) + .map(async (config) => { + const schematicList = await Promise.all( + generateSchematicList(config, registry) + ); + + const markdownList = schematicList + .filter((s) => !s['hidden']) + .map((s_1) => generateTemplate(framework, s_1)); + + await Promise.all( + markdownList.map((template) => + generateMarkdownFile(config.schematicOutput, template) + ) + ); + + console.log( + ` - ${chalk.blue( + config.framework + )} Documentation for ${chalk.magenta( + path.relative(process.cwd(), config.root) + )} generated at ${chalk.grey( + path.relative(process.cwd(), config.schematicOutput) + )}` + ); + }) + ); + }) ); -}); + + console.log(); + await Promise.all( + getPackageConfigurations().map(({ framework, configs }) => { + const schematics = configs + .filter((item) => item.hasSchematics) + .map((item) => item.name); + return generateJsonFile( + path.join(__dirname, '../../docs', framework, 'generators.json'), + schematics + ).then(() => { + console.log( + `${chalk.green('šŸ—ø')} Generated ${chalk.blue( + framework + )} generators.json at ${chalk.grey( + `docs/${framework}/generators.json` + )}` + ); + }); + }) + ); + + console.log(`\n${chalk.green('šŸ—ø')} Generated Documentation for Generators`); +} diff --git a/scripts/documentation/get-package-configurations.ts b/scripts/documentation/get-package-configurations.ts index a637a75f56..6f1fbb9934 100644 --- a/scripts/documentation/get-package-configurations.ts +++ b/scripts/documentation/get-package-configurations.ts @@ -1,15 +1,17 @@ +import * as glob from 'glob'; import * as path from 'path'; -import * as shelljs from 'shelljs'; +import { Framework, Frameworks } from './frameworks'; export interface Configuration { name: string; root: string; + framework: Framework; source: string; output: string; builderOutput: string; schematicOutput: string; - hasBuilders: string; - hasSchematics: string; + hasBuilders: boolean; + hasSchematics: boolean; } /** @@ -21,37 +23,43 @@ export interface Configuration { export function getPackageConfigurations( packagesDirectory: string = 'packages', documentationsDirectory: string = 'docs' -): { framework: 'angular' | 'react' | 'node'; configs: Configuration[] }[] { - return ['angular', 'react', 'node'].map((framework) => { +): { framework: Framework; configs: Configuration[] }[] { + return Frameworks.map((framework: Framework) => { const packagesDir = path.resolve( path.join(__dirname, '../../', packagesDirectory) ); const documentationDir = path.resolve( path.join(__dirname, '../../', documentationsDirectory) ); - const configs = shelljs.ls(packagesDir).map((folderName) => { - const itemList = shelljs.ls(path.join(packagesDir, folderName)); - const output = path.join( - documentationDir, - framework, - `api-${folderName}` - ); - return { - name: folderName, - root: path.join(packagesDir, folderName), - source: path.join(packagesDir, `${folderName}/src`), - output, - framework, - builderOutput: path.join(output, 'executors'), - schematicOutput: path.join(output, 'generators'), - hasBuilders: - itemList.includes('builders.json') || - itemList.includes('executors.json'), - hasSchematics: - itemList.includes('collection.json') || - itemList.includes('generators.json'), - }; - }); - return { framework: framework as any, configs }; + + const configs = glob.sync(`${packagesDir}/*`).map( + (folderPath): Configuration => { + const folderName = folderPath.substring(packagesDir.length + 1); + const itemList = glob + .sync(`${folderPath}/*`) + .map((item) => item.split(folderPath + '/')[1]); + const output = path.join( + documentationDir, + framework, + `api-${folderName}` + ); + return { + name: folderName, + root: folderPath, + source: path.join(folderPath, '/src'), + output, + framework, + builderOutput: path.join(output, 'executors'), + schematicOutput: path.join(output, 'generators'), + hasBuilders: + itemList.includes('builders.json') || + itemList.includes('executors.json'), + hasSchematics: + itemList.includes('collection.json') || + itemList.includes('generators.json'), + }; + } + ); + return { framework, configs }; }); } diff --git a/scripts/documentation/internal-link-checker.ts b/scripts/documentation/internal-link-checker.ts index 0cf05d54a6..adaf8a6b75 100644 --- a/scripts/documentation/internal-link-checker.ts +++ b/scripts/documentation/internal-link-checker.ts @@ -1,8 +1,10 @@ -import { green, red } from 'chalk'; -import * as shell from 'shelljs'; +import * as chalk from 'chalk'; import * as fs from 'fs'; import * as parseLinks from 'parse-markdown-links'; import * as path from 'path'; +import * as glob from 'glob'; + +console.log(`${chalk.blue('i')} Internal Link Check`); const LOGGING_KEYS = [ 'LOG_DOC_TREE', @@ -76,7 +78,7 @@ function expandFrameworks(linkPaths: string[]): string[] { } function extractAllInternalLinks(): Record { - return shell.ls(`${BASE_PATH}/**/*.md`).reduce((acc, path) => { + return glob.sync(`${BASE_PATH}/**/*.md`).reduce((acc, path) => { const fileContents = readFileContents(path); const directLinks = fileContents .split(/[ ,]+/) @@ -103,7 +105,7 @@ function extractAllInternalLinks(): Record { } function extractAllInternalLinksWithAnchors(): Record { - return shell.ls(`${BASE_PATH}/**/*.md`).reduce((acc, path) => { + return glob.sync(`${BASE_PATH}/**/*.md`).reduce((acc, path) => { const links = parseLinks(readFileContents(path)) .filter(isLinkInternal) .filter(isNotAsset) @@ -138,7 +140,7 @@ function isCategoryNode( function getDocumentMap(): DocumentTree[] { return JSON.parse( - fs.readFileSync(path.join(BASE_PATH, 'map.json'), { encoding: 'utf-8' }) + fs.readFileSync(path.join(BASE_PATH, 'map.json'), 'utf-8') ) as DocumentTree[]; } @@ -253,29 +255,27 @@ function checkInternalAnchoredLinks( } if (!erroneousInternalLinks) { - console.log(green('All internal links appear to be valid!!')); - console.log('Moving on to check internal anchors...'); + console.log(`${chalk.green('šŸ—ø')} All internal links appear to be valid!`); const erroneousAnchoredInternalLinks = checkInternalAnchoredLinks( validInternalLinksMap ); if (!erroneousAnchoredInternalLinks) { - console.log(green('All internal anchored links appear to be valid!!')); + console.log( + `${chalk.green('šŸ—ø')} All internal anchored links appear to be valid!` + ); process.exit(0); } else { - console.log( - red( - 'The following files appear to contain the following invalid anchored internal links:' - ) - ); - console.log(red(JSON.stringify(erroneousAnchoredInternalLinks, null, 2))); + console.log(`${chalk.red( + 'ERROR' + )} The following files appear to contain the following invalid anchored internal links: + ${JSON.stringify(erroneousAnchoredInternalLinks, null, 2)}`); process.exit(1); } } else { - console.log( - red( - 'The following files appear to contain the following invalid internal links:' - ) - ); - console.log(red(JSON.stringify(erroneousInternalLinks, null, 2))); + console.log(`${chalk.red( + 'ERROR' + )} The following files appear to contain the following invalid internal links: + ${JSON.stringify(erroneousInternalLinks, null, 2)}`); + process.exit(1); } diff --git a/scripts/documentation/map-link-checker.ts b/scripts/documentation/map-link-checker.ts index 2e7558c3cc..14c77a9330 100644 --- a/scripts/documentation/map-link-checker.ts +++ b/scripts/documentation/map-link-checker.ts @@ -1,12 +1,14 @@ -import { green, red } from 'chalk'; import * as fs from 'fs'; -import * as shell from 'shelljs'; +import * as glob from 'glob'; +import * as chalk from 'chalk'; + +console.log(`${chalk.blue('i')} Documentation Map Check`); const basePath = 'docs'; const sharedFilesPattern = 'shared/cli'; -const readmePathList: string[] = shell - .ls(`${basePath}/**/*.md`) +const readmePathList: string[] = glob + .sync(`${basePath}/**/*.md`) .map((path: string) => path.split(basePath)[1]) .map((path: string) => path.slice(1, -3)) // Removing first `/` and `.md` .filter((path: string) => !path.startsWith(sharedFilesPattern)); @@ -49,38 +51,44 @@ let scriptError = false; if (!!readmeMissList.length) { console.error( - red("\nāš ļø Documentation files and 'map.json' file are out of sync!\n") + chalk.red( + "\nāš ļø Documentation files and 'map.json' file are out of sync!\n" + ) ); console.log(readmeMissList.map((x) => x.concat('.md')).join('\n')); console.error( - red( + chalk.red( `\nSome documentation files exist without any reference in \'map.json\', make sure to add an entry.` ) ); scriptError = true; } else { console.log( - green("Markdown files are in sync with 'map.json', everything is good šŸ‘") + `${chalk.green('šŸ—ø')} Markdown files are in sync with ${chalk.grey( + 'docs/maps.json' + )}.` ); } if (!!mapMissList.length) { - console.error( - red( - "\nāš ļø The 'map.json' file and the documentation files are out of sync!\n" - ) + console.log( + `\n${chalk.red( + 'ERROR' + )} The 'map.json' file and the documentation files are out of sync!\n` ); console.log(mapMissList.map((x) => x.concat('.md')).join('\n')); - console.error( - red( - `\nThe \'map.json\' file is linking documenation files that do not exist.` - ) + console.log( + `\n${chalk.red( + 'ERROR' + )} The \'map.json\' file is linking documenation files that do not exist.` ); scriptError = true; } else { console.log( - green( - "The 'map.json' file and the documentation files are in sync, everything is good šŸ‘" + console.log( + `${chalk.green( + 'šŸ—ø' + )} The 'map.json' file and the documentation files are in sync.` ) ); } diff --git a/yarn.lock b/yarn.lock index 199db7135d..c2a79bb3ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3190,6 +3190,7 @@ url-loader "^4.0.0" util-deprecate "^1.0.2" webpack "^4.44.2" + webpack-dev-middleware "^3.7.0" webpack-filter-warnings-plugin "^1.2.1" webpack-hot-middleware "^2.25.0"