refactor: unify log format with new logger utility (#5994)

Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
This commit is contained in:
Joshua Chen 2021-12-21 00:24:59 +08:00 committed by GitHub
parent faef753730
commit 770418f8d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 717 additions and 650 deletions

View file

@ -122,7 +122,7 @@ module.exports = {
'array-callback-return': WARNING, 'array-callback-return': WARNING,
camelcase: WARNING, camelcase: WARNING,
'no-restricted-syntax': WARNING, 'no-restricted-syntax': WARNING,
'no-unused-expressions': WARNING, 'no-unused-expressions': [WARNING, {allowTaggedTemplates: true}],
'global-require': WARNING, 'global-require': WARNING,
'prefer-destructuring': WARNING, 'prefer-destructuring': WARNING,
yoda: WARNING, yoda: WARNING,

View file

@ -6,7 +6,9 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const chalk = require('chalk'); // @ts-check
const logger = require('@docusaurus/logger').default;
const semver = require('semver'); const semver = require('semver');
const path = require('path'); const path = require('path');
const program = require('commander'); const program = require('commander');
@ -14,19 +16,15 @@ const {default: init} = require('../lib');
const requiredVersion = require('../package.json').engines.node; const requiredVersion = require('../package.json').engines.node;
if (!semver.satisfies(process.version, requiredVersion)) { if (!semver.satisfies(process.version, requiredVersion)) {
console.log( logger.error('Minimum Node.js version not met :(');
chalk.red(`\nMinimum Node.js version not met :)`) + logger.info`You are using Node.js number=${process.version}, Requirement: Node.js number=${requiredVersion}.`;
chalk.yellow(
`\nYou are using Node.js ${process.version}, Requirement: Node.js ${requiredVersion}.\n`,
),
);
process.exit(1); process.exit(1);
} }
function wrapCommand(fn) { function wrapCommand(fn) {
return (...args) => return (...args) =>
fn(...args).catch((err) => { fn(...args).catch((err) => {
console.error(chalk.red(err.stack)); logger.error(err.stack);
process.exitCode = 1; process.exitCode = 1;
}); });
} }
@ -58,8 +56,7 @@ program
program.arguments('<command>').action((cmd) => { program.arguments('<command>').action((cmd) => {
program.outputHelp(); program.outputHelp();
console.log(` ${chalk.red(`\n Unknown command ${chalk.yellow(cmd)}.`)}`); logger.error`Unknown command code=${cmd}.`;
console.log();
}); });
program.parse(process.argv); program.parse(process.argv);

View file

@ -23,7 +23,7 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chalk": "^4.1.2", "@docusaurus/logger": "2.0.0-beta.13",
"commander": "^5.1.0", "commander": "^5.1.0",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
"lodash": "^4.17.20", "lodash": "^4.17.20",

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import fs from 'fs-extra'; import fs from 'fs-extra';
import {execSync} from 'child_process'; import {execSync} from 'child_process';
import prompts, {Choice} from 'prompts'; import prompts, {Choice} from 'prompts';
@ -131,12 +131,14 @@ export default async function init(
} }
if (!name) { if (!name) {
throw new Error(chalk.red('A website name is required.')); logger.error('A website name is required.');
process.exit(1);
} }
const dest = path.resolve(rootDir, name); const dest = path.resolve(rootDir, name);
if (fs.existsSync(dest)) { if (fs.existsSync(dest)) {
throw new Error(`Directory already exists at "${dest}"!`); logger.error`Directory already exists at path=${dest}!`;
process.exit(1);
} }
let template = reqTemplate; let template = reqTemplate;
@ -171,10 +173,10 @@ export default async function init(
if (url && isValidGitRepoUrl(url)) { if (url && isValidGitRepoUrl(url)) {
return true; return true;
} }
return chalk.red(`Invalid repository URL`); return logger.red('Invalid repository URL');
}, },
message: message: logger.interpolate`Enter a repository URL from GitHub, Bitbucket, GitLab, or any other public repo.
'Enter a repository URL from GitHub, Bitbucket, GitLab, or any other public repo.\n(e.g: https://github.com/ownerName/repoName.git)', (e.g: path=${'https://github.com/ownerName/repoName.git'})`,
}); });
template = repoPrompt.gitRepoUrl; template = repoPrompt.gitRepoUrl;
} else if (template === 'Local template') { } else if (template === 'Local template') {
@ -187,11 +189,11 @@ export default async function init(
if (fs.existsSync(fullDir)) { if (fs.existsSync(fullDir)) {
return true; return true;
} }
return chalk.red( return logger.red(
`The path ${chalk.magenta(fullDir)} does not exist.`, logger.interpolate`path=${fullDir} does not exist.`,
); );
} }
return chalk.red('Please enter a valid path.'); return logger.red('Please enter a valid path.');
}, },
message: message:
'Enter a local folder path, relative to the current working directory.', 'Enter a local folder path, relative to the current working directory.',
@ -200,37 +202,34 @@ export default async function init(
} }
if (!template) { if (!template) {
throw new Error('Template should not be empty'); logger.error('Template should not be empty');
process.exit(1);
} }
console.log(` logger.info('Creating new Docusaurus project...');
${chalk.cyan('Creating new Docusaurus project...')}
`);
if (isValidGitRepoUrl(template)) { if (isValidGitRepoUrl(template)) {
console.log(`Cloning Git template ${chalk.cyan(template)}...`); logger.info`Cloning Git template path=${template}...`;
if ( if (
shell.exec(`git clone --recursive ${template} ${dest}`, {silent: true}) shell.exec(`git clone --recursive ${template} ${dest}`, {silent: true})
.code !== 0 .code !== 0
) { ) {
throw new Error(chalk.red(`Cloning Git template ${template} failed!`)); logger.error`Cloning Git template name=${template} failed!`;
process.exit(1);
} }
} else if (templates.includes(template)) { } else if (templates.includes(template)) {
// Docusaurus templates. // Docusaurus templates.
if (useTS) { if (useTS) {
if (!hasTS(template)) { if (!hasTS(template)) {
throw new Error( logger.error`Template name=${template} doesn't provide the Typescript variant.`;
`Template ${template} doesn't provide the Typescript variant.`, process.exit(1);
);
} }
template = `${template}${TypeScriptTemplateSuffix}`; template = `${template}${TypeScriptTemplateSuffix}`;
} }
try { try {
await copyTemplate(templatesDir, template, dest); await copyTemplate(templatesDir, template, dest);
} catch (err) { } catch (err) {
console.log( logger.error`Copying Docusaurus template name=${template} failed!`;
`Copying Docusaurus template ${chalk.cyan(template)} failed!`,
);
throw err; throw err;
} }
} else if (fs.existsSync(path.resolve(process.cwd(), template))) { } else if (fs.existsSync(path.resolve(process.cwd(), template))) {
@ -238,11 +237,12 @@ ${chalk.cyan('Creating new Docusaurus project...')}
try { try {
await fs.copy(templateDir, dest); await fs.copy(templateDir, dest);
} catch (err) { } catch (err) {
console.log(`Copying local template ${templateDir} failed!`); logger.error`Copying local template path=${templateDir} failed!`;
throw err; throw err;
} }
} else { } else {
throw new Error('Invalid template.'); logger.error('Invalid template.');
process.exit(1);
} }
// Update package.json info. // Update package.json info.
@ -253,7 +253,7 @@ ${chalk.cyan('Creating new Docusaurus project...')}
private: true, private: true,
}); });
} catch (err) { } catch (err) {
console.log(chalk.red('Failed to update package.json.')); logger.error('Failed to update package.json.');
throw err; throw err;
} }
@ -275,7 +275,7 @@ ${chalk.cyan('Creating new Docusaurus project...')}
? name ? name
: path.relative(process.cwd(), name); : path.relative(process.cwd(), name);
if (!cliOptions.skipInstall) { if (!cliOptions.skipInstall) {
console.log(`Installing dependencies with ${chalk.cyan(pkgManager)}...`); logger.info`Installing dependencies with name=${pkgManager}...`;
if ( if (
shell.exec( shell.exec(
`cd "${name}" && ${useYarn ? 'yarn' : 'npm install --color always'}`, `cd "${name}" && ${useYarn ? 'yarn' : 'npm install --color always'}`,
@ -288,36 +288,35 @@ ${chalk.cyan('Creating new Docusaurus project...')}
}, },
).code !== 0 ).code !== 0
) { ) {
console.error(chalk.red('Dependency installation failed.')); logger.error('Dependency installation failed.');
console.log(`The site directory has already been created, and you can retry by typing: logger.info`The site directory has already been created, and you can retry by typing:
${chalk.cyan('cd')} ${cdpath} code=${`cd ${cdpath}`}
${chalk.cyan(`${pkgManager} install`)}`); code=${`${pkgManager} install`}`;
process.exit(0); process.exit(0);
} }
} }
console.log(` logger.success`Created path=${cdpath}.`;
Successfully created "${chalk.cyan(cdpath)}". logger.info`Inside that directory, you can run several commands:
Inside that directory, you can run several commands:
${chalk.cyan(`${pkgManager} start`)} code=${`${pkgManager} start`}
Starts the development server. Starts the development server.
${chalk.cyan(`${pkgManager} ${useYarn ? '' : 'run '}build`)} code=${`${pkgManager} ${useYarn ? '' : 'run '}build`}
Bundles your website into static files for production. Bundles your website into static files for production.
${chalk.cyan(`${pkgManager} ${useYarn ? '' : 'run '}serve`)} code=${`${pkgManager} ${useYarn ? '' : 'run '}serve`}
Serves the built website locally. Serves the built website locally.
${chalk.cyan(`${pkgManager} deploy`)} code=${`${pkgManager} deploy`}
Publishes the website to GitHub pages. Publishes the website to GitHub pages.
We recommend that you begin by typing: We recommend that you begin by typing:
${chalk.cyan('cd')} ${cdpath} code=${`cd ${cdpath}`}
${chalk.cyan(`${pkgManager} start`)} code=${`${pkgManager} start`}
Happy building awesome websites! Happy building awesome websites!
`); `;
} }

View file

@ -0,0 +1,4 @@
copyUntypedFiles.js
.tsbuildinfo
tsconfig*
__tests__

View file

@ -0,0 +1,44 @@
# `@docusaurus/logger`
An encapsulated logger for semantically formatting console messages.
## APIs
It exports a single object as default export: `logger`. `logger` has the following properties:
- Some useful colors.
- Formatters. These functions have the same signature as the formatters of `picocolors`. Note that their implementations are not guaranteed. You should only care about their semantics.
- `path`: formats a file path or URL.
- `id`: formats an identifier.
- `code`: formats a code snippet.
- `subdue`: subdues the text.
- `num`: formats a number.
- The `interpolate` function. It is a template literal tag.
- Logging functions. All logging functions can both be used as functions (in which it has the same usage as `console.log`) or template literal tags.
- `info`: prints information.
- `warn`: prints a warning that should be payed attention to.
- `error`: prints an error (not necessarily halting the program) that signals significant problems.
- `success`: prints a success message.
### Using the template literal tag
The template literal tag evaluates the template and expressions embedded. `interpolate` returns a new string, while other logging functions prints it. Below is a typical usage:
```js
logger.info`Hello name=${name}! You have number=${money} dollars. Here are the ${
items.length > 1 ? 'items' : 'item'
} on the shelf: ${items}
To buy anything, enter code=${'buy x'} where code=${'x'} is the item's name; to quit, press code=${'Ctrl + C'}.`;
```
An embedded expression is optionally preceded by a flag in the form `%[a-z]+` (a percentage sign followed by a few lowercase letters). If it's not preceded by any flag, it's printed out as-is. Otherwise, it's formatted with one of the formatters:
- `path=`: `path`
- `name=`: `id`
- `code=`: `code`
- `subdue=`: `subdue`
- `number=`: `num`
If the expression is an array, it's formatted by `` `\n- ${array.join('\n- ')}\n` `` (note it automatically gets a leading line end). Each member is formatted by itself and the bullet is not formatted. So you would see the above message printed as:
![demo](./demo.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View file

@ -0,0 +1,32 @@
{
"name": "@docusaurus/logger",
"version": "2.0.0-beta.13",
"description": "An encapsulated logger for semantically formatting console messages.",
"main": "./lib/index.js",
"repository": {
"type": "git",
"url": "https://github.com/facebook/docusaurus.git",
"directory": "packages/docusaurus-logger"
},
"bugs": {
"url": "https://github.com/facebook/docusaurus/issues"
},
"scripts": {
"build": "tsc",
"watch": "tsc --watch"
},
"publishConfig": {
"access": "public"
},
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"tslib": "^2.3.1"
},
"engines": {
"node": ">=14"
},
"devDependencies": {
"@types/supports-color": "^8.1.1"
}
}

View file

@ -0,0 +1,11 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const chalk = require('chalk');
// Force coloring the output even in CI
module.exports = new chalk.Instance({level: 3});

View file

@ -0,0 +1,73 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import logger from '../index';
describe('formatters', () => {
test('path', () => {
expect(logger.path('hey')).toMatchInlineSnapshot(`"hey"`);
});
test('id', () => {
expect(logger.name('hey')).toMatchInlineSnapshot(`"hey"`);
});
test('code', () => {
expect(logger.code('hey')).toMatchInlineSnapshot(`"\`hey\`"`);
});
test('subdue', () => {
expect(logger.subdue('hey')).toMatchInlineSnapshot(`"hey"`);
});
});
describe('interpolate', () => {
test('should format text with variables & arrays', () => {
const name = 'Josh';
const items = [1, 'hi', 'Hmmm'];
expect(logger.interpolate`Hello ${name}! Here are your goodies:${items}`)
.toMatchInlineSnapshot(`
"Hello Josh! Here are your goodies:
- 1
- hi
- Hmmm"
`);
});
test('should recognize valid flags', () => {
expect(
logger.interpolate`The package at path=${'packages/docusaurus'} has number=${10} files. name=${'Babel'} is exported here subdue=${'(as a preset)'} that you can with code=${"require.resolve('@docusaurus/core/lib/babel/preset')"}`,
).toMatchInlineSnapshot(
`"The package at packages/docusaurus has 10 files. Babel is exported here (as a preset) that you can with \`require.resolve('@docusaurus/core/lib/babel/preset')\`"`,
);
});
test('should interpolate arrays with flags', () => {
expect(
logger.interpolate`The following commands are available:code=${[
'docusaurus start',
'docusaurus build',
'docusaurus deploy',
]}`,
).toMatchInlineSnapshot(`
"The following commands are available:
- \`docusaurus start\`
- \`docusaurus build\`
- \`docusaurus deploy\`"
`);
});
test('should print detached flags as-is', () => {
expect(
logger.interpolate`You can use placeholders like code= ${'and it will'} be replaced with the succeeding arguments`,
).toMatchInlineSnapshot(
`"You can use placeholders like code= and it will be replaced with the succeeding arguments"`,
);
});
test('should throw with bad flags', () => {
expect(
() =>
logger.interpolate`I mistyped this: cde=${'this code'} and I will be damned`,
).toThrowErrorMatchingInlineSnapshot(
`"Bad Docusaurus logging message. This is likely an internal bug, please report it."`,
);
});
});

