-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
403 additions
and
81 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 |
---|---|---|
|
@@ -102,3 +102,6 @@ dist | |
|
||
# TernJS port file | ||
.tern-port | ||
|
||
# dist | ||
packages/**/lib/ |
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
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,5 @@ | ||
const EnvPrefix = `XUS_CLI` | ||
|
||
export function createEnvName(name: string): string { | ||
return `${EnvPrefix}_${name}` | ||
} |
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 * from './logger' | ||
export * from './module' | ||
export * from './validator' | ||
export * from './env' |
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 @@ | ||
type LoggerType = 'warn' | 'error' | 'info' | ||
|
||
function logger(type: LoggerType = 'info') { | ||
return function (msg: string): void { | ||
console[type](msg) | ||
} | ||
} | ||
|
||
export function warn(msg: string): void { | ||
logger('warn')(` | ||
[xus-cli Warning]: ${msg} | ||
`) | ||
} | ||
|
||
export function error(msg: string): void { | ||
logger('error')(` | ||
[xus-cli error]: ${msg} | ||
`) | ||
} | ||
|
||
export function info(msg: string): void { | ||
logger('info')(` | ||
[xus-cli info]: ${msg} | ||
`) | ||
} |
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,12 @@ | ||
export async function loadModule<T = any>( | ||
modulePath: string | ||
): Promise<[Error | null, T]> { | ||
let error: Error | null = null | ||
let moduleContent | ||
try { | ||
moduleContent = await import(modulePath) | ||
} catch (err) { | ||
error = err | ||
} | ||
return [error, moduleContent.default || null] | ||
} |
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 joi, { Root, ObjectSchema } from 'joi' | ||
|
||
type CreateFn<T = any> = (joi: Root) => ObjectSchema<T> | ||
|
||
export function createSchema<T = any>(fn: CreateFn<T>): ObjectSchema<T> { | ||
let schema = fn(joi) | ||
if (typeof schema === 'object' && typeof schema.validate !== 'function') { | ||
schema = joi.object(schema) | ||
} | ||
return schema | ||
} | ||
|
||
type ValidateCb = (message: string) => void | ||
|
||
export function validate( | ||
obj: Record<string, any>, | ||
schema: ObjectSchema, | ||
cb: ValidateCb | ||
): void { | ||
const { error } = schema.validate(obj) | ||
if (error) { | ||
cb(error.details[0].message) | ||
process.exit(1) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
|
@@ -28,6 +28,7 @@ | |
}, | ||
"dependencies": { | ||
"@types/minimist": "^1.2.1", | ||
"@xus/cli-shared-utils": "^0.0.1", | ||
"minimist": "^1.2.5" | ||
} | ||
} |
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,20 +1,69 @@ | ||
// types | ||
import { Commands, Args, RawArgs, Plugin } from './types' | ||
import { error } from '@xus/cli-shared-utils' | ||
import ConfigManager, { IConfigManager } from './manager/ConfigManager' | ||
import PathManager, { IPathManager } from './manager/PathManager' | ||
import EnvManager, { IEnvManager } from './manager/EnvManager' | ||
import PluginAPI from './PluginAPI' | ||
import { BuiltInPlugins } from './builtInPlugins' | ||
|
||
class Cli { | ||
ctxPath: string = process.cwd() | ||
constructor(ctxPath: string) { | ||
this.ctxPath = ctxPath | ||
private initialized = false | ||
plugins: Plugin[] = [] | ||
commands: Commands = {} | ||
// manager | ||
PathManager: IPathManager | ||
EnvManager: IEnvManager | ||
ConfigManager: IConfigManager | ||
|
||
constructor(context: string) { | ||
this.PathManager = new PathManager(context) | ||
this.EnvManager = new EnvManager(this.PathManager) | ||
this.ConfigManager = new ConfigManager(this.PathManager) | ||
|
||
this.plugins = this.resolvePlugins() | ||
} | ||
|
||
// 启动 cli | ||
async setupCli(): Promise<void> { | ||
if (this.initialized) return | ||
this.initialized = true | ||
// 1. load config | ||
await this.ConfigManager.loadUserConfig() | ||
// 2. apply plugins | ||
this.plugins.forEach(({ id, apply }) => { | ||
// some skip plugins ?? | ||
apply(new PluginAPI(id, this), this.ConfigManager.projectConfig) | ||
}) | ||
} | ||
|
||
resolvePlugins(): Plugin[] { | ||
// TODO: user install plugin | ||
return BuiltInPlugins | ||
} | ||
async run( | ||
commandName: string, | ||
args: { [key: string]: any }, | ||
rawArgs: any[] | ||
): Promise<any> { | ||
console.log(`command `, commandName) | ||
console.log(`args `, args) | ||
console.log(`rawArgs `, rawArgs) | ||
// 1. valid commandName (help) | ||
// 2. init cli (load plugin / config...) | ||
// 3. get compiler task run | ||
|
||
async run(commandName: string, args: Args, rawArgs: RawArgs): Promise<any> { | ||
// 1. setup | ||
await this.setupCli() | ||
|
||
// 2. get command task run | ||
const command = this.commands[commandName] || null | ||
if (!command) { | ||
error(` | ||
unknown command ${commandName} | ||
`) | ||
process.exit(1) | ||
} | ||
|
||
// remove command | ||
args._.shift() | ||
rawArgs.shift() | ||
|
||
const { fn } = command | ||
return fn(args, rawArgs) | ||
} | ||
} | ||
|
||
export type CliInstance = InstanceType<typeof Cli> | ||
|
||
export default Cli |
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,7 +1,51 @@ | ||
import { IConfigManager } from './manager/ConfigManager' | ||
import { IEnvManager } from './manager/EnvManager' | ||
import { CommandFn, CommandOps, Commands } from './types' | ||
import { IPathManager } from './manager/PathManager' | ||
import { CliInstance } from './Cli' | ||
|
||
class PluginAPI { | ||
constructor(public id: string, public service: any) {} | ||
id: string | ||
private service: CliInstance | ||
|
||
constructor(id: string, service: CliInstance) { | ||
this.id = id | ||
this.service = service | ||
} | ||
|
||
get PathManager(): IPathManager { | ||
return this.service.PathManager | ||
} | ||
|
||
get EnvManager(): IEnvManager { | ||
return this.service.EnvManager | ||
} | ||
|
||
get ConfigManager(): IConfigManager { | ||
return this.service.ConfigManager | ||
} | ||
|
||
// registerCommander(name: string, opt, fn) {} | ||
get commands(): Commands { | ||
return this.service.commands | ||
} | ||
|
||
registerCommand(name: string, fn: CommandFn): void | ||
registerCommand(name: string, ops: CommandOps, fn: CommandFn): void | ||
registerCommand(name: string, ops: any, fn?: any): void { | ||
if (typeof ops === 'function') { | ||
fn = ops | ||
ops = null | ||
} | ||
|
||
this.service.commands[name] = { | ||
fn, | ||
ops | ||
} | ||
} | ||
|
||
// registerConfigValidator(configName: string): void | ||
} | ||
|
||
export type IPluginAPI = InstanceType<typeof PluginAPI> | ||
|
||
export default PluginAPI |
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,8 @@ | ||
import { IPluginAPI } from '../../PluginAPI' | ||
|
||
export default function (api: IPluginAPI): void { | ||
api.registerCommand('help', (args) => { | ||
console.log(`args `, args) | ||
console.log(`all command `, Object.keys(api.commands)) | ||
}) | ||
} |
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,8 @@ | ||
import CHelp from './commands/help' | ||
|
||
export const BuiltInPlugins = [ | ||
{ | ||
id: 'built-in:commands/help', | ||
apply: CHelp | ||
} | ||
] |
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
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,44 @@ | ||
import { ProjectConfig } from '../types' | ||
import { loadModule } from '@xus/cli-shared-utils' | ||
import { IPathManager } from './PathManager' | ||
|
||
class ConfigManager { | ||
private PathManager: IPathManager | ||
|
||
private finalConfig: ProjectConfig = {} | ||
|
||
get projectConfig(): ProjectConfig { | ||
return this.finalConfig | ||
} | ||
|
||
constructor(pathManager: IPathManager) { | ||
this.PathManager = pathManager | ||
} | ||
|
||
async loadUserConfig(): Promise<void> { | ||
// 1. load userConfig | ||
let userConfig: ProjectConfig | ||
const [err, configContent] = await loadModule<ProjectConfig>( | ||
this.PathManager.userConfigPath | ||
) | ||
if (err) { | ||
userConfig = {} | ||
} | ||
userConfig = configContent | ||
// 2. merge default config | ||
// 3. valid | ||
|
||
this.finalConfig = userConfig | ||
} | ||
|
||
// for plugin | ||
async loadConfig<T = any>(configPath: string): Promise<T | null> { | ||
const [err, configContent] = await loadModule<T>(configPath) | ||
if (err) return null | ||
return configContent || null | ||
} | ||
} | ||
|
||
export type IConfigManager = InstanceType<typeof ConfigManager> | ||
|
||
export default ConfigManager |
Oops, something went wrong.