Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert create-cli.js (gatsby-cli) to TypeScript #23650

Merged
merged 4 commits into from
May 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion integration-tests/gatsby-cli/__tests__/develop.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe(`gatsby develop`, () => {
const [childProcess, getLogs] = GatsbyCLI.from(cwd).invokeAsync(`develop`)

// 2. Wait for the build process to finish
await timeout(10)
await timeout(15)

// 3. kill the `gatsby develop` command so we can get logs
childProcess.kill()
Expand Down
3 changes: 2 additions & 1 deletion packages/gatsby-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"prompts": "^2.3.2",
"react": "^16.8.0",
"redux": "^4.0.5",
"resolve-cwd": "^2.0.0",
"resolve-cwd": "^3.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just so there is paper trail (not something to act on):
Breaking changes in 2->3 ( from https://github.com/sindresorhus/resolve-cwd/releases/tag/v3.0.0 )

Breaking:

- Require Node.js 8
- Return undefined instead of null when the module can't be found when using resolveCwd.silent()

Both are good and don't require any changes from us - we already require node 10 and resolveCwd.silent() change doesn't impact us because we just check for falsiness and not concrete values (and both undefined and null are falsy)

"semver": "^6.3.0",
"signal-exit": "^3.0.3",
"source-map": "0.7.3",
Expand All @@ -55,6 +55,7 @@
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.6",
"@types/hosted-git-info": "^3.0.0",
"@types/yargs": "^15.0.4",
"babel-preset-gatsby-package": "^0.4.1",
"cross-env": "^5.2.1"
},
Expand Down
12 changes: 6 additions & 6 deletions packages/gatsby-cli/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ const getCLI = () => {
jest.resetModules()

const reporter = require(`../reporter`)
const createCLI = require(`../create-cli`)
const { createCli } = require(`../create-cli`)

require(`../`)

return {
reporter,
createCLI,
createCli,
}
}

Expand Down Expand Up @@ -79,10 +79,10 @@ describe(`normal behavior`, () => {
})
})

it(`invokes createCLI`, () => {
const { createCLI } = setup()
it(`invokes createCli`, () => {
const { createCli } = setup()

expect(createCLI).toHaveBeenCalledTimes(1)
expect(createCLI).toHaveBeenCalledWith(process.argv)
expect(createCli).toHaveBeenCalledTimes(1)
expect(createCli).toHaveBeenCalledWith(process.argv)
})
})
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
const path = require(`path`)
const resolveCwd = require(`resolve-cwd`)
const yargs = require(`yargs`)
const report = require(`./reporter`)
const { setStore } = require(`./reporter/redux`)
const { didYouMean } = require(`./did-you-mean`)
const { getLocalGatsbyVersion } = require(`./util/version`)
const envinfo = require(`envinfo`)
const existsSync = require(`fs-exists-cached`).sync
const clipboardy = require(`clipboardy`)
const {
trackCli,
setDefaultTags,
setTelemetryEnabled,
} = require(`gatsby-telemetry`)
const { recipesHandler } = require(`./recipes`)

