Adds publish/subscribe pattern to allow plugins and projects to hook into events (#55)
Also adds CLI to ease development.
This commit is contained in:
1 parent
6a78df1ecd
commit
4c2aec2838
39 files changed
+6974
-444
No files matched your search
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"plugins": ["@babel/plugin-proposal-class-properties"],
|
||||
"presets": ["@babel/preset-env"],
|
||||
"env": {
|
||||
"test": {
|
||||
"plugins": ["@babel/plugin-transform-runtime"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"plugins": ["prettier"],
|
||||
"extends": ["prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"semi": "error",
|
||||
"no-unused-expressions": "true"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
dist/
|
||||
node_modules/
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"endOfLine": "lf",
|
||||
"semi": false,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "medusa-cli",
|
||||
"version": "0.1.0",
|
||||
"description": "Command Line interface for Medusa Commerce",
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
"medusa": "dist/index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa",
|
||||
"directory": "packages/medusa-cli"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "babel src --out-dir dist/ --ignore **/__tests__",
|
||||
"prepare": "cross-env NODE_ENV=production npm run build",
|
||||
"watch": "babel -w src --out-dir dist/ --ignore **/__tests__"
|
||||
},
|
||||
"author": "Sebastian Rindom",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.7.5",
|
||||
"@babel/core": "^7.7.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.7.4",
|
||||
"@babel/plugin-transform-classes": "^7.9.5",
|
||||
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||
"@babel/preset-env": "^7.7.5",
|
||||
"cross-env": "^5.2.1",
|
||||
"eslint": "^6.8.0",
|
||||
"jest": "^25.5.2",
|
||||
"prettier": "^1.19.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.8.7",
|
||||
"@babel/runtime": "^7.9.6",
|
||||
"@hapi/joi": "^16.1.8",
|
||||
"chalk": "^4.0.0",
|
||||
"clipboardy": "^2.3.0",
|
||||
"core-js": "^3.6.5",
|
||||
"fs-exists-cached": "^1.0.0",
|
||||
"joi-objectid": "^3.0.1",
|
||||
"meant": "^1.0.1",
|
||||
"medusa-core-utils": "^0.1.27",
|
||||
"regenerator-runtime": "^0.13.5",
|
||||
"resolve-cwd": "^3.0.0",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"gitHead": "35e0930650d5f4aedf2610749cd131ae8b7e17cc"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
const chalk = require(`chalk`)
|
||||
|
||||
const showSuccessMessage = () => {
|
||||
console.log(chalk.green(`Success!\n`))
|
||||
console.log(chalk.cyan(`Welcome to the Medusa CLI!`))
|
||||
}
|
||||
|
||||
try {
|
||||
// check if it's a global installation of medusa-cli
|
||||
const npmArgs = JSON.parse(process.env[`npm_config_argv`])
|
||||
if (npmArgs.cooked && npmArgs.cooked.includes(`--global`)) {
|
||||
const createCli = require(`../dist/create-cli`)
|
||||
showSuccessMessage()
|
||||
createCli(`--help`)
|
||||
}
|
||||
} catch (e) {}
|
||||
@@ -0,0 +1,238 @@
|
||||
const path = require(`path`)
|
||||
const resolveCwd = require(`resolve-cwd`)
|
||||
const yargs = require(`yargs`)
|
||||
const { getLocalMedusaVersion } = require(`./util/version`)
|
||||
const { didYouMean } = require(`./did-you-mean`)
|
||||
const envinfo = require(`envinfo`)
|
||||
const existsSync = require(`fs-exists-cached`).sync
|
||||
const clipboardy = require(`clipboardy`)
|
||||
|
||||
const handlerP = fn => (...args) => {
|
||||
Promise.resolve(fn(...args)).then(
|
||||
() => process.exit(0),
|
||||
err => console.log(err)
|
||||
)
|
||||
}
|
||||
|
||||
function buildLocalCommands(cli, isLocalProject) {
|
||||
const defaultHost = `localhost`
|
||||
const defaultPort = `9000`
|
||||
const directory = path.resolve(`.`)
|
||||
|
||||
const projectInfo = { directory }
|
||||
const useYarn = existsSync(path.join(directory, `yarn.lock`))
|
||||
|
||||
if (isLocalProject) {
|
||||
const json = require(path.join(directory, `package.json`))
|
||||
projectInfo.sitePackageJson = json
|
||||
}
|
||||
|
||||
function getLocalMedusaMajorVersion() {
|
||||
let version = getLocalMedusaVersion()
|
||||
|
||||
if (version) {
|
||||
version = Number(version.split(`.`)[0])
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
function resolveLocalCommand(command) {
|
||||
if (!isLocalProject) {
|
||||
cli.showHelp()
|
||||
}
|
||||
|
||||
try {
|
||||
const cmdPath = resolveCwd.silent(
|
||||
`@medusajs/medusa/dist/commands/${command}`
|
||||
)
|
||||
return require(cmdPath).default
|
||||
} catch (err) {
|
||||
cli.showHelp()
|
||||
}
|
||||
}
|
||||
|
||||
function getCommandHandler(command, handler) {
|
||||
return argv => {
|
||||
const localCmd = resolveLocalCommand(command)
|
||||
const args = { ...argv, ...projectInfo, useYarn }
|
||||
|
||||
// report.verbose(`running command: ${command}`)
|
||||
return handler ? handler(args, localCmd) : localCmd(args)
|
||||
}
|
||||
}
|
||||
|
||||
cli
|
||||
.command({
|
||||
command: `develop`,
|
||||
desc: `Start development server. Watches file and rebuilds when something changes`,
|
||||
builder: _ =>
|
||||
_.option(`H`, {
|
||||
alias: `host`,
|
||||
type: `string`,
|
||||
default: defaultHost,
|
||||
describe: `Set host. Defaults to ${defaultHost}`,
|
||||
}).option(`p`, {
|
||||
alias: `port`,
|
||||
type: `string`,
|
||||
default: process.env.PORT || defaultPort,
|
||||
describe: process.env.PORT
|
||||
? `Set port. Defaults to ${process.env.PORT} (set by env.PORT) (otherwise defaults ${defaultPort})`
|
||||
: `Set port. Defaults to ${defaultPort}`,
|
||||
}),
|
||||
handler: handlerP(
|
||||
getCommandHandler(`develop`, (args, cmd) => {
|
||||
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 => {})
|
||||
})
|
||||
),
|
||||
})
|
||||
.command({
|
||||
command: `start`,
|
||||
desc: `Start development server.`,
|
||||
builder: _ =>
|
||||
_.option(`H`, {
|
||||
alias: `host`,
|
||||
type: `string`,
|
||||
default: defaultHost,
|
||||
describe: `Set host. Defaults to ${defaultHost}`,
|
||||
}).option(`p`, {
|
||||
alias: `port`,
|
||||
type: `string`,
|
||||
default: process.env.PORT || defaultPort,
|
||||
describe: process.env.PORT
|
||||
? `Set port. Defaults to ${process.env.PORT} (set by env.PORT) (otherwise defaults ${defaultPort})`
|
||||
: `Set port. Defaults to ${defaultPort}`,
|
||||
}),
|
||||
handler: handlerP(
|
||||
getCommandHandler(`start`, (args, cmd) => {
|
||||
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 => {})
|
||||
})
|
||||
),
|
||||
})
|
||||
.command({
|
||||
command: `user`,
|
||||
desc: `Create a user`,
|
||||
builder: _ =>
|
||||
_.option(`e`, {
|
||||
alias: `email`,
|
||||
type: `string`,
|
||||
describe: `User's email.`,
|
||||
}).option(`p`, {
|
||||
alias: `password`,
|
||||
type: `string`,
|
||||
describe: `User's password.`,
|
||||
}),
|
||||
handler: handlerP(
|
||||
getCommandHandler(`user`, (args, cmd) => {
|
||||
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 => {})
|
||||
})
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
function isLocalMedusaProject() {
|
||||
let inMedusaProject = false
|
||||
try {
|
||||
const { dependencies, devDependencies } = require(path.resolve(
|
||||
`./package.json`
|
||||
))
|
||||
inMedusaProject =
|
||||
(dependencies && dependencies["@medusajs/medusa"]) ||
|
||||
(devDependencies && devDependencies["@medusajs/medusa"])
|
||||
} catch (err) {
|
||||
/* ignore */
|
||||
}
|
||||
return !!inMedusaProject
|
||||
}
|
||||
|
||||
function getVersionInfo() {
|
||||
const { version } = require(`../package.json`)
|
||||
const isMedusaProject = isLocalMedusaProject()
|
||||
if (isMedusaProject) {
|
||||
let medusaVersion = getLocalMedusaVersion()
|
||||
|
||||
if (!medusaVersion) {
|
||||
medusaVersion = `unknown`
|
||||
}
|
||||
|
||||
return `Medusa CLI version: ${version}
|
||||
Medusa version: ${medusaVersion}
|
||||
Note: this is the Medusa version for the site at: ${process.cwd()}`
|
||||
} else {
|
||||
return `Medusa CLI version: ${version}`
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = argv => {
|
||||
const cli = yargs()
|
||||
const isLocalProject = isLocalMedusaProject()
|
||||
|
||||
cli
|
||||
.scriptName(`medusa`)
|
||||
.usage(`Usage: $0 <command> [options]`)
|
||||
.alias(`h`, `help`)
|
||||
.alias(`v`, `version`)
|
||||
.option(`verbose`, {
|
||||
default: false,
|
||||
type: `boolean`,
|
||||
describe: `Turn on verbose output`,
|
||||
global: true,
|
||||
})
|
||||
.option(`no-color`, {
|
||||
alias: `no-colors`,
|
||||
default: false,
|
||||
type: `boolean`,
|
||||
describe: `Turn off the color in output`,
|
||||
global: true,
|
||||
})
|
||||
.option(`json`, {
|
||||
describe: `Turn on the JSON logger`,
|
||||
default: false,
|
||||
type: `boolean`,
|
||||
global: true,
|
||||
})
|
||||
|
||||
buildLocalCommands(cli, isLocalProject)
|
||||
|
||||
try {
|
||||
cli.version(
|
||||
`version`,
|
||||
`Show the version of the Medusa CLI and the Medusa package in the current project`,
|
||||
getVersionInfo()
|
||||
)
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return cli
|
||||
.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)
|
||||
})
|
||||
.parse(argv.slice(2))
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import meant from "meant"
|
||||
|
||||
export function didYouMean(scmd, commands) {
|
||||
const bestSimilarity = meant(scmd, commands).map(str => {
|
||||
return ` ${str}`
|
||||
})
|
||||
|
||||
if (bestSimilarity.length === 0) return ``
|
||||
if (bestSimilarity.length === 1) {
|
||||
return `\nDid you mean this?\n ${bestSimilarity[0]}\n`
|
||||
} else {
|
||||
return (
|
||||
[`\nDid you mean one of these?`]
|
||||
.concat(bestSimilarity.slice(0, 3))
|
||||
.join(`\n`) + `\n`
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import "core-js/stable"
|
||||
import "regenerator-runtime/runtime"
|
||||
import os from "os"
|
||||
import semver from "semver"
|
||||
import util from "util"
|
||||
import createCli from "./create-cli"
|
||||
// import report from "./reporter"
|
||||
import pkg from "../package.json"
|
||||
// import updateNotifier from "update-notifier"
|
||||
// import { ensureWindowsDriveLetterIsUppercase } from "./util/ensure-windows-drive-letter-is-uppercase"
|
||||
|
||||
const useJsonLogger = process.argv.slice(2).some(arg => arg.includes(`json`))
|
||||
|
||||
if (useJsonLogger) {
|
||||
process.env.GATSBY_LOGGER = `json`
|
||||
}
|
||||
|
||||
// Ensure stable runs on Windows when started from different shells (i.e. c:\dir vs C:\dir)
|
||||
if (os.platform() === `win32`) {
|
||||
// ensureWindowsDriveLetterIsUppercase()
|
||||
}
|
||||
|
||||
// Check if update is available
|
||||
// updateNotifier({ pkg }).notify({ isGlobal: true })
|
||||
|
||||
const MIN_NODE_VERSION = `10.13.0`
|
||||
// const NEXT_MIN_NODE_VERSION = `10.13.0`
|
||||
|
||||
if (!semver.satisfies(process.version, `>=${MIN_NODE_VERSION}`)) {
|
||||
//report.panic(
|
||||
// report.stripIndent(`
|
||||
// Gatsby requires Node.js ${MIN_NODE_VERSION} or higher (you have ${process.version}).
|
||||
// Upgrade Node to the latest stable release: https://gatsby.dev/upgrading-node-js
|
||||
// `)
|
||||
//)
|
||||
}
|
||||
|
||||
// if (!semver.satisfies(process.version, `>=${NEXT_MIN_NODE_VERSION}`)) {
|
||||
// report.warn(
|
||||
// report.stripIndent(`
|
||||
// Node.js ${process.version} has reached End of Life status on 31 December, 2019.
|
||||
// Gatsby will only actively support ${NEXT_MIN_NODE_VERSION} or higher and drop support for Node 8 soon.
|
||||
// Please upgrade Node.js to a currently active LTS release: https://gatsby.dev/upgrading-node-js
|
||||
// `)
|
||||
// )
|
||||
// }
|
||||
|
||||
process.on(`unhandledRejection`, reason => {
|
||||
// This will exit the process in newer Node anyway so lets be consistent
|
||||
// across versions and crash
|
||||
|
||||
// reason can be anything, it can be a message, an object, ANYTHING!
|
||||
// we convert it to an error object so we don't crash on structured error validation
|
||||
if (!(reason instanceof Error)) {
|
||||
reason = new Error(util.format(reason))
|
||||
}
|
||||
|
||||
console.log(reason)
|
||||
// report.panic(`UNHANDLED REJECTION`, reason as Error)
|
||||
})
|
||||
|
||||
process.on(`uncaughtException`, error => {
|
||||
console.log(error)
|
||||
// report.panic(`UNHANDLED EXCEPTION`, error)
|
||||
})
|
||||
|
||||
createCli(process.argv)
|
||||
@@ -0,0 +1,6 @@
|
||||
import { getMedusaVersion } from "medusa-core-utils"
|
||||
|
||||
export const getLocalMedusaVersion = () => {
|
||||
const version = getMedusaVersion()
|
||||
return version
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user