View file

@ -0,0 +1,134 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import chalk, {Chalk} from 'chalk';
type InterpolatableValue = string | number | (string | number)[];
const path = (msg: unknown): string => chalk.cyan(chalk.underline(msg));
const name = (msg: unknown): string => chalk.blue(chalk.bold(msg));
const code = (msg: unknown): string => chalk.cyan(`\`${msg}\``);
const subdue: Chalk = chalk.gray;
const num: Chalk = chalk.yellow;
function interpolate(
msgs: TemplateStringsArray,
...values: InterpolatableValue[]
): string {
let res = '';
values.forEach((value, idx) => {
const flag = msgs[idx].match(/[a-z]+=$/);
res += msgs[idx].replace(/[a-z]+=$/, '');
const format = (function () {
if (!flag) {
return (a: string | number) => a;
}
switch (flag[0]) {
case 'path=':
return path;
case 'number=':
return num;
case 'name=':
return name;
case 'subdue=':
return subdue;
case 'code=':
return code;
default:
throw new Error(
'Bad Docusaurus logging message. This is likely an internal bug, please report it.',
);
}
})();
res += Array.isArray(value)
? `\n- ${value.map((v) => format(v)).join('\n- ')}`
: format(value);
});
res += msgs.slice(-1)[0];
return res;
}
function info(msg: unknown): void;
function info(
msg: TemplateStringsArray,
...values: [InterpolatableValue, ...InterpolatableValue[]]
): void;
function info(msg: unknown, ...values: InterpolatableValue[]): void {
console.info(
`${chalk.cyan(chalk.bold('[INFO]'))} ${
values.length === 0
? msg
: interpolate(msg as TemplateStringsArray, ...values)
}`,
);
}
function warn(msg: unknown): void;
function warn(
msg: TemplateStringsArray,
...values: [InterpolatableValue, ...InterpolatableValue[]]
): void;
function warn(msg: unknown, ...values: InterpolatableValue[]): void {
console.warn(
chalk.yellow(
`${chalk.bold('[WARNING]')} ${
values.length === 0
? msg
: interpolate(msg as TemplateStringsArray, ...values)
}`,
),
);
}
function error(msg: unknown): void;
function error(
msg: TemplateStringsArray,
...values: [InterpolatableValue, ...InterpolatableValue[]]
): void;
function error(msg: unknown, ...values: InterpolatableValue[]): void {
console.error(
chalk.red(
`${chalk.bold('[ERROR]')} ${
values.length === 0
? msg
: interpolate(msg as TemplateStringsArray, ...values)
}`,
),
);
}
function success(msg: unknown): void;
function success(
msg: TemplateStringsArray,
...values: [InterpolatableValue, ...InterpolatableValue[]]
): void;
function success(msg: unknown, ...values: InterpolatableValue[]): void {
console.log(
`${chalk.green(chalk.bold('[SUCCESS]'))} ${
values.length === 0
? msg
: interpolate(msg as TemplateStringsArray, ...values)
}`,
);
}
const logger = {
red: chalk.red,
yellow: chalk.yellow,
green: chalk.green,
bold: chalk.bold,
dim: chalk.dim,
path,
name,
code,
subdue,
num,
interpolate,
info,
warn,
error,
success,
};
export default logger;

View file

@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"sourceMap": true,
"declarationMap": true,
"rootDir": "src",
"outDir": "lib"
}
}

View file

