-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(nx): add friendlier output when running outside a workspace
- Loading branch information
1 parent
99bc6df
commit 44c8d17
Showing
7 changed files
with
319 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,13 @@ | ||
#!/usr/bin/env node | ||
import { statSync } from 'fs'; | ||
import * as path from 'path'; | ||
|
||
function findWorkspaceRoot(dir: string) { | ||
if (path.dirname(dir) === dir) return null; | ||
if (exists(path.join(dir, 'angular.json'))) { | ||
return { type: 'angular', dir }; | ||
} else if (exists(path.join(dir, 'workspace.json'))) { | ||
return { type: 'nx', dir }; | ||
} else { | ||
return findWorkspaceRoot(path.dirname(dir)); | ||
} | ||
} | ||
|
||
function exists(filePath: string): boolean { | ||
try { | ||
return statSync(filePath).isFile() || statSync(filePath).isDirectory(); | ||
} catch (err) { | ||
return false; | ||
} | ||
} | ||
import { findWorkspaceRoot } from '../lib/find-workspace-root'; | ||
import { initGlobal } from '../lib/init-global'; | ||
import { initLocal } from '../lib/init-local'; | ||
|
||
const workspace = findWorkspaceRoot(__dirname); | ||
|
||
// we are running a local nx | ||
if (workspace) { | ||
// required to make sure nrwl/workspace import works | ||
if (workspace.type === 'nx') { | ||
require(path.join( | ||
workspace.dir, | ||
'node_modules', | ||
'@nrwl', | ||
'tao', | ||
'src', | ||
'compat', | ||
'compat.js' | ||
)); | ||
} | ||
|
||
// The commandsObject is a Yargs object declared in `nx-commands.ts`, | ||
// It is exposed and bootstrapped here to provide CLI features. | ||
const w = require('@nrwl/workspace'); | ||
if (w.supportedNxCommands.includes(process.argv[2])) { | ||
w.commandsObject.argv; | ||
} else if (workspace.type === 'nx') { | ||
require(path.join( | ||
workspace.dir, | ||
'node_modules', | ||
'@nrwl', | ||
'tao', | ||
'index.js' | ||
)); | ||
} else if (workspace.type === 'angular') { | ||
w.output.note({ | ||
title: `Nx didn't recognize the command, forwarding on to the Angular CLI.` | ||
}); | ||
require(path.join( | ||
workspace.dir, | ||
'node_modules', | ||
'@angular', | ||
'cli', | ||
'lib', | ||
'init.js' | ||
)); | ||
} | ||
initLocal(workspace); | ||
} else { | ||
// we are running global nx | ||
const w = findWorkspaceRoot(process.cwd()); | ||
if (w) { | ||
require(path.join(w.dir, 'node_modules', '@nrwl', 'cli', 'bin', 'nx.js')); | ||
} else { | ||
console.log(`The current directory isn't part of an Nx workspace.`); | ||
process.exit(0); | ||
} | ||
initGlobal(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { existsSync } from 'fs'; | ||
import * as path from 'path'; | ||
import { Workspace } from './workspace'; | ||
|
||
/** | ||
* Recursive function that walks back up the directory | ||
* tree to try and find a workspace file. | ||
* | ||
* @param dir Directory to start searching with | ||
*/ | ||
export function findWorkspaceRoot(dir: string): Workspace { | ||
if (path.dirname(dir) === dir) { | ||
return null; | ||
} | ||
|
||
if (existsSync(path.join(dir, 'angular.json'))) { | ||
return { type: 'angular', dir }; | ||
} | ||
|
||
if (existsSync(path.join(dir, 'workspace.json'))) { | ||
return { type: 'nx', dir }; | ||
} | ||
|
||
return findWorkspaceRoot(path.dirname(dir)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import chalk from 'chalk'; | ||
import * as path from 'path'; | ||
import { findWorkspaceRoot } from './find-workspace-root'; | ||
import { output } from './output'; | ||
|
||
/** | ||
* Nx is being run from outside a workspace | ||
*/ | ||
export function initGlobal() { | ||
const workspace = findWorkspaceRoot(process.cwd()); | ||
|
||
if (workspace) { | ||
// Found a workspace root - hand off to the local copy of Nx | ||
require(path.join( | ||
workspace.dir, | ||
'node_modules', | ||
'@nrwl', | ||
'cli', | ||
'bin', | ||
'nx.js' | ||
)); | ||
} else { | ||
output.log({ | ||
title: `The current directory isn't part of an Nx workspace.`, | ||
bodyLines: [ | ||
`To create a workspace run:`, | ||
chalk.bold.white(`npx create-nx-workspace@latest <workspace name>`) | ||
] | ||
}); | ||
|
||
output.note({ | ||
title: `For more information please visit https://nx.dev/` | ||
}); | ||
process.exit(0); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import * as path from 'path'; | ||
import { Workspace } from './workspace'; | ||
|
||
/** | ||
* Nx is being run inside a workspace. | ||
* | ||
* @param workspace Relevant local workspace properties | ||
*/ | ||
export function initLocal(workspace: Workspace) { | ||
// required to make sure nrwl/workspace import works | ||
if (workspace.type === 'nx') { | ||
require(path.join( | ||
workspace.dir, | ||
'node_modules', | ||
'@nrwl', | ||
'tao', | ||
'src', | ||
'compat', | ||
'compat.js' | ||
)); | ||
} | ||
|
||
// The commandsObject is a Yargs object declared in `nx-commands.ts`, | ||
// It is exposed and bootstrapped here to provide CLI features. | ||
const w = require('@nrwl/workspace'); | ||
if (w.supportedNxCommands.includes(process.argv[2])) { | ||
w.commandsObject.argv; | ||
} else if (workspace.type === 'nx') { | ||
require(path.join( | ||
workspace.dir, | ||
'node_modules', | ||
'@nrwl', | ||
'tao', | ||
'index.js' | ||
)); | ||
} else if (workspace.type === 'angular') { | ||
w.output.note({ | ||
title: `Nx didn't recognize the command, forwarding on to the Angular CLI.` | ||
}); | ||
require(path.join( | ||
workspace.dir, | ||
'node_modules', | ||
'@angular', | ||
'cli', | ||
'lib', | ||
'init.js' | ||
)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
/** | ||
* This file has been copied from workspace/src/command-line/output | ||
* Consider that file to be the golden source. Changes (which should be few) | ||
* should be copied here if necessary. | ||
*/ | ||
import chalk from 'chalk'; | ||
|
||
export interface CLIErrorMessageConfig { | ||
title: string; | ||
bodyLines?: string[]; | ||
slug?: string; | ||
} | ||
|
||
export interface CLIWarnMessageConfig { | ||
title: string; | ||
bodyLines?: string[]; | ||
slug?: string; | ||
} | ||
|
||
export interface CLILogMessageConfig { | ||
title: string; | ||
bodyLines?: string[]; | ||
} | ||
|
||
export interface CLINoteMessageConfig { | ||
title: string; | ||
bodyLines?: string[]; | ||
} | ||
|
||
export interface CLISuccessMessageConfig { | ||
title: string; | ||
} | ||
|
||
/** | ||
* Automatically disable styling applied by chalk if CI=true | ||
*/ | ||
if (process.env.CI === 'true') { | ||
chalk.level = 0; | ||
} | ||
|
||
class CLIOutput { | ||
private readonly NX_PREFIX = `${chalk.cyan( | ||
'>' | ||
)} ${chalk.reset.inverse.bold.cyan(' NX ')}`; | ||
/** | ||
* Longer dash character which forms more of a continuous line when place side to side | ||
* with itself, unlike the standard dash character | ||
*/ | ||
private readonly VERTICAL_SEPARATOR = | ||
'———————————————————————————————————————————————'; | ||
|
||
/** | ||
* Expose some color and other utility functions so that other parts of the codebase that need | ||
* more fine-grained control of message bodies are still using a centralized | ||
* implementation. | ||
*/ | ||
colors = { | ||
gray: chalk.gray | ||
}; | ||
bold = chalk.bold; | ||
underline = chalk.underline; | ||
|
||
private writeToStdOut(str: string) { | ||
process.stdout.write(str); | ||
} | ||
|
||
private writeOutputTitle({ | ||
label, | ||
title | ||
}: { | ||
label?: string; | ||
title: string; | ||
}): void { | ||
let outputTitle: string; | ||
if (label) { | ||
outputTitle = `${this.NX_PREFIX} ${label} ${title}\n`; | ||
} else { | ||
outputTitle = `${this.NX_PREFIX} ${title}\n`; | ||
} | ||
this.writeToStdOut(outputTitle); | ||
} | ||
|
||
private writeOptionalOutputBody(bodyLines?: string[]): void { | ||
if (!bodyLines) { | ||
return; | ||
} | ||
this.addNewline(); | ||
bodyLines.forEach(bodyLine => this.writeToStdOut(' ' + bodyLine + '\n')); | ||
} | ||
|
||
addNewline() { | ||
this.writeToStdOut('\n'); | ||
} | ||
|
||
addVerticalSeparator() { | ||
this.writeToStdOut(`\n${chalk.gray(this.VERTICAL_SEPARATOR)}\n\n`); | ||
} | ||
|
||
error({ title, slug, bodyLines }: CLIErrorMessageConfig) { | ||
this.addNewline(); | ||
|
||
this.writeOutputTitle({ | ||
label: chalk.reset.inverse.bold.red(' ERROR '), | ||
title: chalk.bold.red(title) | ||
}); | ||
|
||
this.writeOptionalOutputBody(bodyLines); | ||
|
||
/** | ||
* Optional slug to be used in an Nx error message redirect URL | ||
*/ | ||
if (slug && typeof slug === 'string') { | ||
this.addNewline(); | ||
this.writeToStdOut( | ||
chalk.grey(' ' + 'Learn more about this error: ') + | ||
'https://errors.nx.dev/' + | ||
slug + | ||
'\n' | ||
); | ||
} | ||
|
||
this.addNewline(); | ||
} | ||
|
||
warn({ title, slug, bodyLines }: CLIWarnMessageConfig) { | ||
this.addNewline(); | ||
|
||
this.writeOutputTitle({ | ||
label: chalk.reset.inverse.bold.yellow(' WARNING '), | ||
title: chalk.bold.yellow(title) | ||
}); | ||
|
||
this.writeOptionalOutputBody(bodyLines); | ||
|
||
/** | ||
* Optional slug to be used in an Nx warning message redirect URL | ||
*/ | ||
if (slug && typeof slug === 'string') { | ||
this.addNewline(); | ||
this.writeToStdOut( | ||
chalk.grey(' ' + 'Learn more about this warning: ') + | ||
'https://errors.nx.dev/' + | ||
slug + | ||
'\n' | ||
); | ||
} | ||
|
||
this.addNewline(); | ||
} | ||
|
||
note({ title, bodyLines }: CLINoteMessageConfig) { | ||
this.addNewline(); | ||
|
||
this.writeOutputTitle({ | ||
label: chalk.reset.inverse.bold.keyword('orange')(' NOTE '), | ||
title: chalk.bold.keyword('orange')(title) | ||
}); | ||
|
||
this.writeOptionalOutputBody(bodyLines); | ||
|
||
this.addNewline(); | ||
} | ||
|
||
success({ title }: CLISuccessMessageConfig) { | ||
this.addNewline(); | ||
|
||
this.writeOutputTitle({ | ||
label: chalk.reset.inverse.bold.green(' SUCCESS '), | ||
title: chalk.bold.green(title) | ||
}); | ||
|
||
this.addNewline(); | ||
} | ||
|
||
logSingleLine(message: string) { | ||
this.addNewline(); | ||
|
||
this.writeOutputTitle({ | ||
title: message | ||
}); | ||
|
||
this.addNewline(); | ||
} | ||
|
||
log({ title, bodyLines }: CLIWarnMessageConfig) { | ||
this.addNewline(); | ||
|
||
this.writeOutputTitle({ | ||
title: chalk.white(title) | ||
}); | ||
|
||
this.writeOptionalOutputBody(bodyLines); | ||
|
||
this.addNewline(); | ||
} | ||
} | ||
|
||
export const output = new CLIOutput(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface Workspace { | ||
type: 'nx' | 'angular'; | ||
dir: string; | ||
} |
Oops, something went wrong.