mirror of https://github.com/msgbyte/tailchat
refactor: move tailchat-cli into tailchat
parent
c057d2afc3
commit
160547a156
@ -0,0 +1,107 @@
|
|||||||
|
lib
|
||||||
|
plugins
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
@ -0,0 +1,2 @@
|
|||||||
|
# https://npmmirror.com/
|
||||||
|
registry = https://registry.npmmirror.com
|
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 MsgByte
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -0,0 +1,15 @@
|
|||||||
|
# tailchat-cli
|
||||||
|
A Command line interface of tailchat
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tailchat <command>
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
tailchat create [template] 创建 Tailchat 项目代码
|
||||||
|
tailchat connect 连接到 Tailchat 节点网络
|
||||||
|
tailchat declaration [source] Tailchat 插件类型声明
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--version Show version number [boolean]
|
||||||
|
-h, --help Show help [boolean]
|
||||||
|
```
|
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
require('../lib')
|
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"name": "tailchat-cli",
|
||||||
|
"version": "1.3.0",
|
||||||
|
"description": "A Command line interface of tailchat",
|
||||||
|
"bin": {
|
||||||
|
"tailchat": "./bin/cli"
|
||||||
|
},
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"types": "./lib/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"bin",
|
||||||
|
"templates"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"dev": "ts-node ./src/index.ts",
|
||||||
|
"build": "rm -rf lib && tsc",
|
||||||
|
"prepare": "npm run build",
|
||||||
|
"release": "npm publish --registry https://registry.npmjs.com/",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/msgbyte/tailchat-cli.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"tailchat"
|
||||||
|
],
|
||||||
|
"author": "moonrailgun",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/msgbyte/tailchat-cli/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/msgbyte/tailchat-cli#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^16.0.0",
|
||||||
|
"fs-extra": "^10.1.0",
|
||||||
|
"got": "11.8.5",
|
||||||
|
"inquirer": "^8.2.2",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"node-plop": "^0.26.3",
|
||||||
|
"ora": "5.4.1",
|
||||||
|
"plop": "^3.0.5",
|
||||||
|
"tailchat-server-sdk": "^0.0.12",
|
||||||
|
"yargs": "^17.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/fs-extra": "^9.0.13",
|
||||||
|
"@types/inquirer": "^8.2.1",
|
||||||
|
"@types/node": "16.11.7",
|
||||||
|
"@types/yargs": "^17.0.10",
|
||||||
|
"ts-node": "^10.7.0",
|
||||||
|
"typescript": "^4.6.3"
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
|||||||
|
import { CommandModule } from 'yargs';
|
||||||
|
import { TcBroker } from 'tailchat-server-sdk';
|
||||||
|
import defaultBrokerConfig from 'tailchat-server-sdk/dist/runner/moleculer.config';
|
||||||
|
import { config } from 'dotenv';
|
||||||
|
|
||||||
|
export const connectCommand: CommandModule = {
|
||||||
|
command: 'connect',
|
||||||
|
describe: '连接到 Tailchat 节点网络',
|
||||||
|
builder: undefined,
|
||||||
|
async handler(args) {
|
||||||
|
config();
|
||||||
|
|
||||||
|
const broker = new TcBroker({
|
||||||
|
...defaultBrokerConfig,
|
||||||
|
transporter: process.env.TRANSPORTER,
|
||||||
|
});
|
||||||
|
await broker.start();
|
||||||
|
broker.repl();
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,44 @@
|
|||||||
|
import { CommandModule } from 'yargs';
|
||||||
|
import nodePlop from 'node-plop';
|
||||||
|
import path from 'path';
|
||||||
|
import inquirer from 'inquirer';
|
||||||
|
|
||||||
|
const plop = nodePlop(path.resolve(__dirname, '../../templates/plopfile.js'));
|
||||||
|
|
||||||
|
export const createCommand: CommandModule = {
|
||||||
|
command: 'create [template]',
|
||||||
|
describe: '创建 Tailchat 项目代码',
|
||||||
|
builder: (yargs) =>
|
||||||
|
yargs.positional('template', {
|
||||||
|
demandOption: true,
|
||||||
|
description: '代码模板名',
|
||||||
|
type: 'string',
|
||||||
|
choices: plop.getGeneratorList().map((v) => v.name),
|
||||||
|
}),
|
||||||
|
async handler(args) {
|
||||||
|
let template: string;
|
||||||
|
|
||||||
|
if (!args.template) {
|
||||||
|
const res = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
name: 'template',
|
||||||
|
message: '选择代码模板',
|
||||||
|
choices: plop.getGeneratorList().map((v) => ({
|
||||||
|
name: `${v.name} (${v.description})`,
|
||||||
|
value: v.name,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
template = String(res.template);
|
||||||
|
} else {
|
||||||
|
template = String(args.template);
|
||||||
|
}
|
||||||
|
|
||||||
|
const basic = plop.getGenerator(template);
|
||||||
|
|
||||||
|
const answers = await basic.runPrompts();
|
||||||
|
const results = await basic.runActions(answers);
|
||||||
|
console.log('results', results);
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,65 @@
|
|||||||
|
import inquirer from 'inquirer';
|
||||||
|
import { CommandModule } from 'yargs';
|
||||||
|
import fs, { mkdirp } from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import ora from 'ora';
|
||||||
|
import got from 'got';
|
||||||
|
|
||||||
|
export const declarationCommand: CommandModule = {
|
||||||
|
command: 'declaration [source]',
|
||||||
|
describe: 'Tailchat 插件类型声明',
|
||||||
|
builder: (yargs) =>
|
||||||
|
yargs.positional('source', {
|
||||||
|
demandOption: true,
|
||||||
|
description: '声明类型来源',
|
||||||
|
type: 'string',
|
||||||
|
choices: ['empty', 'github'],
|
||||||
|
}),
|
||||||
|
async handler(args) {
|
||||||
|
let source = String(args.source);
|
||||||
|
|
||||||
|
if (!source) {
|
||||||
|
const res = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
name: 'source',
|
||||||
|
message: '选择类型来源',
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
name: '空',
|
||||||
|
value: 'empty',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '从 Github 下载完整声明',
|
||||||
|
value: 'github',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
source = String(res.source);
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = '';
|
||||||
|
if (source === 'empty') {
|
||||||
|
content =
|
||||||
|
"declare module '@capital/common';\ndeclare module '@capital/component';\n";
|
||||||
|
} else if (source === 'github') {
|
||||||
|
const spinner = ora('正在从 Github 下载插件类型声明').start();
|
||||||
|
|
||||||
|
content = await got
|
||||||
|
.get(
|
||||||
|
'https://raw.githubusercontent.com/msgbyte/tailchat/master/web/tailchat.d.ts'
|
||||||
|
)
|
||||||
|
.then((res) => res.body);
|
||||||
|
|
||||||
|
spinner.succeed('声明文件下载完毕');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content !== '') {
|
||||||
|
const target = path.resolve(process.cwd(), './types/tailchat.d.ts');
|
||||||
|
await mkdirp(path.dirname(target));
|
||||||
|
await fs.writeFile(target, content);
|
||||||
|
console.log('写入类型文件完毕:', target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,13 @@
|
|||||||
|
import yargs from 'yargs';
|
||||||
|
import { createCommand } from './commands/create';
|
||||||
|
import { connectCommand } from './commands/connect';
|
||||||
|
import { declarationCommand } from './commands/declaration';
|
||||||
|
|
||||||
|
yargs
|
||||||
|
.demandCommand()
|
||||||
|
.command(createCommand)
|
||||||
|
.command(connectCommand)
|
||||||
|
.command(declarationCommand)
|
||||||
|
.alias('h', 'help')
|
||||||
|
.scriptName('tailchat')
|
||||||
|
.parse();
|
@ -0,0 +1,85 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const _ = require('lodash')
|
||||||
|
|
||||||
|
function pickPluginName(text) {
|
||||||
|
const [_1, _2, ...others] = text.split('.');
|
||||||
|
return others.join('-');
|
||||||
|
}
|
||||||
|
function upperFirst(text) {
|
||||||
|
return _.upperFirst(_.camelCase(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (
|
||||||
|
/** @type {import('plop').NodePlopAPI} */
|
||||||
|
plop
|
||||||
|
) {
|
||||||
|
plop.setHelper('pickPluginName', pickPluginName);
|
||||||
|
plop.setHelper('pickPluginNameUp', (text) => {
|
||||||
|
return upperFirst(pickPluginName(text));
|
||||||
|
});
|
||||||
|
|
||||||
|
const serverPrompts = [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'id',
|
||||||
|
require: true,
|
||||||
|
default: 'com.msgbyte.example',
|
||||||
|
message: '插件唯一id, 以反域名格式的唯一字符串',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'author',
|
||||||
|
message: '插件作者',
|
||||||
|
default: 'anonymous',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'desc',
|
||||||
|
message: '插件描述',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 服务端插件的前端模板代码
|
||||||
|
plop.setGenerator('server-plugin', {
|
||||||
|
description: '服务端插件模板代码',
|
||||||
|
prompts: serverPrompts,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'addMany',
|
||||||
|
destination: path.resolve(process.cwd(), './plugins'),
|
||||||
|
base: './server-plugin',
|
||||||
|
templateFiles: ['./server-plugin/**/*'],
|
||||||
|
skipIfExists: true,
|
||||||
|
globOptions: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 服务端插件的前端模板代码
|
||||||
|
plop.setGenerator('server-plugin-web', {
|
||||||
|
description: '服务端插件的前端模板代码',
|
||||||
|
prompts: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'name',
|
||||||
|
require: true,
|
||||||
|
message: '插件名称',
|
||||||
|
},
|
||||||
|
...serverPrompts,
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'addMany',
|
||||||
|
destination: path.resolve(process.cwd(), './plugins'),
|
||||||
|
base: './server-plugin-web',
|
||||||
|
templateFiles: [
|
||||||
|
'./server-plugin-web/**/*',
|
||||||
|
'./server-plugin-web/*/.ministarrc.js',
|
||||||
|
],
|
||||||
|
skipIfExists: true,
|
||||||
|
globOptions: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,7 @@
|
|||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
externalDeps: ['react'],
|
||||||
|
pluginRoot: path.resolve(__dirname, './web'),
|
||||||
|
outDir: path.resolve(__dirname, '../../public'),
|
||||||
|
};
|
@ -0,0 +1,20 @@
|
|||||||
|
import { db } from 'tailchat-server-sdk';
|
||||||
|
const { getModelForClass, prop, modelOptions, TimeStamps } = db;
|
||||||
|
|
||||||
|
@modelOptions({
|
||||||
|
options: {
|
||||||
|
customName: 'p_{{pickPluginName id}}',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export class {{pickPluginNameUp id}} extends TimeStamps implements db.Base {
|
||||||
|
_id: db.Types.ObjectId;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type {{pickPluginNameUp id}}Document = db.DocumentType<{{pickPluginNameUp id}}>;
|
||||||
|
|
||||||
|
const model = getModelForClass({{pickPluginNameUp id}});
|
||||||
|
|
||||||
|
export type {{pickPluginNameUp id}}Model = typeof model;
|
||||||
|
|
||||||
|
export default model;
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "tailchat-plugin-{{pickPluginName id}}",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "{{author}}",
|
||||||
|
"description": "{{desc}}",
|
||||||
|
"license": "MIT",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {},
|
||||||
|
"devDependencies": {},
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import { TcService, TcDbService } from 'tailchat-server-sdk';
|
||||||
|
import type { {{pickPluginNameUp id}}Document, {{pickPluginNameUp id}}Model } from '../models/{{pickPluginName id}}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务管理服务
|
||||||
|
*/
|
||||||
|
interface {{pickPluginNameUp id}}Service
|
||||||
|
extends TcService,
|
||||||
|
TcDbService<{{pickPluginNameUp id}}Document, {{pickPluginNameUp id}}Model> {}
|
||||||
|
class {{pickPluginNameUp id}}Service extends TcService {
|
||||||
|
get serviceName() {
|
||||||
|
return 'plugin:{{id}}';
|
||||||
|
}
|
||||||
|
|
||||||
|
onInit() {
|
||||||
|
this.registerLocalDb(require('../models/{{pickPluginName id}}').default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {{pickPluginNameUp id}}Service;
|
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "lib",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noEmit": false
|
||||||
|
},
|
||||||
|
"exclude": ["./templates"]
|
||||||
|
}
|
Loading…
Reference in New Issue