@ -20,10 +20,10 @@
"dependencies": { "dependencies": {
"@babel/parser": "^7.16.4", "@babel/parser": "^7.16.4",
"@babel/traverse": "^7.16.3", "@babel/traverse": "^7.16.3",
"@docusaurus/logger": "2.0.0-beta.13",
"@docusaurus/utils": "2.0.0-beta.13", "@docusaurus/utils": "2.0.0-beta.13",
"@mdx-js/mdx": "^1.6.21", "@mdx-js/mdx": "^1.6.21",
"@mdx-js/react": "^1.6.21", "@mdx-js/react": "^1.6.21",
"chalk": "^4.1.2",
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",

View file

@ -7,7 +7,7 @@
import {readFile} from 'fs-extra'; import {readFile} from 'fs-extra';
import mdx from '@mdx-js/mdx'; import mdx from '@mdx-js/mdx';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import emoji from 'remark-emoji'; import emoji from 'remark-emoji';
import { import {
parseFrontMatter, parseFrontMatter,
@ -164,7 +164,7 @@ ${JSON.stringify(frontMatter, null, 2)}`;
if (shouldError) { if (shouldError) {
return callback(new Error(errorMessage)); return callback(new Error(errorMessage));
} else { } else {
console.warn(chalk.yellow(errorMessage)); logger.warn(errorMessage);
} }
} }
} }

View file

@ -6,7 +6,9 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const chalk = require('chalk'); // @ts-check
const logger = require('@docusaurus/logger').default;
const semver = require('semver'); const semver = require('semver');
const cli = require('commander'); const cli = require('commander');
const path = require('path'); const path = require('path');
@ -18,18 +20,14 @@ const {migrateDocusaurusProject, migrateMDToMDX} = require('../lib');
function wrapCommand(fn) { function wrapCommand(fn) {
return (...args) => return (...args) =>
fn(...args).catch((err) => { fn(...args).catch((err) => {
console.error(chalk.red(err.stack)); logger.error(err.stack);
process.exitCode = 1; process.exitCode = 1;
}); });
} }
if (!semver.satisfies(process.version, requiredVersion)) { if (!semver.satisfies(process.version, requiredVersion)) {
console.log( logger.error('Minimum Node.js version not met :(');
chalk.red(`\nMinimum Node.js version not met :(`) + logger.info`You are using Node.js number=${process.version}, Requirement: Node.js number=${requiredVersion}.`;
chalk.yellow(
`\n\nYou are using Node ${process.version}. We require Node.js ${requiredVersion} or up!\n`,
),
);
process.exit(1); process.exit(1);
} }

View file

@ -24,8 +24,8 @@
}, },
"dependencies": { "dependencies": {
"@babel/preset-env": "^7.16.4", "@babel/preset-env": "^7.16.4",
"@docusaurus/logger": "2.0.0-beta.13",
"@mapbox/hast-util-to-jsx": "^1.0.0", "@mapbox/hast-util-to-jsx": "^1.0.0",
"chalk": "^4.1.2",
"color": "^4.0.1", "color": "^4.0.1",
"commander": "^5.1.0", "commander": "^5.1.0",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",

View file

@ -5,9 +5,9 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import * as fs from 'fs-extra'; import fs from 'fs-extra';
import importFresh from 'import-fresh'; import importFresh from 'import-fresh';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import glob from 'glob'; import glob from 'glob';
import Color from 'color'; import Color from 'color';
@ -79,7 +79,7 @@ export async function migrateDocusaurusProject(
): Promise<void> { ): Promise<void> {
function createMigrationContext(): MigrationContext { function createMigrationContext(): MigrationContext {
const v1Config = importFresh(`${siteDir}/siteConfig`) as VersionOneConfig; const v1Config = importFresh(`${siteDir}/siteConfig`) as VersionOneConfig;
console.log('Starting migration from v1 to v2...'); logger.info('Starting migration from v1 to v2...');
const partialMigrationContext = { const partialMigrationContext = {
siteDir, siteDir,
newDir, newDir,
@ -109,85 +109,68 @@ export async function migrateDocusaurusProject(
react: '^17.0.1', react: '^17.0.1',
'react-dom': '^17.0.1', 'react-dom': '^17.0.1',
}; };
let errorCount = 0;
try { try {
createClientRedirects(siteConfig, deps, config); createClientRedirects(siteConfig, deps, config);
console.log( logger.success('Created client redirect for non clean URL');
chalk.green('Successfully created client redirect for non clean URL'), } catch (e) {
); logger.error(`Failed to creating redirects: ${e}`);
} catch (errorInClientRedirect) { errorCount += 1;
console.log(
chalk.red(`Error while creating redirects: ${errorInClientRedirect}`),
);
} }
if (shouldMigratePages) { if (shouldMigratePages) {
try { try {
createPages(newDir, siteDir); createPages(newDir, siteDir);
console.log( logger.success(
chalk.green( 'Created new doc pages (check migration page for more details)',
'Successfully created pages (check migration page for more details)',
),
);
} catch (errorInMigratingPages) {
console.log(
chalk.red(
`Error occurred while creating pages: ${errorInMigratingPages}`,
),
); );
} catch (e) {
logger.error(`Failed to create new doc pages: ${e}`);
errorCount += 1;
} }
} else { } else {
try { try {
createDefaultLandingPage(newDir); createDefaultLandingPage(newDir);
console.log( logger.success(
chalk.green( 'Created landing page (check migration page for more details)',
'Successfully created landing page (check migration page for more details)',
),
);
} catch (errorInLandingPage) {
console.log(
chalk.red(
`Error occurred while creating landing page: ${errorInLandingPage}`,
),
); );
} catch (e) {
logger.error(`Failed to create landing page: ${e}`);
errorCount += 1;
} }
} }
try { try {
migrateStaticFiles(siteDir, newDir); migrateStaticFiles(siteDir, newDir);
console.log(chalk.green('Successfully migrated static folder')); logger.success('Migrated static folder');
} catch (errorInStatic) { } catch (e) {
console.log( logger.error(`Failed to copy static folder: ${e}`);
chalk.red(`Error occurred while copying static folder: ${errorInStatic}`), errorCount += 1;
);
} }
try { try {
migrateBlogFiles(siteDir, newDir, classicPreset, shouldMigrateMdFiles); migrateBlogFiles(siteDir, newDir, classicPreset, shouldMigrateMdFiles);
} catch (errorInMigratingBlogs) { } catch (e) {
console.log( logger.error(`Failed to migrate blogs: ${e}`);
chalk.red( errorCount += 1;
`Error occurred while migrating blogs: ${errorInMigratingBlogs}`,
),
);
} }
try { try {
handleVersioning(siteDir, siteConfig, newDir, config, shouldMigrateMdFiles); handleVersioning(siteDir, siteConfig, newDir, config, shouldMigrateMdFiles);
} catch (errorInVersion) { } catch (e) {
console.log( logger.error(`Failed to migrate versioned docs: ${e}`);
chalk.red( errorCount += 1;
`Error occurred while migrating versioned docs: ${errorInVersion}`,
),
);
} }
try { try {
migrateLatestDocs(siteDir, newDir, shouldMigrateMdFiles, classicPreset); migrateLatestDocs(siteDir, newDir, shouldMigrateMdFiles, classicPreset);
} catch (errorInDoc) { } catch (e) {
chalk.red(`Error occurred while migrating docs: ${errorInDoc}`); logger.error(`Failed to migrate docs: ${e}`);
errorCount += 1;
} }
try { try {
migrateLatestSidebar(siteDir, newDir, classicPreset, siteConfig); migrateLatestSidebar(siteDir, newDir, classicPreset, siteConfig);
} catch (error) { } catch (e) {
console.log(chalk.red(`Error occurred while migrating sidebar: ${error}`)); logger.error(`Failed to migrate sidebar: ${e}`);
errorCount += 1;
} }
try { try {
@ -195,26 +178,26 @@ export async function migrateDocusaurusProject(
path.join(newDir, 'docusaurus.config.js'), path.join(newDir, 'docusaurus.config.js'),
`module.exports=${JSON.stringify(config, null, 2)}`, `module.exports=${JSON.stringify(config, null, 2)}`,
); );
console.log( logger.success(
chalk.green( `Created a new config file with new navbar and footer config`,
`Successfully created a new config file with new navbar and footer config`,
),
);
} catch (error) {
console.log(
chalk.red(`Error occurred while creating config file: ${error}`),
); );
} catch (e) {
logger.error(`Failed to create config file: ${e}`);
errorCount += 1;
} }
try { try {
migratePackageFile(siteDir, deps, newDir); migratePackageFile(siteDir, deps, newDir);
} catch (error) { } catch (e) {
console.log( logger.error(
chalk.red( `Error occurred while creating package.json file for project: ${e}`,
`Error occurred while creating package.json file for project: ${error}`,
),
); );
errorCount += 1;
}
if (errorCount) {
logger.warn`Migration from v1 to v2 failed with number=${errorCount} errors: please check the log above`;
} else {
logger.success('Completed migration from v1 to v2');
} }
console.log('Completed migration from v1 to v2');
} }
export function createConfigFile({ export function createConfigFile({
@ -270,11 +253,9 @@ export function createConfigFile({
customConfigFields[key] = value; customConfigFields[key] = value;
} }
}); });
console.log( logger.info`Following Fields from path=${'siteConfig.js'} will be added to path=${'docusaurus.config.js'} in code=${'customFields'}: ${Object.keys(
`${chalk.yellow( customConfigFields,
'Following Fields from siteConfig.js will be added to docusaurus.config.js in `customFields`', )}`;
)}\n${chalk.yellow(Object.keys(customConfigFields).join('\n'))}`,
);
let v2DocsPath: string | undefined; let v2DocsPath: string | undefined;
if (siteConfig.customDocsPath) { if (siteConfig.customDocsPath) {
@ -409,12 +390,12 @@ function createPages(newDir: string, siteDir: string): void {
const content = String(fs.readFileSync(filePath)); const content = String(fs.readFileSync(filePath));
fs.writeFileSync(filePath, migratePage(content)); fs.writeFileSync(filePath, migratePage(content));
}); });
} catch (error) { } catch (e) {
console.log(chalk.red(`Unable to migrate Pages : ${error}`)); logger.error(`Unable to migrate Pages: ${e}`);
createDefaultLandingPage(newDir); createDefaultLandingPage(newDir);
} }
} else { } else {
console.log('Ignoring Pages'); logger.info('Ignoring Pages');
} }
} }
@ -452,13 +433,9 @@ function migrateBlogFiles(
fs.writeFileSync(file, sanitizedFileContent(content, migrateMDFiles)); fs.writeFileSync(file, sanitizedFileContent(content, migrateMDFiles));
}); });
classicPreset.blog.path = 'blog'; classicPreset.blog.path = 'blog';
console.log( logger.success('Migrated blogs to version 2 with change in front matter');
chalk.green(
`Successfully migrated blogs to version 2 with change in frontmatter`,
),
);
} else { } else {
console.log(chalk.yellow(`Blog not found. Skipping migration for blog`)); logger.warn('Blog not found. Skipping migration for blog');
} }
} }
@ -489,18 +466,10 @@ function handleVersioning(
versionRegex, versionRegex,
migrateMDFiles, migrateMDFiles,
); );
console.log( logger.success`Migrated version docs and sidebar. The following doc versions have been created:name=${loadedVersions}`;
chalk.green(
`Successfully migrated version docs and sidebar. The following doc versions have been created: \n${loadedVersions.join(
'\n',
)}`,
),
);
} else { } else {
console.log( logger.warn(
chalk.yellow(
'Versioned docs not found. Skipping migration for versioned docs', 'Versioned docs not found. Skipping migration for versioned docs',
),
); );
} }
} }
@ -689,9 +658,7 @@ function migrateLatestSidebar(
'sidebars.json', 'sidebars.json',
); );
} catch { } catch {
console.log( logger.warn('Sidebar not found. Skipping migration for sidebar');
chalk.yellow(`Sidebar not found. Skipping migration for sidebar`),
);
} }
if (siteConfig.colors) { if (siteConfig.colors) {
const primaryColor = Color(siteConfig.colors.primaryColor); const primaryColor = Color(siteConfig.colors.primaryColor);
@ -732,11 +699,9 @@ function migrateLatestDocs(
const content = String(fs.readFileSync(file)); const content = String(fs.readFileSync(file));
fs.writeFileSync(file, sanitizedFileContent(content, migrateMDFiles)); fs.writeFileSync(file, sanitizedFileContent(content, migrateMDFiles));
}); });
console.log(chalk.green(`Successfully migrated docs to version 2`)); logger.success('Migrated docs to version 2');
} else { } else {
console.log( logger.warn('Docs folder not found. Skipping migration for docs');
chalk.yellow(`Docs folder not found. Skipping migration for docs`),
);
} }
} }
@ -774,7 +739,7 @@ function migratePackageFile(
path.join(newDir, 'package.json'), path.join(newDir, 'package.json'),
JSON.stringify(packageFile, null, 2), JSON.stringify(packageFile, null, 2),
); );
console.log(chalk.green(`Successfully migrated package.json file`)); logger.success('Migrated package.json file');
} }
export async function migrateMDToMDX( export async function migrateMDToMDX(
@ -790,5 +755,5 @@ export async function migrateMDToMDX(
sanitizedFileContent(String(fs.readFileSync(file)), true), sanitizedFileContent(String(fs.readFileSync(file)), true),
); );
}); });
console.log(`Successfully migrated ${siteDir} to ${newDir}`); logger.success`Successfully migrated path=${siteDir} to path=${newDir}`;
} }

View file

@ -19,6 +19,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-beta.13", "@docusaurus/core": "2.0.0-beta.13",
"@docusaurus/logger": "2.0.0-beta.13",
"@docusaurus/utils": "2.0.0-beta.13", "@docusaurus/utils": "2.0.0-beta.13",
"@docusaurus/utils-common": "2.0.0-beta.13", "@docusaurus/utils-common": "2.0.0-beta.13",
"@docusaurus/utils-validation": "2.0.0-beta.13", "@docusaurus/utils-validation": "2.0.0-beta.13",

View file

@ -22,7 +22,7 @@ import {
ApplyTrailingSlashParams, ApplyTrailingSlashParams,
} from '@docusaurus/utils-common'; } from '@docusaurus/utils-common';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
export default function collectRedirects( export default function collectRedirects(
pluginContext: PluginContext, pluginContext: PluginContext,
@ -99,14 +99,10 @@ function filterUnwantedRedirects(
Object.entries(groupBy(redirects, (redirect) => redirect.from)).forEach( Object.entries(groupBy(redirects, (redirect) => redirect.from)).forEach(
([from, groupedFromRedirects]) => { ([from, groupedFromRedirects]) => {
if (groupedFromRedirects.length > 1) { if (groupedFromRedirects.length > 1) {
console.error( logger.error`name=${'@docusaurus/plugin-client-redirects'}: multiple redirects are created with the same "from" pathname: path=${from}
chalk.red( It is not possible to redirect the same pathname to multiple destinations: ${groupedFromRedirects.map(
`@docusaurus/plugin-client-redirects: multiple redirects are created with the same "from" pathname=${from} (r) => JSON.stringify(r),
It is not possible to redirect the same pathname to multiple destinations: )}`;
- ${groupedFromRedirects.map((r) => JSON.stringify(r)).join('\n- ')}
`,
),
);
} }
}, },
); );
@ -117,13 +113,9 @@ It is not possible to redirect the same pathname to multiple destinations:
(redirect) => pluginContext.relativeRoutesPaths.includes(redirect.from), (redirect) => pluginContext.relativeRoutesPaths.includes(redirect.from),
); );
if (redirectsOverridingExistingPath.length > 0) { if (redirectsOverridingExistingPath.length > 0) {
console.error( logger.error`name=${'@docusaurus/plugin-client-redirects'}: some redirects would override existing paths, and will be ignored: ${redirectsOverridingExistingPath.map(
chalk.red( (r) => JSON.stringify(r),
`@docusaurus/plugin-client-redirects: some redirects would override existing paths, and will be ignored: )}`;
- ${redirectsOverridingExistingPath.map((r) => JSON.stringify(r)).join('\n- ')}
`,
),
);
} }
return collectedRedirects.filter( return collectedRedirects.filter(
(redirect) => !pluginContext.relativeRoutesPaths.includes(redirect.from), (redirect) => !pluginContext.relativeRoutesPaths.includes(redirect.from),

View file

@ -19,10 +19,10 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-beta.13", "@docusaurus/core": "2.0.0-beta.13",
"@docusaurus/logger": "2.0.0-beta.13",
"@docusaurus/mdx-loader": "2.0.0-beta.13", "@docusaurus/mdx-loader": "2.0.0-beta.13",
"@docusaurus/utils": "2.0.0-beta.13", "@docusaurus/utils": "2.0.0-beta.13",
"@docusaurus/utils-validation": "2.0.0-beta.13", "@docusaurus/utils-validation": "2.0.0-beta.13",
"chalk": "^4.1.2",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"feed": "^4.2.2", "feed": "^4.2.2",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",

View file

@ -6,7 +6,7 @@
*/ */
import fs from 'fs-extra'; import fs from 'fs-extra';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import path from 'path'; import path from 'path';
import {Author, BlogContentPaths} from './types'; import {Author, BlogContentPaths} from './types';
import {findFolderContainingFile} from '@docusaurus/utils'; import {findFolderContainingFile} from '@docusaurus/utils';
@ -48,7 +48,7 @@ export async function readAuthorsMapFile(
return validateAuthorsMapFile(unsafeContent); return validateAuthorsMapFile(unsafeContent);
} catch (e) { } catch (e) {
// TODO replace later by error cause: see https://v8.dev/features/error-cause // TODO replace later by error cause: see https://v8.dev/features/error-cause
console.error(chalk.red('The author list file looks invalid!')); logger.error('The author list file looks invalid!');
throw e; throw e;
} }
} }
@ -88,9 +88,7 @@ export async function getAuthorsMap(
return await readAuthorsMapFile(filePath); return await readAuthorsMapFile(filePath);
} catch (e) { } catch (e) {
// TODO replace later by error cause, see https://v8.dev/features/error-cause // TODO replace later by error cause, see https://v8.dev/features/error-cause
console.error( logger.error`Couldn't read blog authors map at path=${filePath}`;
chalk.red(`Couldn't read blog authors map at path ${filePath}`),
);
throw e; throw e;
} }
} }

View file

@ -6,7 +6,6 @@
*/ */
import fs from 'fs-extra'; import fs from 'fs-extra';
import chalk from 'chalk';
import path from 'path'; import path from 'path';
import readingTime from 'reading-time'; import readingTime from 'reading-time';
import {keyBy, mapValues} from 'lodash'; import {keyBy, mapValues} from 'lodash';
@ -33,6 +32,7 @@ import {
import {LoadContext} from '@docusaurus/types'; import {LoadContext} from '@docusaurus/types';
import {validateBlogPostFrontMatter} from './blogFrontMatter'; import {validateBlogPostFrontMatter} from './blogFrontMatter';
import {AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors'; import {AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors';
import logger from '@docusaurus/logger';
export function truncate(fileString: string, truncateMarker: RegExp): string { export function truncate(fileString: string, truncateMarker: RegExp): string {
return fileString.split(truncateMarker, 1).shift()!; return fileString.split(truncateMarker, 1).shift()!;
@ -151,11 +151,7 @@ async function processBlogSourceFile(
} }
if (frontMatter.id) { if (frontMatter.id) {
console.warn( logger.warn`name=${'id'} header option is deprecated in path=${blogSourceRelative} file. Please use name=${'slug'} option instead.`;
chalk.yellow(
`"id" header option is deprecated in ${blogSourceRelative} file. Please use "slug" option instead.`,
),
);
} }
const parsedBlogFileName = parseBlogFileName(blogSourceRelative); const parsedBlogFileName = parseBlogFileName(blogSourceRelative);
@ -276,11 +272,7 @@ export async function generateBlogPosts(
authorsMap, authorsMap,
); );
} catch (e) { } catch (e) {
console.error( logger.error`Processing of blog source file failed for path path=${blogSourceFile}.`;
chalk.red(
`Processing of blog source file failed for path "${blogSourceFile}"`,
),
);
throw e; throw e;
} }
}), }),

View file

@ -19,10 +19,10 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-beta.13", "@docusaurus/core": "2.0.0-beta.13",
"@docusaurus/logger": "2.0.0-beta.13",
"@docusaurus/mdx-loader": "2.0.0-beta.13", "@docusaurus/mdx-loader": "2.0.0-beta.13",
"@docusaurus/utils": "2.0.0-beta.13", "@docusaurus/utils": "2.0.0-beta.13",
"@docusaurus/utils-validation": "2.0.0-beta.13", "@docusaurus/utils-validation": "2.0.0-beta.13",
"chalk": "^4.1.2",
"combine-promises": "^1.1.0", "combine-promises": "^1.1.0",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",

View file

@ -221,7 +221,11 @@ describe('docsVersion', () => {
getVersionsFilePath(simpleSiteDir, DEFAULT_PLUGIN_ID), getVersionsFilePath(simpleSiteDir, DEFAULT_PLUGIN_ID),
); );
expect(versions).toEqual(['1.0.0']); expect(versions).toEqual(['1.0.0']);
expect(consoleMock).toHaveBeenCalledWith('[docs]: version 1.0.0 created!'); expect(consoleMock).toHaveBeenCalledWith(
expect.stringMatching(
/.*\[SUCCESS\].* .*\[docs\].*: version .*1\.0\.0.* created!.*/,
),
);
copyMock.mockRestore(); copyMock.mockRestore();
writeMock.mockRestore(); writeMock.mockRestore();
@ -274,7 +278,11 @@ describe('docsVersion', () => {
getVersionsFilePath(versionedSiteDir, DEFAULT_PLUGIN_ID), getVersionsFilePath(versionedSiteDir, DEFAULT_PLUGIN_ID),
); );
expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0', 'withSlugs']); expect(versions).toEqual(['2.0.0', '1.0.1', '1.0.0', 'withSlugs']);
expect(consoleMock).toHaveBeenCalledWith('[docs]: version 2.0.0 created!'); expect(consoleMock).toHaveBeenCalledWith(
expect.stringMatching(
/.*\[SUCCESS\].* .*\[docs\].*: version .*2\.0\.0.* created!.*/,
),
);
copyMock.mockRestore(); copyMock.mockRestore();
writeMock.mockRestore(); writeMock.mockRestore();
@ -326,7 +334,9 @@ describe('docsVersion', () => {
); );
expect(versions).toEqual(['2.0.0', '1.0.0']); expect(versions).toEqual(['2.0.0', '1.0.0']);
expect(consoleMock).toHaveBeenCalledWith( expect(consoleMock).toHaveBeenCalledWith(
'[community]: version 2.0.0 created!', expect.stringMatching(
/.*\[SUCCESS\].* .*\[community\].*: version .*2.0.0.* created!.*/,
),
); );
copyMock.mockRestore(); copyMock.mockRestore();

View file

@ -29,8 +29,7 @@ describe('lastUpdate', () => {
}); });
test('non-existing file', async () => { test('non-existing file', async () => {
const consoleMock = jest.spyOn(console, 'error'); const consoleMock = jest.spyOn(console, 'error').mockImplementation();
consoleMock.mockImplementation();
const nonExistingFileName = '.nonExisting'; const nonExistingFileName = '.nonExisting';
const nonExistingFilePath = path.join( const nonExistingFilePath = path.join(
__dirname, __dirname,
@ -39,8 +38,8 @@ describe('lastUpdate', () => {
); );
expect(await getFileLastUpdate(nonExistingFilePath)).toBeNull(); expect(await getFileLastUpdate(nonExistingFilePath)).toBeNull();
expect(consoleMock).toHaveBeenCalledTimes(1); expect(consoleMock).toHaveBeenCalledTimes(1);
expect(consoleMock.mock.calls[0][0].message).toContain( expect(consoleMock).toHaveBeenLastCalledWith(
' with exit code 128', expect.stringMatching(/with exit code 128/),
); );
expect(await getFileLastUpdate(null)).toBeNull(); expect(await getFileLastUpdate(null)).toBeNull();
expect(await getFileLastUpdate(undefined)).toBeNull(); expect(await getFileLastUpdate(undefined)).toBeNull();
@ -60,7 +59,9 @@ describe('lastUpdate', () => {
const lastUpdateData = await getFileLastUpdate(existingFilePath); const lastUpdateData = await getFileLastUpdate(existingFilePath);
expect(lastUpdateData).toBeNull(); expect(lastUpdateData).toBeNull();
expect(consoleMock).toHaveBeenLastCalledWith( expect(consoleMock).toHaveBeenLastCalledWith(
'Sorry, the docs plugin last update options require Git.', expect.stringMatching(
/.*\[WARNING\].* Sorry, the docs plugin last update options require Git\..*/,
),
); );
consoleMock.mockRestore(); consoleMock.mockRestore();

View file

@ -15,6 +15,7 @@ import path from 'path';
import type {PathOptions, SidebarOptions} from './types'; import type {PathOptions, SidebarOptions} from './types';
import {loadSidebarsFile, resolveSidebarPathOption} from './sidebars'; import {loadSidebarsFile, resolveSidebarPathOption} from './sidebars';
import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils'; import {DEFAULT_PLUGIN_ID} from '@docusaurus/utils';
import logger from '@docusaurus/logger';
function createVersionedSidebarFile({ function createVersionedSidebarFile({
siteDir, siteDir,
@ -133,5 +134,5 @@ export function cliDocsVersionCommand(
fs.ensureDirSync(path.dirname(versionsJSONFile)); fs.ensureDirSync(path.dirname(versionsJSONFile));
fs.writeFileSync(versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`); fs.writeFileSync(versionsJSONFile, `${JSON.stringify(versions, null, 2)}\n`);
console.log(`${pluginIdLogPrefix}: version ${version} created!`); logger.success`name=${pluginIdLogPrefix}: version name=${version} created!`;
} }

View file

@ -7,7 +7,7 @@
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import {keyBy, last} from 'lodash'; import {keyBy, last} from 'lodash';
import { import {
aliasedSitePath, aliasedSitePath,
@ -274,11 +274,7 @@ export function processDocMetadata(args: {
try { try {
return doProcessDocMetadata(args); return doProcessDocMetadata(args);
} catch (e) { } catch (e) {
console.error( logger.error`Can't process doc metadata for doc at path path=${args.docFile.filePath} in version name=${args.versionMetadata.versionName}`;
chalk.red(
`Can't process doc metadata for doc at path "${args.docFile.filePath}" in version "${args.versionMetadata.versionName}"`,
),
);
throw e; throw e;
} }
} }

View file

@ -51,7 +51,7 @@ import {
translateLoadedContent, translateLoadedContent,
getLoadedContentTranslationFiles, getLoadedContentTranslationFiles,
} from './translations'; } from './translations';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import {getVersionTags} from './tags'; import {getVersionTags} from './tags';
import {createVersionRoutes} from './routes'; import {createVersionRoutes} from './routes';
import type {PropTagsListPage} from '@docusaurus/plugin-content-docs'; import type {PropTagsListPage} from '@docusaurus/plugin-content-docs';
@ -203,11 +203,7 @@ export default function pluginContentDocs(
try { try {
return await doLoadVersion(versionMetadata); return await doLoadVersion(versionMetadata);
} catch (e) { } catch (e) {
console.error( logger.error`Loading of version failed for version name=${versionMetadata.versionName}`;
chalk.red(
`Loading of version failed for version "${versionMetadata.versionName}"`,
),
);
throw e; throw e;
} }
} }

View file

@ -6,6 +6,7 @@
*/ */
import shell from 'shelljs'; import shell from 'shelljs';
import logger from '@docusaurus/logger';
type FileLastUpdateData = {timestamp?: number; author?: string}; type FileLastUpdateData = {timestamp?: number; author?: string};
@ -36,7 +37,7 @@ export async function getFileLastUpdate(
if (!shell.which('git')) { if (!shell.which('git')) {
if (!showedGitRequirementError) { if (!showedGitRequirementError) {
showedGitRequirementError = true; showedGitRequirementError = true;
console.warn('Sorry, the docs plugin last update options require Git.'); logger.warn('Sorry, the docs plugin last update options require Git.');
} }
return null; return null;
@ -51,8 +52,8 @@ export async function getFileLastUpdate(
); );
} }
return getTimestampAndAuthor(result.stdout.trim()); return getTimestampAndAuthor(result.stdout.trim());
} catch (error) { } catch (e) {
console.error(error); logger.error(e);
} }
return null; return null;

View file

@ -19,7 +19,7 @@ import type {
OptionValidationContext, OptionValidationContext,
ValidationResult, ValidationResult,
} from '@docusaurus/types'; } from '@docusaurus/types';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import admonitions from 'remark-admonitions'; import admonitions from 'remark-admonitions';
import {DefaultSidebarItemsGenerator} from './sidebars/generator'; import {DefaultSidebarItemsGenerator} from './sidebars/generator';
import { import {
@ -157,11 +157,7 @@ export function validateOptions({
}; };
} }
if (options.sidebarCollapsed) { if (options.sidebarCollapsed) {
console.warn( logger.warn`The docs plugin config is inconsistent. It does not make sense to use code=${'sidebarCollapsible: false'} and code=${'sidebarCollapsed: true'} at the same time. code=${'sidebarCollapsed: true'} will be ignored.`;
chalk.yellow(
'The docs plugin config is inconsistent. It does not make sense to use sidebarCollapsible=false and sidebarCollapsed=true at the same time. sidebarCollapsed=false will be ignored.',
),
);
options = { options = {
...options, ...options,
sidebarCollapsed: false, sidebarCollapsed: false,

View file

@ -14,7 +14,7 @@ import {
} from './types'; } from './types';
import type {PropCategoryGeneratedIndex} from '@docusaurus/plugin-content-docs'; import type {PropCategoryGeneratedIndex} from '@docusaurus/plugin-content-docs';
import {toVersionMetadataProp} from './props'; import {toVersionMetadataProp} from './props';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
export async function createCategoryGeneratedIndexRoutes({ export async function createCategoryGeneratedIndexRoutes({
version, version,
@ -163,11 +163,7 @@ export async function createVersionRoutes({
try { try {
return await doCreateVersionRoutes(loadedVersion); return await doCreateVersionRoutes(loadedVersion);
} catch (e) { } catch (e) {
console.error( logger.error`Can't create version routes for version name=${loadedVersion.versionName}`;
chalk.red(
`Can't create version routes for version "${loadedVersion.versionName}"`,
),
);
throw e; throw e;
} }
} }

View file

@ -57,7 +57,7 @@ describe('DefaultSidebarItemsGenerator', () => {
expect(sidebarSlice).toEqual([]); expect(sidebarSlice).toEqual([]);
expect(consoleWarn).toHaveBeenCalledWith( expect(consoleWarn).toHaveBeenCalledWith(
expect.stringMatching( expect.stringMatching(
/No docs found in dir .: can't auto-generate a sidebar/, /.*\[WARNING\].* No docs found in .*\..*: can't auto-generate a sidebar\..*/,
), ),
); );
}); });

View file

@ -16,7 +16,7 @@ import type {
} from './types'; } from './types';
import {sortBy, last} from 'lodash'; import {sortBy, last} from 'lodash';
import {addTrailingSlash, posixPath} from '@docusaurus/utils'; import {addTrailingSlash, posixPath} from '@docusaurus/utils';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import Yaml from 'js-yaml'; import Yaml from 'js-yaml';
@ -72,11 +72,7 @@ async function readCategoryMetadataFile(
try { try {
return validateCategoryMetadataFile(unsafeContent); return validateCategoryMetadataFile(unsafeContent);
} catch (e) { } catch (e) {
console.error( logger.error`The docs sidebar category metadata file path=${filePath} looks invalid!`;
chalk.red(
`The docs sidebar category metadata file looks invalid!\nPath: ${filePath}`,
),
);
throw e; throw e;
} }
} }
@ -134,11 +130,7 @@ export const DefaultSidebarItemsGenerator: SidebarItemsGenerator = async ({
const docs = allDocs.filter(isInAutogeneratedDir); const docs = allDocs.filter(isInAutogeneratedDir);
if (docs.length === 0) { if (docs.length === 0) {
console.warn( logger.warn`No docs found in path=${autogenDir}: can't auto-generate a sidebar.`;
chalk.yellow(
`No docs found in dir ${autogenDir}: can't auto-generate a sidebar.`,
),
);
} }
return docs; return docs;
} }

View file

@ -33,7 +33,6 @@
"@docusaurus/utils-validation": "2.0.0-beta.13", "@docusaurus/utils-validation": "2.0.0-beta.13",
"@mdx-js/mdx": "^1.6.21", "@mdx-js/mdx": "^1.6.21",
"@mdx-js/react": "^1.6.21", "@mdx-js/react": "^1.6.21",
"chalk": "^4.1.2",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"copy-text-to-clipboard": "^3.0.1", "copy-text-to-clipboard": "^3.0.1",
"globby": "^11.0.2", "globby": "^11.0.2",

View file

@ -22,6 +22,7 @@
"dependencies": { "dependencies": {
"@docsearch/react": "^3.0.0-alpha.39", "@docsearch/react": "^3.0.0-alpha.39",
"@docusaurus/core": "2.0.0-beta.13", "@docusaurus/core": "2.0.0-beta.13",
"@docusaurus/logger": "2.0.0-beta.13",
"@docusaurus/theme-common": "2.0.0-beta.13", "@docusaurus/theme-common": "2.0.0-beta.13",
"@docusaurus/theme-translations": "2.0.0-beta.13", "@docusaurus/theme-translations": "2.0.0-beta.13",
"@docusaurus/utils": "2.0.0-beta.13", "@docusaurus/utils": "2.0.0-beta.13",

View file

@ -10,6 +10,7 @@ import fs from 'fs';
import {defaultConfig, compile} from 'eta'; import {defaultConfig, compile} from 'eta';
import {normalizeUrl, getSwizzledComponent} from '@docusaurus/utils'; import {normalizeUrl, getSwizzledComponent} from '@docusaurus/utils';
import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations'; import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations';
import logger from '@docusaurus/logger';
import openSearchTemplate from './templates/opensearch'; import openSearchTemplate from './templates/opensearch';
import {memoize} from 'lodash'; import {memoize} from 'lodash';
@ -83,9 +84,9 @@ export default function theme(
favicon: favicon ? normalizeUrl([url, baseUrl, favicon]) : null, favicon: favicon ? normalizeUrl([url, baseUrl, favicon]) : null,
}), }),
); );
} catch (err) { } catch (e) {
console.error(err); logger.error('Generating OpenSearch file failed.');
throw new Error(`Generating OpenSearch file failed: ${err}`); throw e;
} }
}, },

