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