const handlerP = fn => (...args) => {
import path from "path"
import resolveCwd from "resolve-cwd"
import yargs from "yargs"
import report from "./reporter"
import { setStore } from "./reporter/redux"
import { getLocalGatsbyVersion } from "./util/version"
import envinfo from "envinfo"
import { sync as existsSync } from "fs-exists-cached"
import clipboardy from "clipboardy"
import { trackCli, setDefaultTags, setTelemetryEnabled } from "gatsby-telemetry"
import { initStarter } from "./init-starter"
import { recipesHandler } from "./recipes"

const handlerP = (fn: Function) => (...args: unknown[]): void => {
Promise.resolve(fn(...args)).then(
() => process.exit(0),
err => report.panic(err)
)
}

function buildLocalCommands(cli, isLocalSite) {
function buildLocalCommands(cli: yargs.Argv, isLocalSite: boolean): void {
const defaultHost = `localhost`
const defaultPort = `8000`
const directory = path.resolve(`.`)
Expand All @@ -33,25 +29,30 @@ function buildLocalCommands(cli, isLocalSite) {
? [`> 1%`, `last 2 versions`, `IE >= 9`]
: [`>0.25%`, `not dead`]

const siteInfo = { directory, browserslist: DEFAULT_BROWSERS }
const siteInfo = {
directory,
browserslist: DEFAULT_BROWSERS,
sitePackageJson: undefined,
}

const useYarn = existsSync(path.join(directory, `yarn.lock`))
if (isLocalSite) {
const json = require(path.join(directory, `package.json`))
siteInfo.sitePackageJson = json
siteInfo.browserslist = json.browserslist || siteInfo.browserslist
}

function getLocalGatsbyMajorVersion() {
let version = getLocalGatsbyVersion()
function getLocalGatsbyMajorVersion(): number | undefined {
const version = getLocalGatsbyVersion()

if (version) {
version = Number(version.split(`.`)[0])
return Number(version.split(`.`)[0])
}

return version
return undefined
}

function resolveLocalCommand(command) {
function resolveLocalCommand(command: string): Function | never {
if (!isLocalSite) {
cli.showHelp()
report.verbose(`current directory: ${directory}`)
Expand All @@ -73,7 +74,15 @@ function buildLocalCommands(cli, isLocalSite) {
)

report.verbose(`loading local command from: ${cmdPath}`)
return require(cmdPath)

const cmd = require(cmdPath)
if (cmd instanceof Function) {
return cmd
}

return report.panic(
`Handler for command "${command}" is not a function. Your Gatsby package might be corrupted, try reinstalling it and running the command again.`
)
} catch (err) {
cli.showHelp()
return report.panic(
Expand All @@ -83,11 +92,14 @@ function buildLocalCommands(cli, isLocalSite) {
}
}

function getCommandHandler(command, handler) {
return argv => {
function getCommandHandler(
command: string,
handler?: (args: yargs.Arguments, cmd: Function) => void
) {
return (argv: yargs.Arguments): void => {
report.setVerbose(!!argv.verbose)

report.setNoColor(argv.noColor || process.env.NO_COLOR)
report.setNoColor(!!(argv.noColor || process.env.NO_COLOR))

process.env.gatsby_log_level = argv.verbose ? `verbose` : `normal`
report.verbose(`set gatsby_log_level: "${process.env.gatsby_log_level}"`)
Expand All @@ -105,7 +117,7 @@ function buildLocalCommands(cli, isLocalSite) {

cli.command({
command: `develop`,
desc:
describe:
`Start development server. Watches files, rebuilds, and hot reloads ` +
`if something changes`,
builder: _ =>
Expand Down Expand Up @@ -160,20 +172,20 @@ function buildLocalCommands(cli, isLocalSite) {
describe: `Tracer configuration file (OpenTracing compatible). See https://gatsby.dev/tracing`,
}),
handler: handlerP(
getCommandHandler(`develop`, (args, cmd) => {
getCommandHandler(`develop`, (args: yargs.Arguments, cmd: Function) => {
process.env.NODE_ENV = process.env.NODE_ENV || `development`
cmd(args)
// Return an empty promise to prevent handlerP from exiting early.
// The development server shouldn't ever exit until the user directly
// kills it so this is fine.
return new Promise(resolve => {})
return new Promise(() => {})
})
),
})

cli.command({
command: `build`,
desc: `Build a Gatsby project.`,
describe: `Build a Gatsby project.`,
builder: _ =>
_.option(`prefix-paths`, {
type: `boolean`,
Expand Down Expand Up @@ -216,7 +228,7 @@ function buildLocalCommands(cli, isLocalSite) {
hidden: true,
}),
handler: handlerP(
getCommandHandler(`build`, (args, cmd) => {
getCommandHandler(`build`, (args: yargs.Arguments, cmd: Function) => {
process.env.NODE_ENV = `production`
return cmd(args)
})
Expand All @@ -225,7 +237,7 @@ function buildLocalCommands(cli, isLocalSite) {

cli.command({
command: `serve`,
desc: `Serve previously built Gatsby site.`,
describe: `Serve previously built Gatsby site.`,
builder: _ =>
_.option(`H`, {
alias: `host`,
Expand Down Expand Up @@ -257,15 +269,15 @@ function buildLocalCommands(cli, isLocalSite) {

cli.command({
command: `info`,
desc: `Get environment information for debugging and issue reporting`,
describe: `Get environment information for debugging and issue reporting`,
builder: _ =>
_.option(`C`, {
alias: `clipboard`,
type: `boolean`,
default: false,
describe: `Automagically copy environment information to clipboard`,
}),
handler: args => {
handler: (args: yargs.Arguments) => {
try {
const copyToClipboard =
// Clipboard is not accessible when on a linux tty
Expand Down Expand Up @@ -311,27 +323,38 @@ function buildLocalCommands(cli, isLocalSite) {

cli.command({
command: `clean`,
desc: `Wipe the local gatsby environment including built assets and cache`,
describe: `Wipe the local gatsby environment including built assets and cache`,
handler: getCommandHandler(`clean`),
})

cli.command({
command: `repl`,
desc: `Get a node repl with context of Gatsby environment, see (https://www.gatsbyjs.org/docs/gatsby-repl/)`,
handler: getCommandHandler(`repl`, (args, cmd) => {
process.env.NODE_ENV = process.env.NODE_ENV || `development`
return cmd(args)
}),
describe: `Get a node repl with context of Gatsby environment, see (https://www.gatsbyjs.org/docs/gatsby-repl/)`,
handler: getCommandHandler(
`repl`,
(args: yargs.Arguments, cmd: Function) => {
process.env.NODE_ENV = process.env.NODE_ENV || `development`
return cmd(args)
}
),
})

cli.command({
command: `recipes [recipe]`,
desc: `[EXPERIMENTAL] Run a recipe`,
handler: handlerP(({ recipe }) => recipesHandler(recipe)),
describe: `[EXPERIMENTAL] Run a recipe`,
handler: handlerP(({ recipe }: yargs.Arguments) => {
if (typeof recipe !== `string`) {
throw new Error(
`Error: gatsby recipes needs to be called with a specific recipe`
)
}

recipesHandler(recipe)
}),
})
}

function isLocalGatsbySite() {
function isLocalGatsbySite(): boolean {
let inGatsbySite = false
try {
const { dependencies, devDependencies } = require(path.resolve(
Expand All @@ -346,7 +369,7 @@ function isLocalGatsbySite() {
return !!inGatsbySite
}

function getVersionInfo() {
function getVersionInfo(): string {
const { version } = require(`../package.json`)
const isGatsbySite = isLocalGatsbySite()
if (isGatsbySite) {
Expand All @@ -365,10 +388,11 @@ Gatsby version: ${gatsbyVersion}
}
}

module.exports = argv => {
const cli = yargs().parserConfiguration({
export const createCli = (argv: string[]): yargs.Arguments => {
const cli = yargs(argv).parserConfiguration({
"boolean-negation": false,
})

const isLocalSite = isLocalGatsbySite()

cli
Expand Down Expand Up @@ -415,17 +439,19 @@ module.exports = argv => {
return cli
.command({
command: `new [rootPath] [starter]`,
desc: `Create new Gatsby project.`,
handler: handlerP(({ rootPath, starter }) => {
const { initStarter } = require(`./init-starter`)
return initStarter(starter, { rootPath })
describe: `Create new Gatsby project.`,
handler: handlerP(async ({ rootPath, starter }) => {
const starterStr = starter ? String(starter) : undefined
const rootPathStr = rootPath ? String(rootPath) : undefined

await initStarter(starterStr, rootPathStr)
}),
})
.command(`plugin`, `Useful commands relating to Gatsby plugins`, yargs =>
yargs
.command({
command: `docs`,
desc: `Helpful info about using and creating plugins`,
describe: `Helpful info about using and creating plugins`,
handler: handlerP(() =>
console.log(`
Using a plugin:
Expand Down Expand Up @@ -456,7 +482,7 @@ Creating a plugin:
)
.command({
command: `telemetry`,
desc: `Enable or disable Gatsby anonymous analytics collection.`,
describe: `Enable or disable Gatsby anonymous analytics collection.`,
builder: yargs =>
yargs
.option(`enable`, {
Expand All @@ -468,7 +494,7 @@ Creating a plugin:
description: `Disable telemetry`,
}),

handler: handlerP(({ enable, disable }) => {
handler: handlerP(({ enable, disable }: yargs.Arguments) => {
const enabled = enable || !disable
setTelemetryEnabled(enabled)
report.log(`Telemetry collection ${enabled ? `enabled` : `disabled`}`)
Expand All @@ -477,17 +503,6 @@ Creating a plugin:
.wrap(cli.terminalWidth())
.demandCommand(1, `Pass --help to see all available commands and options.`)
.strict()
.fail((msg, err, yargs) => {
const availableCommands = yargs.getCommands().map(commandDescription => {
const [command] = commandDescription
return command.split(` `)[0]
})
const arg = argv.slice(2)[0]
const suggestion = arg ? didYouMean(arg, availableCommands) : ``

cli.showHelp()
report.log(suggestion)
report.log(msg)
})
.recommendCommands()
.parse(argv.slice(2))
}
20 changes: 0 additions & 20 deletions packages/gatsby-cli/src/did-you-mean.ts

This file was deleted.

Loading