View file

@ -23,7 +23,8 @@
"tslib": "^2.3.1" "tslib": "^2.3.1"
}, },
"devDependencies": { "devDependencies": {
"chalk": "^4.1.2", "@docusaurus/core": "2.0.0-beta.13",
"@docusaurus/logger": "2.0.0-beta.13",
"lodash": "^4.17.20" "lodash": "^4.17.20"
}, },
"engines": { "engines": {

View file

@ -5,9 +5,10 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
// @ts-check
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
const chalk = require('chalk'); const logger = require('@docusaurus/logger').default;
const path = require('path'); const path = require('path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const {mapValues, pickBy, difference, orderBy} = require('lodash'); const {mapValues, pickBy, difference, orderBy} = require('lodash');
@ -69,17 +70,10 @@ function sortObjectKeys(obj) {
}, {}); }, {});
} }
function logSection(title) { /**
console.log(``); * @param {string[]} targetDirs
console.log(``); * @returns {Promise<import('@docusaurus/types').TranslationFileContent>}
console.log(`##############################`); */
console.log(`## ${chalk.blue(title)}`);
}
function logKeys(keys) {
return `Keys:\n- ${keys.join('\n- ')}`;
}
async function extractThemeCodeMessages(targetDirs = AllThemesSrcDirs) { async function extractThemeCodeMessages(targetDirs = AllThemesSrcDirs) {
// Unsafe import, should we create a package for the translationsExtractor ? // Unsafe import, should we create a package for the translationsExtractor ?
const { const {
@ -122,7 +116,7 @@ ${warning}
} }
async function readMessagesFile(filePath) { async function readMessagesFile(filePath) {
return JSON.parse(await fs.readFile(filePath)); return JSON.parse((await fs.readFile(filePath)).toString());
} }
async function writeMessagesFile(filePath, messages) { async function writeMessagesFile(filePath, messages) {
@ -130,11 +124,11 @@ async function writeMessagesFile(filePath, messages) {
const content = `${JSON.stringify(sortedMessages, null, 2)}\n`; // \n makes prettier happy const content = `${JSON.stringify(sortedMessages, null, 2)}\n`; // \n makes prettier happy
await fs.outputFile(filePath, content); await fs.outputFile(filePath, content);
console.log( logger.info`path=${path.basename(
`${path.basename(filePath)} updated (${ filePath,
)} updated subdue=${logger.interpolate`(number=${
Object.keys(sortedMessages).length Object.keys(sortedMessages).length
} messages)`, } messages)`}\n`;
);
} }
async function getCodeTranslationFiles(themeName) { async function getCodeTranslationFiles(themeName) {
@ -166,11 +160,8 @@ async function updateBaseFile(baseFile, targetDirs) {
); );
if (unknownMessages.length) { if (unknownMessages.length) {
console.log( logger.error`Some messages exist in base locale but were not found by the code extractor!
chalk.red(`Some messages exist in base locale but were not found by the code extractor! They won't be removed automatically, so do the cleanup manually if necessary! code=${unknownMessages}`;
They won't be removed automatically, so do the cleanup manually if necessary!
${logKeys(unknownMessages)}`),
);
} }
const newBaseMessages = { const newBaseMessages = {
@ -210,11 +201,8 @@ async function updateLocaleCodeTranslations(localeFile, baseFileMessages) {
); );
if (unknownMessages.length) { if (unknownMessages.length) {
console.log( logger.error`Some localized messages do not exist in base.json!
chalk.red(`Some localized messages do not exist in base.json! You may want to delete these! code=${unknownMessages}`;
You may want to delete these!
${logKeys(unknownMessages)}`),
);
} }
const newLocaleFileMessages = { const newLocaleFileMessages = {
@ -227,10 +215,7 @@ ${logKeys(unknownMessages)}`),
.map(([key]) => key); .map(([key]) => key);
if (untranslatedKeys.length) { if (untranslatedKeys.length) {
console.warn( logger.warn`Some messages do not seem to be translated! code=${untranslatedKeys}`;
chalk.yellow(`Some messages do not seem to be translated!
${logKeys(untranslatedKeys)}`),
);
} }
await writeMessagesFile(localeFile, newLocaleFileMessages); await writeMessagesFile(localeFile, newLocaleFileMessages);
@ -241,7 +226,7 @@ async function updateCodeTranslations() {
// eslint-disable-next-line no-restricted-syntax // eslint-disable-next-line no-restricted-syntax
for (const theme of Themes) { for (const theme of Themes) {
const {baseFile, localesFiles} = await getCodeTranslationFiles(theme.name); const {baseFile, localesFiles} = await getCodeTranslationFiles(theme.name);
logSection(`Will update base file for ${theme.name}`); logger.info`Will update base file for name=${theme.name}\n`;
const baseFileMessages = await updateBaseFile(baseFile, theme.src); const baseFileMessages = await updateBaseFile(baseFile, theme.src);
const [, newLocale] = process.argv; const [, newLocale] = process.argv;
@ -250,26 +235,23 @@ async function updateCodeTranslations() {
if (!fs.existsSync(newLocalePath)) { if (!fs.existsSync(newLocalePath)) {
await writeMessagesFile(newLocalePath, baseFileMessages); await writeMessagesFile(newLocalePath, baseFileMessages);
console.error( logger.success`Locale file path=${path.basename(
chalk.green( newLocalePath,
`Locale file ${path.basename(newLocalePath)} have been created.`, )} have been created.`;
),
);
} else { } else {
console.error( logger.warn`Locale file path=${path.basename(
chalk.red( newLocalePath,
`Locale file ${path.basename(newLocalePath)} was already created!`, )} was already created!`;
),
);
} }
} else { } else {
// eslint-disable-next-line no-restricted-syntax // eslint-disable-next-line no-restricted-syntax
for (const localeFile of localesFiles) { for (const localeFile of localesFiles) {
logSection( logger.info`Will update name=${path.basename(
`Will update ${path.basename(
path.dirname(localeFile), path.dirname(localeFile),
)} locale in ${path.basename(localeFile, path.extname(localeFile))}`, )} locale in name=${path.basename(
); localeFile,
path.extname(localeFile),
)}`;
await updateLocaleCodeTranslations(localeFile, baseFileMessages); await updateLocaleCodeTranslations(localeFile, baseFileMessages);
} }
@ -280,16 +262,12 @@ async function updateCodeTranslations() {
function run() { function run() {
updateCodeTranslations().then( updateCodeTranslations().then(
() => { () => {
console.log(''); logger.success('updateCodeTranslations end\n');
console.log(chalk.green('updateCodeTranslations end'));
console.log('');
}, },
(e) => { (e) => {
console.log(''); logger.error(
console.error(chalk.red(`updateCodeTranslations failure: ${e.message}`)); `\nupdateCodeTranslations failure: ${e.message}\n${e.stack}\n`,
console.log(''); );
console.error(e.stack);
console.log('');
process.exit(1); process.exit(1);
}, },
); );

View file

@ -18,8 +18,8 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/logger": "2.0.0-beta.13",
"@docusaurus/utils": "2.0.0-beta.13", "@docusaurus/utils": "2.0.0-beta.13",
"chalk": "^4.1.2",
"joi": "^17.4.2", "joi": "^17.4.2",
"tslib": "^2.3.1" "tslib": "^2.3.1"
}, },

View file

@ -6,7 +6,7 @@
*/ */
import Joi from './Joi'; import Joi from './Joi';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import {PluginIdSchema} from './validationSchemas'; import {PluginIdSchema} from './validationSchemas';
// TODO temporary escape hatch for alpha-60: to be removed soon // TODO temporary escape hatch for alpha-60: to be removed soon
@ -19,21 +19,14 @@ export const isValidationDisabledEscapeHatch =
process.env.DISABLE_DOCUSAURUS_VALIDATION === 'true'; process.env.DISABLE_DOCUSAURUS_VALIDATION === 'true';
if (isValidationDisabledEscapeHatch) { if (isValidationDisabledEscapeHatch) {
console.error( logger.error`You should avoid using code=${'DISABLE_DOCUSAURUS_VALIDATION'} escape hatch, this will be removed.`;
chalk.red(
'You should avoid using DISABLE_DOCUSAURUS_VALIDATION escape hatch, this will be removed.',
),
);
} }
export const logValidationBugReportHint = (): void => { export const logValidationBugReportHint = (): void => {
console.log( logger.error('A validation error occurred.');
`\n${chalk.red('A validation error occurred.')}${chalk.cyanBright( logger.info(`The validation system was added recently to Docusaurus as an attempt to avoid user configuration errors.
'\nThe validation system was added recently to Docusaurus as an attempt to avoid user configuration errors.' + We may have made some mistakes.
'\nWe may have made some mistakes.' + If you think your configuration is valid and should keep working, please open a bug report.`);
'\nIf you think your configuration is valid and should keep working, please open a bug report.',
)}\n`,
);
}; };
export function printWarning(warning?: Joi.ValidationError): void { export function printWarning(warning?: Joi.ValidationError): void {
@ -41,7 +34,7 @@ export function printWarning(warning?: Joi.ValidationError): void {
const warningMessages = warning.details const warningMessages = warning.details
.map(({message}) => message) .map(({message}) => message)
.join('\n'); .join('\n');
console.log(chalk.yellow(warningMessages)); logger.warn(warningMessages);
} }
} }
@ -63,7 +56,7 @@ export function normalizePluginOptions<T extends {id?: string}>(
if (error) { if (error) {
logValidationBugReportHint(); logValidationBugReportHint();
if (isValidationDisabledEscapeHatch) { if (isValidationDisabledEscapeHatch) {
console.error(error); logger.error(error);
return options as T; return options as T;
} else { } else {
throw error; throw error;
@ -91,7 +84,7 @@ export function normalizeThemeConfig<T>(
if (error) { if (error) {
logValidationBugReportHint(); logValidationBugReportHint();
if (isValidationDisabledEscapeHatch) { if (isValidationDisabledEscapeHatch) {
console.error(error); logger.error(error);
return themeConfig as T; return themeConfig as T;
} else { } else {
throw error; throw error;
@ -116,19 +109,14 @@ export function validateFrontMatter<T>(
const frontMatterString = JSON.stringify(frontMatter, null, 2); const frontMatterString = JSON.stringify(frontMatter, null, 2);
const errorDetails = error.details; const errorDetails = error.details;
const invalidFields = errorDetails.map(({path}) => path).join(', '); const invalidFields = errorDetails.map(({path}) => path).join(', ');
const errorMessages = errorDetails
.map(({message}) => ` - ${message}`)
.join('\n');
logValidationBugReportHint(); logValidationBugReportHint();
console.error( logger.error`The following frontmatter:
chalk.red( ${logger.yellow(frontMatterString)}
`The following frontmatter:\n${chalk.yellow( contains invalid values for field(s): ${logger.yellow(invalidFields)}.
frontMatterString, ${errorDetails.map(({message}) => message)}
)}\ncontains invalid values for field(s): ${invalidFields}.\n${errorMessages}\n`, `;
),
);
throw error; throw error;
} }

View file

@ -18,9 +18,9 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/logger": "2.0.0-beta.13",
"@mdx-js/runtime": "^1.6.22", "@mdx-js/runtime": "^1.6.22",
"@svgr/webpack": "^6.0.0", "@svgr/webpack": "^6.0.0",
"chalk": "^4.1.2",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
@ -44,7 +44,8 @@
"@types/github-slugger": "^1.3.0", "@types/github-slugger": "^1.3.0",
"@types/micromatch": "^4.0.2", "@types/micromatch": "^4.0.2",
"@types/react-dom": "^17.0.1", "@types/react-dom": "^17.0.1",
"dedent": "^0.7.0" "dedent": "^0.7.0",
"tslib": "^2.3.1"
}, },
"peerDependencies": { "peerDependencies": {
"react": "*", "react": "*",

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import path from 'path'; import path from 'path';
import {createHash} from 'crypto'; import {createHash} from 'crypto';
import {camelCase, mapValues} from 'lodash'; import {camelCase, mapValues} from 'lodash';
@ -369,13 +369,13 @@ export function reportMessage(
case 'ignore': case 'ignore':
break; break;
case 'log': case 'log':
console.log(chalk.bold.blue('info ') + chalk.blue(message)); logger.info(message);
break; break;
case 'warn': case 'warn':
console.warn(chalk.bold.yellow('warn ') + chalk.yellow(message)); logger.warn(message);
break; break;
case 'error': case 'error':
console.error(chalk.bold.red('error ') + chalk.red(message)); logger.error(message);
break; break;
case 'throw': case 'throw':
throw new Error(message); throw new Error(message);

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import fs from 'fs-extra'; import fs from 'fs-extra';
import matter from 'gray-matter'; import matter from 'gray-matter';
@ -166,10 +166,8 @@ export function parseMarkdownString(
excerpt, excerpt,
}; };
} catch (e) { } catch (e) {
console.error( logger.error(`Error while parsing Markdown frontmatter.
chalk.red(`Error while parsing Markdown frontmatter. This can happen if you use special characters in frontmatter values (try using double quotes around that value).`);
This can happen if you use special characters in frontmatter values (try using double quotes around that value).`),
);
throw e; throw e;
} }
} }

View file

@ -5,7 +5,9 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const chalk = require('chalk'); // @ts-check
const logger = require('@docusaurus/logger').default;
const fs = require('fs-extra'); const fs = require('fs-extra');
const semver = require('semver'); const semver = require('semver');
const path = require('path'); const path = require('path');
@ -53,7 +55,7 @@ try {
} }
} catch (e) { } catch (e) {
// Do not stop cli if this fails, see https://github.com/facebook/docusaurus/issues/5400 // Do not stop cli if this fails, see https://github.com/facebook/docusaurus/issues/5400
console.error(e); logger.error(e);
} }
// We don't want to display update message for canary releases // We don't want to display update message for canary releases
@ -74,6 +76,7 @@ if (
notifier.config.set('update', notifier.update); notifier.config.set('update', notifier.update);
if (ignoreUpdate(notifier.update)) { if (ignoreUpdate(notifier.update)) {
// @ts-expect-error: it works
return; return;
} }
@ -91,6 +94,7 @@ if (
? `yarn upgrade ${siteDocusaurusPackagesForUpdate}` ? `yarn upgrade ${siteDocusaurusPackagesForUpdate}`
: `npm i ${siteDocusaurusPackagesForUpdate}`; : `npm i ${siteDocusaurusPackagesForUpdate}`;
/** @type {import('boxen').Options} */
const boxenOptions = { const boxenOptions = {
padding: 1, padding: 1,
margin: 1, margin: 1,
@ -100,13 +104,12 @@ if (
}; };
const docusaurusUpdateMessage = boxen( const docusaurusUpdateMessage = boxen(
`Update available ${chalk.dim(`${notifier.update.current}`)}${chalk.reset( `Update available ${logger.dim(
' → ', `${notifier.update.current}`,
)}${chalk.green( )} ${logger.green(`${notifier.update.latest}`)}
`${notifier.update.latest}`,
)}\n\nTo upgrade Docusaurus packages with the latest version, run the following command:\n${chalk.cyan( To upgrade Docusaurus packages with the latest version, run the following command:
`${upgradeCommand}`, ${logger.code(upgradeCommand)}`,
)}`,
boxenOptions, boxenOptions,
); );
@ -115,11 +118,7 @@ if (
// notify user if node version needs to be updated // notify user if node version needs to be updated
if (!semver.satisfies(process.version, requiredVersion)) { if (!semver.satisfies(process.version, requiredVersion)) {
console.log( logger.error('Minimum Node.js version not met :(');
chalk.red(`\nMinimum Node version not met :(`) + logger.info`You are using Node.js number=${process.version}, Requirement: Node.js number=${requiredVersion}.`;
chalk.yellow(
`\n\nYou are using Node ${process.version}. We require Node ${requiredVersion} or up!\n`,
),
);
process.exit(1); process.exit(1);
} }

View file

@ -6,7 +6,9 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const chalk = require('chalk'); // @ts-check
const logger = require('@docusaurus/logger').default;
const fs = require('fs'); const fs = require('fs');
const cli = require('commander'); const cli = require('commander');
const { const {
@ -219,8 +221,7 @@ cli
cli.arguments('<command>').action((cmd) => { cli.arguments('<command>').action((cmd) => {
cli.outputHelp(); cli.outputHelp();
console.log(` ${chalk.red(`\n Unknown command ${chalk.yellow(cmd)}.`)}.`); logger.error` Unknown command name=${cmd}.`;
console.log();
}); });
function isInternalCommand(command) { function isInternalCommand(command) {
@ -238,6 +239,7 @@ function isInternalCommand(command) {
async function run() { async function run() {
if (!isInternalCommand(process.argv.slice(2)[0])) { if (!isInternalCommand(process.argv.slice(2)[0])) {
// @ts-expect-error: Hmmm
await externalCommand(cli, resolveDir('.')); await externalCommand(cli, resolveDir('.'));
} }
@ -251,6 +253,6 @@ async function run() {
run(); run();
process.on('unhandledRejection', (err) => { process.on('unhandledRejection', (err) => {
console.error(chalk.red(err.stack)); logger.error(err.stack);
process.exit(1); process.exit(1);
}); });

View file

@ -42,6 +42,7 @@
"@babel/runtime-corejs3": "^7.16.3", "@babel/runtime-corejs3": "^7.16.3",
"@babel/traverse": "^7.16.3", "@babel/traverse": "^7.16.3",
"@docusaurus/cssnano-preset": "2.0.0-beta.13", "@docusaurus/cssnano-preset": "2.0.0-beta.13",
"@docusaurus/logger": "2.0.0-beta.13",
"@docusaurus/mdx-loader": "2.0.0-beta.13", "@docusaurus/mdx-loader": "2.0.0-beta.13",
"@docusaurus/react-loadable": "5.5.2", "@docusaurus/react-loadable": "5.5.2",
"@docusaurus/utils": "2.0.0-beta.13", "@docusaurus/utils": "2.0.0-beta.13",
@ -53,7 +54,6 @@
"babel-loader": "^8.2.2", "babel-loader": "^8.2.2",
"babel-plugin-dynamic-import-node": "2.3.0", "babel-plugin-dynamic-import-node": "2.3.0",
"boxen": "^5.0.1", "boxen": "^5.0.1",
"chalk": "^4.1.2",
"chokidar": "^3.5.2", "chokidar": "^3.5.2",
"clean-css": "^5.1.5", "clean-css": "^5.1.5",
"commander": "^5.1.0", "commander": "^5.1.0",

View file

@ -13,7 +13,7 @@
import {execSync} from 'child_process'; import {execSync} from 'child_process';
import detect from 'detect-port'; import detect from 'detect-port';
import isRoot from 'is-root'; import isRoot from 'is-root';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import prompts from 'prompts'; import prompts from 'prompts';
const isInteractive = process.stdout.isTTY; const isInteractive = process.stdout.isTTY;
@ -68,12 +68,7 @@ function getProcessForPort(port: number): string | null {
const processId = getProcessIdOnPort(port); const processId = getProcessIdOnPort(port);
const directory = getDirectoryOfProcessById(processId); const directory = getDirectoryOfProcessById(processId);
const command = getProcessCommand(processId); const command = getProcessCommand(processId);
return ( return logger.interpolate`code=${command} subdue=${`(pid ${processId})`} in path=${directory}`;
chalk.cyan(command) +
chalk.grey(` (pid ${processId})\n`) +
chalk.blue(' in ') +
chalk.cyan(directory)
);
} catch (e) { } catch (e) {
return null; return null;
} }
@ -104,11 +99,11 @@ export default async function choosePort(
const question: prompts.PromptObject = { const question: prompts.PromptObject = {
type: 'confirm', type: 'confirm',
name: 'shouldChangePort', name: 'shouldChangePort',
message: `${chalk.yellow( message: logger.yellow(`${logger.bold('[WARNING]')} ${message}${
`${message}${
existingProcess ? ` Probably:\n ${existingProcess}` : '' existingProcess ? ` Probably:\n ${existingProcess}` : ''
}`, }
)}\n\nWould you like to run the app on another port instead?`,
Would you like to run the app on another port instead?`),
initial: true, initial: true,
}; };
prompts(question).then((answer) => { prompts(question).then((answer) => {
@ -119,15 +114,14 @@ export default async function choosePort(
} }
}); });
} else { } else {
console.log(chalk.red(message)); logger.error(message);
resolve(null); resolve(null);
} }
}), }),
(err) => { (err) => {
throw new Error( throw new Error(
`${chalk.red(`Could not find an open port at ${chalk.bold(host)}.`)}\n${ `Could not find an open port at ${host}.
`Network error message: "${err.message}".` || err ${`Network error message: "${err.message || err}".`}`,
}\n`,
); );
}, },
); );

View file

@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
// @ts-check
import * as eta from 'eta'; import * as eta from 'eta';
import React from 'react'; import React from 'react';
import {StaticRouter} from 'react-router-dom'; import {StaticRouter} from 'react-router-dom';
@ -24,7 +26,7 @@ import {
createStatefulLinksCollector, createStatefulLinksCollector,
ProvideLinksCollector, ProvideLinksCollector,
} from './LinksCollector'; } from './LinksCollector';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import {memoize} from 'lodash'; import {memoize} from 'lodash';
@ -43,21 +45,16 @@ export default async function render(locals) {
try { try {
return await doRender(locals); return await doRender(locals);
} catch (e) { } catch (e) {
console.error( logger.error`Docusaurus Node/SSR could not render static page with path path=${locals.path} because of following error:
chalk.red( ${e.stack}`;
`Docusaurus Node/SSR could not render static page with path "${locals.path}" because of following error:\n\n${e.stack}\n`,
),
);
const isNotDefinedErrorRegex = const isNotDefinedErrorRegex =
/(window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i; /(window|document|localStorage|navigator|alert|location|buffer|self) is not defined/i;
if (isNotDefinedErrorRegex.test(e.message)) { if (isNotDefinedErrorRegex.test(e.message)) {
console.error( logger.info`It looks like you are using code that should run on the client-side only.
chalk.green( To get around it, try using code=${'<BrowserOnly>'} (path=${'https://docusaurus.io/docs/docusaurus-core/#browseronly'}) or code=${'ExecutionEnvironment'} (path=${'https://docusaurus.io/docs/docusaurus-core/#executionenvironment'}).
'Pro tip: It looks like you are using code that should run on the client-side only.\nTo get around it, try using <BrowserOnly> (https://docusaurus.io/docs/docusaurus-core/#browseronly) or ExecutionEnvironment (https://docusaurus.io/docs/docusaurus-core/#executionenvironment).\nIt might also require to wrap your client code in useEffect hook and/or import a third-party library dynamically (if any).', It might also require to wrap your client code in code=${'useEffect'} hook and/or import a third-party library dynamically (if any).`;
),
);
} }
throw new Error('Server-side rendering fails due to the error above.'); throw new Error('Server-side rendering fails due to the error above.');
@ -142,11 +139,8 @@ async function doRender(locals) {
minifyJS: true, minifyJS: true,
}); });
} catch (e) { } catch (e) {
console.error( logger.error`Minification of page path=${locals.path} failed because of following error:
chalk.red( ${e.stack}`;
`Minification page with path "${locals.path}" failed because of following error:\n\n${e.stack}\n`,
),
);
throw e; throw e;
} }
} }

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import CopyWebpackPlugin from 'copy-webpack-plugin'; import CopyWebpackPlugin from 'copy-webpack-plugin';
import fs from 'fs-extra'; import fs from 'fs-extra';
import path from 'path'; import path from 'path';
@ -47,7 +47,6 @@ export default async function build(
isLastLocale: boolean; isLastLocale: boolean;
}) { }) {
try { try {
// console.log(chalk.green(`Site successfully built in locale=${locale}`));
return await buildLocale({ return await buildLocale({
siteDir, siteDir,
locale, locale,
@ -56,7 +55,7 @@ export default async function build(
isLastLocale, isLastLocale,
}); });
} catch (e) { } catch (e) {
console.error(`Unable to build website for locale "${locale}".`); logger.error`Unable to build website for locale name=${locale}.`;
throw e; throw e;
} }
} }
@ -73,12 +72,7 @@ export default async function build(
return tryToBuildLocale({locale: cliOptions.locale, isLastLocale: true}); return tryToBuildLocale({locale: cliOptions.locale, isLastLocale: true});
} else { } else {
if (i18n.locales.length > 1) { if (i18n.locales.length > 1) {
console.log( logger.info`Website will be built for all these locales: ${i18n.locales}`;
chalk.yellow(
`\nWebsite will be built for all these locales:
- ${i18n.locales.join('\n- ')}`,
),
);
} }
// We need the default locale to always be the 1st in the list // We need the default locale to always be the 1st in the list
@ -112,9 +106,7 @@ async function buildLocale({
}): Promise<string> { }): Promise<string> {
process.env.BABEL_ENV = 'production'; process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production'; process.env.NODE_ENV = 'production';
console.log( logger.info`name=${`[${locale}]`} Creating an optimized production build...`;
chalk.blue(`\n[${locale}] Creating an optimized production build...`),
);
const props: Props = await load(siteDir, { const props: Props = await load(siteDir, {
customOutDir: cliOptions.outDir, customOutDir: cliOptions.outDir,
@ -238,18 +230,13 @@ async function buildLocale({
baseUrl, baseUrl,
}); });
console.log( logger.success`Generated static files in path=${path.relative(
`${chalk.green(`Success!`)} Generated static files in "${chalk.cyan( process.cwd(),
path.relative(process.cwd(), outDir), outDir,
)}".`, )}.`;
);
if (isLastLocale) { if (isLastLocale) {
console.log( logger.info`Use code=${'npm run serve'} command to test your build locally.`;
`\nUse ${chalk.greenBright(
'`npm run serve`',
)} command to test your build locally.\n`,
);
} }
if (forceTerminate && isLastLocale && !cliOptions.bundleAnalyzer) { if (forceTerminate && isLastLocale && !cliOptions.bundleAnalyzer) {

View file

@ -7,22 +7,20 @@
import fs from 'fs-extra'; import fs from 'fs-extra';
import path from 'path'; import path from 'path';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import { import {
DEFAULT_BUILD_DIR_NAME, DEFAULT_BUILD_DIR_NAME,
GENERATED_FILES_DIR_NAME, GENERATED_FILES_DIR_NAME,
} from '@docusaurus/utils'; } from '@docusaurus/utils';
function removePath(fsPath: string) { async function removePath(fsPath: string) {
return fs try {
.remove(path.join(fsPath)) fs.remove(path.join(fsPath));
.then(() => { logger.success`Removed the path=${fsPath} directory.`;
console.log(chalk.green(`Successfully removed "${fsPath}" directory.`)); } catch (e) {
}) logger.error`Could not remove path=${fsPath} directory.
.catch((err) => { ${e as string}`;
console.error(`Could not remove ${fsPath} directory.`); }
console.error(err);
});
} }
export default async function clear(siteDir: string): Promise<unknown> { export default async function clear(siteDir: string): Promise<unknown> {

View file

@ -7,7 +7,7 @@
import fs from 'fs-extra'; import fs from 'fs-extra';
import shell from 'shelljs'; import shell from 'shelljs';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import {loadContext} from '../server'; import {loadContext} from '../server';
import build from './build'; import build from './build';
import {BuildCLIOptions} from '@docusaurus/types'; import {BuildCLIOptions} from '@docusaurus/types';
@ -25,14 +25,10 @@ function obfuscateGitPass(str: string) {
function shellExecLog(cmd: string) { function shellExecLog(cmd: string) {
try { try {
const result = shell.exec(cmd); const result = shell.exec(cmd);
console.log( logger.info`code=${obfuscateGitPass(cmd)} subdue=${`code: ${result.code}`}`;
`${chalk.cyan('CMD:')} ${obfuscateGitPass(cmd)} ${chalk.cyan(
`(code: ${result.code})`,
)}`,
);
return result; return result;
} catch (e) { } catch (e) {
console.log(`${chalk.red('CMD:')} ${obfuscateGitPass(cmd)}`); logger.error`code=${obfuscateGitPass(cmd)}`;
throw e; throw e;
} }
} }
@ -84,17 +80,13 @@ export default async function deploy(
}); });
if (typeof siteConfig.trailingSlash === 'undefined') { if (typeof siteConfig.trailingSlash === 'undefined') {
console.warn( logger.warn(`When deploying to GitHub Pages, it is better to use an explicit "trailingSlash" site config.
chalk.yellow(`
Docusaurus recommendation:
When deploying to GitHub Pages, it is better to use an explicit "trailingSlash" site config.
Otherwise, GitHub Pages will add an extra trailing slash to your site urls only on direct-access (not when navigation) with a server redirect. Otherwise, GitHub Pages will add an extra trailing slash to your site urls only on direct-access (not when navigation) with a server redirect.
This behavior can have SEO impacts and create relative link issues. This behavior can have SEO impacts and create relative link issues.
`), `);
);
} }
console.log('Deploy command invoked...'); logger.info('Deploy command invoked...');
if (!shell.which('git')) { if (!shell.which('git')) {
throw new Error('Git not installed or on the PATH!'); throw new Error('Git not installed or on the PATH!');
} }
@ -135,7 +127,7 @@ This behavior can have SEO impacts and create relative link issues.
`Missing project organization name. Did you forget to define "organizationName" in ${siteConfigPath}? You may also export it via the ORGANIZATION_NAME environment variable.`, `Missing project organization name. Did you forget to define "organizationName" in ${siteConfigPath}? You may also export it via the ORGANIZATION_NAME environment variable.`,
); );
} }
console.log(`${chalk.cyan('organizationName:')} ${organizationName}`); logger.info`organizationName: name=${organizationName}`;
const projectName = const projectName =
process.env.PROJECT_NAME || process.env.PROJECT_NAME ||
@ -146,7 +138,7 @@ This behavior can have SEO impacts and create relative link issues.
`Missing project name. Did you forget to define "projectName" in ${siteConfigPath}? You may also export it via the PROJECT_NAME environment variable.`, `Missing project name. Did you forget to define "projectName" in ${siteConfigPath}? You may also export it via the PROJECT_NAME environment variable.`,
); );
} }
console.log(`${chalk.cyan('projectName:')} ${projectName}`); logger.info`projectName: name=${projectName}`;
// We never deploy on pull request. // We never deploy on pull request.
const isPullRequest = const isPullRequest =
@ -173,7 +165,7 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
const deploymentBranch = const deploymentBranch =
process.env.DEPLOYMENT_BRANCH || siteConfig.deploymentBranch || 'gh-pages'; process.env.DEPLOYMENT_BRANCH || siteConfig.deploymentBranch || 'gh-pages';
console.log(`${chalk.cyan('deploymentBranch:')} ${deploymentBranch}`); logger.info`deploymentBranch: name=${deploymentBranch}`;
const githubHost = const githubHost =
process.env.GITHUB_HOST || siteConfig.githubHost || 'github.com'; process.env.GITHUB_HOST || siteConfig.githubHost || 'github.com';
@ -199,9 +191,7 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
); );
} }
console.log( logger.info`Remote repo URL: name=${obfuscateGitPass(deploymentRepoURL)}`;
`${chalk.cyan('Remote repo URL:')} ${obfuscateGitPass(deploymentRepoURL)}`,
);
// Check if this is a cross-repo publish. // Check if this is a cross-repo publish.
const crossRepoPublish = !sourceRepoUrl.endsWith( const crossRepoPublish = !sourceRepoUrl.endsWith(
@ -283,7 +273,7 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
try { try {
await runDeploy(await build(siteDir, cliOptions, false)); await runDeploy(await build(siteDir, cliOptions, false));
} catch (buildError) { } catch (buildError) {
console.error(buildError); logger.error((buildError as Error).message);
process.exit(1); process.exit(1);
} }
} else { } else {

View file

@ -7,8 +7,7 @@
import http from 'http'; import http from 'http';
import serveHandler from 'serve-handler'; import serveHandler from 'serve-handler';
import boxen from 'boxen'; import logger from '@docusaurus/logger';
import chalk from 'chalk';
import path from 'path'; import path from 'path';
import {loadSiteConfig} from '../server'; import {loadSiteConfig} from '../server';
import build from './build'; import build from './build';
@ -71,18 +70,8 @@ export default async function serve(
}); });
}); });
console.log( logger.success`Serving path=${cliOptions.dir} directory at path=${
boxen( servingUrl + baseUrl
chalk.green( }.`;
`Serving "${cliOptions.dir}" directory at "${servingUrl + baseUrl}".`,
),
{
borderColor: 'green',
padding: 1,
margin: 1,
align: 'center',
},
),
);
server.listen(port); server.listen(port);
} }

View file

@ -6,7 +6,7 @@
*/ */
import {normalizeUrl, posixPath} from '@docusaurus/utils'; import {normalizeUrl, posixPath} from '@docusaurus/utils';
import chalk = require('chalk'); import logger from '@docusaurus/logger';
import chokidar from 'chokidar'; import chokidar from 'chokidar';
import HtmlWebpackPlugin from 'html-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin';
import path from 'path'; import path from 'path';
@ -34,7 +34,7 @@ export default async function start(
): Promise<void> { ): Promise<void> {
process.env.NODE_ENV = 'development'; process.env.NODE_ENV = 'development';
process.env.BABEL_ENV = 'development'; process.env.BABEL_ENV = 'development';
console.log(chalk.blue('Starting the development server...')); logger.info('Starting the development server...');
function loadSite() { function loadSite() {
return load(siteDir, { return load(siteDir, {
@ -60,9 +60,7 @@ export default async function start(
const urls = prepareUrls(protocol, host, port); const urls = prepareUrls(protocol, host, port);
const openUrl = normalizeUrl([urls.localUrlForBrowser, baseUrl]); const openUrl = normalizeUrl([urls.localUrlForBrowser, baseUrl]);
console.log( logger.success`Docusaurus website is running at path=${openUrl}.`;
chalk.cyanBright(`Docusaurus website is running at "${openUrl}".`),
);
// Reload files processing. // Reload files processing.
const reload = debounce(() => { const reload = debounce(() => {
@ -70,15 +68,11 @@ export default async function start(
.then(({baseUrl: newBaseUrl}) => { .then(({baseUrl: newBaseUrl}) => {
const newOpenUrl = normalizeUrl([urls.localUrlForBrowser, newBaseUrl]); const newOpenUrl = normalizeUrl([urls.localUrlForBrowser, newBaseUrl]);
if (newOpenUrl !== openUrl) { if (newOpenUrl !== openUrl) {
console.log( logger.success`Docusaurus website is running at path=${newOpenUrl}.`;
chalk.cyanBright(
`Docusaurus website is running at "${newOpenUrl}".`,
),
);
} }
}) })
.catch((err) => { .catch((err) => {
console.error(chalk.red(err.stack)); logger.error(err.stack);
}); });
}, 500); }, 500);
const {siteConfig, plugins = []} = props; const {siteConfig, plugins = []} = props;
@ -170,10 +164,10 @@ export default async function start(
if (process.env.E2E_TEST) { if (process.env.E2E_TEST) {
compiler.hooks.done.tap('done', (stats) => { compiler.hooks.done.tap('done', (stats) => {
if (stats.hasErrors()) { if (stats.hasErrors()) {
console.log('E2E_TEST: Project has compiler errors.'); logger.error('E2E_TEST: Project has compiler errors.');
process.exit(1); process.exit(1);
} }
console.log('E2E_TEST: Project can compile.'); logger.success('E2E_TEST: Project can compile.');
process.exit(0); process.exit(0);
}); });
} }

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import fs from 'fs-extra'; import fs from 'fs-extra';
import importFresh from 'import-fresh'; import importFresh from 'import-fresh';
import path from 'path'; import path from 'path';
@ -100,23 +100,18 @@ function themeComponents(
const components = colorCode(themePath, plugin); const components = colorCode(themePath, plugin);
if (components.length === 0) { if (components.length === 0) {
return `${chalk.red('No component to swizzle.')}`; return 'No component to swizzle.';
} }
return ` return `Theme components available for swizzle.
${chalk.cyan('Theme components available for swizzle.')}
${chalk.green('green =>')} safe: lower breaking change risk ${logger.green(logger.bold('green =>'))} safe: lower breaking change risk
${chalk.red('red =>')} unsafe: higher breaking change risk ${logger.red(logger.bold('red =>'))} unsafe: higher breaking change risk
${components.join('\n')} ${components.join('\n')}
`; `;
} }
function formattedThemeNames(themeNames: string[]): string {
return `Themes available for swizzle:\n- ${themeNames.join('\n- ')}`;
}
function colorCode( function colorCode(
themePath: string, themePath: string,
plugin: ImportedPluginModule, plugin: ImportedPluginModule,
@ -135,8 +130,12 @@ function colorCode(
); );
return [ return [
...greenComponents.map((component) => chalk.green(`safe: ${component}`)), ...greenComponents.map(
...redComponents.map((component) => chalk.red(`unsafe: ${component}`)), (component) => `${logger.green(logger.bold('safe:'))} ${component}`,
),
...redComponents.map(
(component) => `${logger.red(logger.bold('unsafe:'))} ${component}`,
),
]; ];
} }
@ -161,27 +160,25 @@ export default async function swizzle(
); );
if (!themeName) { if (!themeName) {
console.log(formattedThemeNames(themeNames)); logger.info`Themes available for swizzle: name=${themeNames}`;
process.exit(1); return;
} }
let pluginModule: ImportedPluginModule; let pluginModule: ImportedPluginModule;
try { try {
pluginModule = importFresh(themeName); pluginModule = importFresh(themeName);
} catch { } catch {
let suggestion; let suggestion: string | undefined;
themeNames.forEach((name) => { themeNames.forEach((name) => {
if (leven(name, themeName) < 4) { if (leven(name, themeName) < 4) {
suggestion = name; suggestion = name;
} }
}); });
chalk.red( logger.error`Theme name=${themeName} not found. ${
`Theme ${themeName} not found. ${
suggestion suggestion
? `Did you mean "${suggestion}" ?` ? logger.interpolate`Did you mean name=${suggestion}?`
: formattedThemeNames(themeNames) : logger.interpolate`Themes available for swizzle: ${themeNames}`
}`, }`;
);
process.exit(1); process.exit(1);
} }
@ -218,19 +215,17 @@ export default async function swizzle(
: pluginInstance.getThemePath?.(); : pluginInstance.getThemePath?.();
if (!themePath) { if (!themePath) {
console.warn( logger.warn(
chalk.yellow(
typescript typescript
? `${themeName} does not provide TypeScript theme code via "getTypeScriptThemePath()".` ? logger.interpolate`name=${themeName} does not provide TypeScript theme code via ${'getTypeScriptThemePath()'}.`
: `${themeName} does not provide any theme code.`, : logger.interpolate`name=${themeName} does not provide any theme code.`,
),
); );
process.exit(1); process.exit(1);
} }
if (!componentName) { if (!componentName) {
console.warn(themeComponents(themePath, pluginModule)); logger.info(themeComponents(themePath, pluginModule));
process.exit(1); return;
} }
const components = getComponentName(themePath, pluginModule, Boolean(danger)); const components = getComponentName(themePath, pluginModule, Boolean(danger));
@ -256,12 +251,8 @@ export default async function swizzle(
if (mostSuitableMatch !== componentName) { if (mostSuitableMatch !== componentName) {
mostSuitableComponent = mostSuitableMatch; mostSuitableComponent = mostSuitableMatch;
console.log( logger.error`Component name=${componentName} doesn't exist.`;
chalk.red(`Component "${componentName}" doesn't exist.`), logger.info`name=${mostSuitableComponent} is swizzled instead of name=${componentName}.`;
chalk.yellow(
`"${mostSuitableComponent}" is swizzled instead of "${componentName}".`,
),
);
} }
} }
@ -277,40 +268,29 @@ export default async function swizzle(
} else if (fs.existsSync(`${fromPath}.js`)) { } else if (fs.existsSync(`${fromPath}.js`)) {
[fromPath, toPath] = [`${fromPath}.js`, `${toPath}.js`]; [fromPath, toPath] = [`${fromPath}.js`, `${toPath}.js`];
} else { } else {
let suggestion; let suggestion: string | undefined;
components.forEach((name) => { components.forEach((name) => {
if (leven(name, mostSuitableComponent) < 3) { if (leven(name, mostSuitableComponent) < 3) {
suggestion = name; suggestion = name;
} }
}); });
console.warn(chalk.red(`Component ${mostSuitableComponent} not found.`)); logger.error`Component name=${mostSuitableComponent} not found. ${
console.warn(
suggestion suggestion
? `Did you mean "${suggestion}"?` ? logger.interpolate`Did you mean name=${suggestion} ?`
: `${themeComponents(themePath, pluginModule)}`, : themeComponents(themePath, pluginModule)
); }`;
process.exit(1); process.exit(1);
} }
} }
if (!components.includes(mostSuitableComponent) && !danger) { if (!components.includes(mostSuitableComponent) && !danger) {
console.warn( logger.error`name=${mostSuitableComponent} is an internal component and has a higher breaking change probability. If you want to swizzle it, use the code=${'--danger'} flag.`;
chalk.red(
`${mostSuitableComponent} is an internal component and has a higher breaking change probability. If you want to swizzle it, use the "--danger" flag.`,
),
);
process.exit(1); process.exit(1);
} }
await fs.copy(fromPath, toPath); await fs.copy(fromPath, toPath);
const relativeDir = path.relative(process.cwd(), toPath); logger.success`Copied code=${
const fromMsg = chalk.blue( mostSuitableComponent ? `${themeName} ${mostSuitableComponent}` : themeName
mostSuitableComponent } to path=${path.relative(process.cwd(), toPath)}.`;
? `${themeName} ${chalk.yellow(mostSuitableComponent)}`
: themeName,
);
const toMsg = chalk.cyan(relativeDir);
console.log(`\n${chalk.green('Success!')} Copied ${fromMsg} to ${toMsg}.\n`);
} }

View file

@ -6,7 +6,7 @@
*/ */
import fs from 'fs-extra'; import fs from 'fs-extra';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import {loadContext, loadPluginConfigs} from '../server'; import {loadContext, loadPluginConfigs} from '../server';
import initPlugins from '../server/plugins/init'; import initPlugins from '../server/plugins/init';
@ -150,21 +150,10 @@ export default async function writeHeadingIds(
const pathsModified = result.filter(Boolean) as string[]; const pathsModified = result.filter(Boolean) as string[];
if (pathsModified.length) { if (pathsModified.length) {
console.log( logger.success`Heading ids added to Markdown files (number=${`${pathsModified.length}/${markdownFiles.length}`} files): ${pathsModified}`;
chalk.green(`Heading ids added to Markdown files (${
pathsModified.length
}/${markdownFiles.length} files):
- ${pathsModified.join('\n- ')}`),
);
} else { } else {
console.log( logger.warn`number=${
chalk.yellow(
`${
markdownFiles.length markdownFiles.length
} Markdown files already have explicit heading IDs. If you intend to overwrite the existing heading IDs, use the ${chalk.cyan( } Markdown files already have explicit heading IDs. If you intend to overwrite the existing heading IDs, use the code=${'--overwrite'} option.`;
'--overwrite',
)} option.`,
),
);
} }
} }

View file

@ -147,7 +147,7 @@ describe('normalizeConfig', () => {
'should accept [function, object] for plugin', 'should accept [function, object] for plugin',
[[function (_context, _options) {}, {it: 'should work'}]], [[function (_context, _options) {}, {it: 'should work'}]],
], ],
])(`%s for the input of: %p`, (_message, plugins) => { ])(`subdue= for the input of: path=`, (_message, plugins) => {
expect(() => { expect(() => {
normalizeConfig({ normalizeConfig({
plugins, plugins,

View file

@ -34,7 +34,6 @@ function loadI18nTest(i18nConfig: I18nConfig, locale?: string) {
} }
describe('defaultLocaleConfig', () => { describe('defaultLocaleConfig', () => {
// @ts-expect-error: wait for TS support of ES2021 feature
const canComputeLabel = typeof Intl.DisplayNames !== 'undefined'; const canComputeLabel = typeof Intl.DisplayNames !== 'undefined';
test('returns correct labels', () => { test('returns correct labels', () => {
@ -174,7 +173,7 @@ describe('loadI18n', () => {
'it', 'it',
); );
expect(consoleSpy.mock.calls[0][0]).toMatch( expect(consoleSpy.mock.calls[0][0]).toMatch(
/The locale "it" was not found in your site configuration/, /The locale .*it.* was not found in your site configuration/,
); );
}); });
}); });

View file

@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import logger from '@docusaurus/logger';
import {DocusaurusConfig, I18nConfig} from '@docusaurus/types'; import {DocusaurusConfig, I18nConfig} from '@docusaurus/types';
import {DEFAULT_CONFIG_FILE_NAME, STATIC_DIR_NAME} from '@docusaurus/utils'; import {DEFAULT_CONFIG_FILE_NAME, STATIC_DIR_NAME} from '@docusaurus/utils';
import { import {
@ -200,7 +201,7 @@ export function validateConfig(
if (error) { if (error) {
logValidationBugReportHint(); logValidationBugReportHint();
if (isValidationDisabledEscapeHatch) { if (isValidationDisabledEscapeHatch) {
console.error(error); logger.error(error.message);
return config as DocusaurusConfig; return config as DocusaurusConfig;
} }

View file

@ -7,9 +7,9 @@
import {I18n, DocusaurusConfig, I18nLocaleConfig} from '@docusaurus/types'; import {I18n, DocusaurusConfig, I18nLocaleConfig} from '@docusaurus/types';
import path from 'path'; import path from 'path';
import {normalizeUrl, NODE_MAJOR_VERSION} from '@docusaurus/utils'; import {normalizeUrl} from '@docusaurus/utils';
import {getLangDir} from 'rtl-detect'; import {getLangDir} from 'rtl-detect';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
function getDefaultLocaleLabel(locale: string) { function getDefaultLocaleLabel(locale: string) {
// Intl.DisplayNames is ES2021 - Node14+ // Intl.DisplayNames is ES2021 - Node14+
@ -51,28 +51,14 @@ export async function loadI18n(
const currentLocale = options.locale ?? i18nConfig.defaultLocale; const currentLocale = options.locale ?? i18nConfig.defaultLocale;
if (!i18nConfig.locales.includes(currentLocale)) { if (!i18nConfig.locales.includes(currentLocale)) {
console.warn( logger.warn`The locale name=${currentLocale} was not found in your site configuration: Available locales are: ${i18nConfig.locales}
chalk.yellow( Note: Docusaurus only support running one locale at a time.`;
`The locale "${currentLocale}" was not found in your site configuration: Available locales are: ${i18nConfig.locales.join(
',',
)}.
Note: Docusaurus only support running one locale at a time.`,
),
);
} }
const locales = i18nConfig.locales.includes(currentLocale) const locales = i18nConfig.locales.includes(currentLocale)
? i18nConfig.locales ? i18nConfig.locales
: (i18nConfig.locales.concat(currentLocale) as [string, ...string[]]); : (i18nConfig.locales.concat(currentLocale) as [string, ...string[]]);
if (shouldWarnAboutNodeVersion(NODE_MAJOR_VERSION, locales)) {
console.warn(
chalk.yellow(
`To use Docusaurus i18n, it is strongly advised to use Node.js 14 or later (instead of ${NODE_MAJOR_VERSION}).`,
),
);
}
function getLocaleConfig(locale: string): I18nLocaleConfig { function getLocaleConfig(locale: string): I18nLocaleConfig {
return { return {
...getDefaultLocaleConfig(locale), ...getDefaultLocaleConfig(locale),

View file

@ -11,8 +11,8 @@ import {
DEFAULT_CONFIG_FILE_NAME, DEFAULT_CONFIG_FILE_NAME,
GENERATED_FILES_DIR_NAME, GENERATED_FILES_DIR_NAME,
} from '@docusaurus/utils'; } from '@docusaurus/utils';
import path, {join} from 'path'; import path from 'path';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import ssrDefaultTemplate from '../client/templates/ssr.html.template'; import ssrDefaultTemplate from '../client/templates/ssr.html.template';
import loadClientModules from './client-modules'; import loadClientModules from './client-modules';
import loadConfig from './config'; import loadConfig from './config';
@ -385,9 +385,9 @@ ${Object.keys(registry)
// Version metadata. // Version metadata.
const siteMetadata: DocusaurusSiteMetadata = { const siteMetadata: DocusaurusSiteMetadata = {
docusaurusVersion: getPackageJsonVersion( docusaurusVersion: getPackageJsonVersion(
join(__dirname, '../../package.json'), path.join(__dirname, '../../package.json'),
)!, )!,
siteVersion: getPackageJsonVersion(join(siteDir, 'package.json')), siteVersion: getPackageJsonVersion(path.join(siteDir, 'package.json')),
pluginVersions: {}, pluginVersions: {},
}; };
plugins plugins
@ -446,15 +446,14 @@ function checkDocusaurusPackagesVersion(siteMetadata: DocusaurusSiteMetadata) {
if ( if (
versionInfo.type === 'package' && versionInfo.type === 'package' &&
versionInfo.name?.startsWith('@docusaurus/') && versionInfo.name?.startsWith('@docusaurus/') &&
versionInfo.version &&
versionInfo.version !== docusaurusVersion versionInfo.version !== docusaurusVersion
) { ) {
// should we throw instead? // should we throw instead?
// It still could work with different versions // It still could work with different versions
console.warn( logger.error`Invalid name=${plugin} version number=${versionInfo.version}.
chalk.red( All official @docusaurus/* packages should have the exact same version as @docusaurus/core (number=${docusaurusVersion}).
`Invalid ${plugin} version ${versionInfo.version}.\nAll official @docusaurus/* packages should have the exact same version as @docusaurus/core (${docusaurusVersion}).\nMaybe you want to check, or regenerate your yarn.lock or package-lock.json file?`, Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?`;
),
);
} }
}, },
); );

View file

@ -20,7 +20,7 @@ import {
InitializedPlugin, InitializedPlugin,
} from '@docusaurus/types'; } from '@docusaurus/types';
import initPlugins from './init'; import initPlugins from './init';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import {chain} from 'lodash'; import {chain} from 'lodash';
import {localizePluginTranslationFile} from '../translations/translations'; import {localizePluginTranslationFile} from '../translations/translations';
import applyRouteTrailingSlash from './applyRouteTrailingSlash'; import applyRouteTrailingSlash from './applyRouteTrailingSlash';
@ -211,11 +211,7 @@ export async function loadPlugins({
// TODO remove this deprecated lifecycle soon // TODO remove this deprecated lifecycle soon
// deprecated since alpha-60 // deprecated since alpha-60
// TODO, 1 user reported usage of this lifecycle! https://github.com/facebook/docusaurus/issues/3918 // TODO, 1 user reported usage of this lifecycle! https://github.com/facebook/docusaurus/issues/3918
console.error( logger.error`Plugin code=${'routesLoaded'} lifecycle is deprecated. If you think we should keep this lifecycle, please report here: path=${'https://github.com/facebook/docusaurus/issues/3918'}`;
chalk.red(
'Plugin routesLoaded lifecycle is deprecated. If you think we should keep this lifecycle, please report here: https://github.com/facebook/docusaurus/issues/3918',
),
);
return plugin.routesLoaded(pluginsRouteConfigs); return plugin.routesLoaded(pluginsRouteConfigs);
}), }),

View file

@ -16,7 +16,7 @@ import {
} from '@docusaurus/types'; } from '@docusaurus/types';
import {getPluginI18nPath, toMessageRelativeFilePath} from '@docusaurus/utils'; import {getPluginI18nPath, toMessageRelativeFilePath} from '@docusaurus/utils';
import {Joi} from '@docusaurus/utils-validation'; import {Joi} from '@docusaurus/utils-validation';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
export type WriteTranslationsOptions = { export type WriteTranslationsOptions = {
override?: boolean; override?: boolean;
@ -115,11 +115,8 @@ export async function writeTranslationFileContent({
Object.keys(newContent), Object.keys(newContent),
); );
if (unknownKeys.length > 0) { if (unknownKeys.length > 0) {
console.warn( logger.warn`Some translation keys looks unknown to us in file path=${filePath}.
chalk.yellow(`Some translation keys looks unknown to us in file ${filePath} Maybe you should remove them? ${unknownKeys}`;
Maybe you should remove them?
- ${unknownKeys.join('\n- ')}`),
);
} }
const mergedContent = mergeTranslationFileContent({ const mergedContent = mergeTranslationFileContent({
@ -130,16 +127,11 @@ Maybe you should remove them?
// Avoid creating empty translation files // Avoid creating empty translation files
if (Object.keys(mergedContent).length > 0) { if (Object.keys(mergedContent).length > 0) {
console.log( logger.info`number=${
`${Object.keys(mergedContent) Object.keys(mergedContent).length
.length.toString() } translations will be written at path=${toMessageRelativeFilePath(
.padStart(
3,
' ',
)} translations will be written at "${toMessageRelativeFilePath(
filePath, filePath,
)}".`, )}.`;
);
await fs.ensureDir(path.dirname(filePath)); await fs.ensureDir(path.dirname(filePath));
await fs.writeFile(filePath, JSON.stringify(mergedContent, null, 2)); await fs.writeFile(filePath, JSON.stringify(mergedContent, null, 2));
} }
@ -290,12 +282,8 @@ export function applyDefaultCodeTranslations({
Object.keys(extractedCodeTranslations), Object.keys(extractedCodeTranslations),
); );
if (unusedDefaultCodeMessages.length > 0) { if (unusedDefaultCodeMessages.length > 0) {
console.warn( logger.warn`Unused default message codes found.
chalk.yellow(`Unused default message codes found. Please report this Docusaurus issue. name=${unusedDefaultCodeMessages}`;
Please report this Docusaurus issue.
- ${unusedDefaultCodeMessages.join('\n- ')}
`),
);
} }
return mapValues( return mapValues(

View file

@ -8,7 +8,7 @@
import fs from 'fs-extra'; import fs from 'fs-extra';
import traverse, {Node} from '@babel/traverse'; import traverse, {Node} from '@babel/traverse';
import generate from '@babel/generator'; import generate from '@babel/generator';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import {parse, types as t, NodePath, TransformOptions} from '@babel/core'; import {parse, types as t, NodePath, TransformOptions} from '@babel/core';
import { import {
InitializedPlugin, InitializedPlugin,
@ -115,11 +115,7 @@ function logSourceCodeFileTranslationsWarnings(
) { ) {
sourceCodeFilesTranslations.forEach(({sourceCodeFilePath, warnings}) => { sourceCodeFilesTranslations.forEach(({sourceCodeFilePath, warnings}) => {
if (warnings.length > 0) { if (warnings.length > 0) {
console.warn( logger.warn`Translation extraction warnings for file path=${sourceCodeFilePath}: ${warnings}`;
`Translation extraction warnings for file path=${sourceCodeFilePath}:\n- ${chalk.yellow(
warnings.join('\n\n- '),
)}`,
);
} }
}); });
} }
@ -302,7 +298,6 @@ function extractSourceCodeAstTranslations(
return; return;
} }
// console.log('CallExpression', path.node);
const args = path.get('arguments'); const args = path.get('arguments');
if (args.length === 1 || args.length === 2) { if (args.length === 1 || args.length === 2) {
const firstArgPath = args[0]; const firstArgPath = args[0];
@ -310,8 +305,6 @@ function extractSourceCodeAstTranslations(
// evaluation allows translate("x" + "y"); to be considered as translate("xy"); // evaluation allows translate("x" + "y"); to be considered as translate("xy");
const firstArgEvaluated = firstArgPath.evaluate(); const firstArgEvaluated = firstArgPath.evaluate();
// console.log('firstArgEvaluated', firstArgEvaluated);
if ( if (
firstArgEvaluated.confident && firstArgEvaluated.confident &&
typeof firstArgEvaluated.value === 'object' typeof firstArgEvaluated.value === 'object'

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import path from 'path'; import path from 'path';
import {Configuration} from 'webpack'; import {Configuration} from 'webpack';
import merge from 'webpack-merge'; import merge from 'webpack-merge';
@ -45,12 +45,9 @@ export default function createClientConfig(
apply: (compiler) => { apply: (compiler) => {
compiler.hooks.done.tap('client:done', (stats) => { compiler.hooks.done.tap('client:done', (stats) => {
if (stats.hasErrors()) { if (stats.hasErrors()) {
console.log( logger.error(
chalk.red(
'Client bundle compiled with errors therefore further build is impossible.', 'Client bundle compiled with errors therefore further build is impossible.',
),
); );
process.exit(1); process.exit(1);
} }
}); });

View file

@ -21,7 +21,7 @@ import TerserPlugin from 'terser-webpack-plugin';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import path from 'path'; import path from 'path';
import crypto from 'crypto'; import crypto from 'crypto';
import chalk from 'chalk'; import logger from '@docusaurus/logger';
import {TransformOptions} from '@babel/core'; import {TransformOptions} from '@babel/core';
import { import {
ConfigureWebpackFn, ConfigureWebpackFn,
@ -161,11 +161,7 @@ export const getCustomizableJSLoader =
// TODO remove this before end of 2021? // TODO remove this before end of 2021?
const warnBabelLoaderOnce = memoize(() => { const warnBabelLoaderOnce = memoize(() => {
console.warn( logger.warn`Docusaurus plans to support multiple JS loader strategies (Babel, esbuild...): code=${'getBabelLoader(isServer)'} is now deprecated in favor of code=${'getJSLoader(isServer)'}.`;
chalk.yellow(
'Docusaurus plans to support multiple JS loader strategies (Babel, esbuild...): "getBabelLoader(isServer)" is now deprecated in favor of "getJSLoader({isServer})".',
),
);
}); });
const getBabelLoaderDeprecated = function getBabelLoaderDeprecated( const getBabelLoaderDeprecated = function getBabelLoaderDeprecated(
isServer: boolean, isServer: boolean,
@ -177,11 +173,7 @@ const getBabelLoaderDeprecated = function getBabelLoaderDeprecated(
// TODO remove this before end of 2021 ? // TODO remove this before end of 2021 ?
const warnCacheLoaderOnce = memoize(() => { const warnCacheLoaderOnce = memoize(() => {
console.warn( logger.warn`Docusaurus uses Webpack 5 and code=${'getCacheLoader()'} usage is now deprecated.`;
chalk.yellow(
'Docusaurus uses Webpack 5 and getCacheLoader() usage is now deprecated.',
),
);
}); });
function getCacheLoaderDeprecated() { function getCacheLoaderDeprecated() {
warnCacheLoaderOnce(); warnCacheLoaderOnce();
@ -269,11 +261,11 @@ export function compile(config: Configuration[]): Promise<void> {
const compiler = webpack(config); const compiler = webpack(config);
compiler.run((err, stats) => { compiler.run((err, stats) => {
if (err) { if (err) {
console.error(err.stack || err); logger.error(err.stack || err);
// @ts-expect-error: see https://webpack.js.org/api/node/#error-handling // @ts-expect-error: see https://webpack.js.org/api/node/#error-handling
if (err.details) { if (err.details) {
// @ts-expect-error: see https://webpack.js.org/api/node/#error-handling // @ts-expect-error: see https://webpack.js.org/api/node/#error-handling
console.error(err.details); logger.error(err.details);
} }
reject(err); reject(err);
} }
@ -284,16 +276,14 @@ export function compile(config: Configuration[]): Promise<void> {
} }
if (errorsWarnings && stats?.hasWarnings()) { if (errorsWarnings && stats?.hasWarnings()) {
errorsWarnings.warnings?.forEach((warning) => { errorsWarnings.warnings?.forEach((warning) => {
console.warn(warning); logger.warn(`${warning}`);
}); });
} }
// Webpack 5 requires calling close() so that persistent caching works // Webpack 5 requires calling close() so that persistent caching works
// See https://github.com/webpack/webpack.js.org/pull/4775 // See https://github.com/webpack/webpack.js.org/pull/4775
compiler.close((errClose) => { compiler.close((errClose) => {
if (errClose) { if (errClose) {
console.error( logger.error(`Error while closing Webpack compiler: ${errClose}`);
chalk.red('Error while closing Webpack compiler:', errClose),
);
reject(errClose); reject(errClose);
} else { } else {
resolve(); resolve();
@ -322,9 +312,8 @@ function validateKeyAndCerts({
encrypted = crypto.publicEncrypt(cert, Buffer.from('test')); encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
} catch (err) { } catch (err) {
throw new Error( throw new Error(
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${ `The certificate ${crtFile} is invalid.
(err as Error).message ${err}`,
}`,
); );
} }
@ -333,9 +322,8 @@ function validateKeyAndCerts({
crypto.privateDecrypt(key, encrypted); crypto.privateDecrypt(key, encrypted);
} catch (err) { } catch (err) {
throw new Error( throw new Error(
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${ `The certificate key ${keyFile} is invalid.
(err as Error).message ${err}`,
}`,
); );
} }
} }
@ -344,9 +332,7 @@ function validateKeyAndCerts({
function readEnvFile(file: string, type: string) { function readEnvFile(file: string, type: string) {
if (!fs.existsSync(file)) { if (!fs.existsSync(file)) {
throw new Error( throw new Error(
`You specified ${chalk.cyan( `You specified ${type} in your env, but the file "${file}" can't be found.`,
type,
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`,
); );
} }
return fs.readFileSync(file); return fs.readFileSync(file);

View file

@ -2,7 +2,6 @@
"extends": "../../tsconfig.json", "extends": "../../tsconfig.json",
"compilerOptions": { "compilerOptions": {
"incremental": true, "incremental": true,
"lib": ["DOM", "ES2019"],
"tsBuildInfoFile": "./lib/.tsbuildinfo", "tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src", "rootDir": "src",
"outDir": "lib", "outDir": "lib",