Init: Create & Init ms Project...
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
commit
05bf312076
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
16
lerna.json
Normal file
16
lerna.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"version": "0.0.0",
|
||||||
|
"useWorkspaces": true,
|
||||||
|
"npmClient": "yarn",
|
||||||
|
"packages": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"command": {
|
||||||
|
"run": {
|
||||||
|
"stream": true
|
||||||
|
},
|
||||||
|
"publish": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm-hosted/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
package.json
Normal file
20
package.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "ms",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"clean": "npx lerna run clean",
|
||||||
|
"watch": "npx lerna run watch --parallel",
|
||||||
|
"build": "npx lerna run build",
|
||||||
|
"lp": "npx lerna publish"
|
||||||
|
},
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"lerna": "^3.16.4"
|
||||||
|
}
|
||||||
|
}
|
4
packages/api/.gitignore
vendored
Normal file
4
packages/api/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/package-lock.json
|
||||||
|
/yarn.lock
|
22
packages/api/.npmignore
Normal file
22
packages/api/.npmignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
typings
|
||||||
|
bundled
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
docs
|
||||||
|
wiki
|
||||||
|
gulpfile.js
|
||||||
|
bower.json
|
||||||
|
karma.conf.js
|
||||||
|
tsconfig.json
|
||||||
|
typings.json
|
||||||
|
CONTRIBUTING.md
|
||||||
|
ISSUE_TEMPLATE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
||||||
|
tslint.json
|
||||||
|
wallaby.js
|
||||||
|
.travis.yml
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
type_definitions
|
33
packages/api/package.json
Normal file
33
packages/api/package.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "@ms/api",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "MiaoScript api package",
|
||||||
|
"keywords": [
|
||||||
|
"miaoscript",
|
||||||
|
"minecraft",
|
||||||
|
"bukkit",
|
||||||
|
"sponge"
|
||||||
|
],
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"homepage": "https://github.com/circlecloud/ms.git",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm/"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"watch": "npx tsc --watch",
|
||||||
|
"build": "yarn clean && npx tsc",
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ms/common": "^0.0.0",
|
||||||
|
"inversify": "^5.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rimraf": "^3.0.0",
|
||||||
|
"typescript": "^3.6.2"
|
||||||
|
}
|
||||||
|
}
|
23
packages/api/src/command.ts
Normal file
23
packages/api/src/command.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { PluginInfo } from './typings/plugin';
|
||||||
|
export namespace command {
|
||||||
|
export abstract class Command {
|
||||||
|
on(plugin: PluginInfo, name: string, exec: { cmd: Function, tab?: Function }) {
|
||||||
|
var cmd = this.create(plugin, { name: name });
|
||||||
|
console.debug(`插件 ${plugin.description.name} 创建命令 ${name}(${cmd})...`)
|
||||||
|
if (exec.cmd && typeof exec.cmd === "function") {
|
||||||
|
this.onCommand(plugin, cmd, exec.cmd)
|
||||||
|
} else {
|
||||||
|
throw Error("CommandExec Must be a function... Input: " + exec.cmd)
|
||||||
|
}
|
||||||
|
if (exec.tab && typeof exec.tab === "function") {
|
||||||
|
this.onTabComplete(plugin, cmd, exec.tab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Create Server Command Object
|
||||||
|
*/
|
||||||
|
abstract create(plugin: object, opts: { name: string });
|
||||||
|
abstract onCommand(plugin: object, command: any, opts: { name: string });
|
||||||
|
abstract onTabComplete(plugin: object, command: any, opts: { name: string });
|
||||||
|
}
|
||||||
|
}
|
146
packages/api/src/console.ts
Normal file
146
packages/api/src/console.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
let Arrays = Java.type('java.util.Arrays');
|
||||||
|
let Level = Java.type('java.util.logging.Level');
|
||||||
|
let ignoreLogPrefix = ['java.', 'net.minecraft.', 'org.bukkit.', 'jdk.nashorn.'];
|
||||||
|
|
||||||
|
export class MiaoScriptConsole implements Console {
|
||||||
|
Console: NodeJS.ConsoleConstructor;
|
||||||
|
|
||||||
|
private _name: string = '';
|
||||||
|
private logger: any;
|
||||||
|
|
||||||
|
protected prefix: string = '§6[§bMiaoScript§6]§r ';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.logger = global.logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
set name(name: string) {
|
||||||
|
if (name) {
|
||||||
|
this._name = `[${name}] `;
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
this.prefix = `§6[§cMS§6][§b${name}§6]§r `;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log(...args): void {
|
||||||
|
this.logger.info(this.name + args.join(' '));
|
||||||
|
}
|
||||||
|
info(...args) {
|
||||||
|
this.logger.info(this.name + args.join(' '));
|
||||||
|
};
|
||||||
|
warn(...args) {
|
||||||
|
this.logger.warning(this.name + args.join(' '));
|
||||||
|
};
|
||||||
|
error(...args) {
|
||||||
|
this.logger.log(Level.SEVERE, this.name + args.join(' '));
|
||||||
|
};
|
||||||
|
debug(...args) {
|
||||||
|
if (global.debug) {
|
||||||
|
this.logger.info(this.name + '[DEBUG] ' + args.join(' '));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sender(...args) {
|
||||||
|
this.info(args)
|
||||||
|
}
|
||||||
|
console(...args) {
|
||||||
|
this.info(args)
|
||||||
|
}
|
||||||
|
object(obj) {
|
||||||
|
for (var i in obj) {
|
||||||
|
this.logger(i, '=>', obj[i])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ex(ex: Error) {
|
||||||
|
this.stack(ex).forEach(line => this.console(line))
|
||||||
|
};
|
||||||
|
stack(ex: Error | any): string[] {
|
||||||
|
var stack = ex.getStackTrace();
|
||||||
|
var cache = ['§4' + ex];
|
||||||
|
if (stack.class) {
|
||||||
|
stack = Arrays.asList(stack)
|
||||||
|
}
|
||||||
|
stack.forEach(function(trace) {
|
||||||
|
if (trace.className.startsWith('<')) {
|
||||||
|
var fileName = trace.fileName
|
||||||
|
fileName = fileName.indexOf('runtime') > -1 ? fileName.split('runtime')[1] : fileName;
|
||||||
|
cache.push(` §e->§c ${fileName} => §4${trace.methodName}:${trace.lineNumber}`)
|
||||||
|
} else {
|
||||||
|
var className = trace.className;
|
||||||
|
if (className.startsWith('jdk.nashorn.internal.scripts')) {
|
||||||
|
className = className.substr(className.lastIndexOf('$') + 1)
|
||||||
|
} else {
|
||||||
|
for (var prefix in ignoreLogPrefix) {
|
||||||
|
if (className.startsWith(ignoreLogPrefix[prefix])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache.push(` §e->§c ${className}.${trace.methodName}(§4${trace.fileName}:${trace.lineNumber}§c)`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
assert(value: any, message?: string, ...optionalParams: any[]): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
clear(): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
count(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
countReset(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
dir(obj: any, options?: NodeJS.InspectOptions): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
dirxml(...data: any[]): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
group(...label: any[]): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
groupCollapsed(...label: any[]): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
groupEnd(): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
table(tabularData: any, properties?: string[]): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
time(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
timeEnd(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
timeLog(label?: string, ...data: any[]): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
trace(message?: any, ...optionalParams: any[]): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
markTimeline(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
profile(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
profileEnd(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
timeStamp(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
timeline(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
timelineEnd(label?: string): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
}
|
154
packages/api/src/event.ts
Normal file
154
packages/api/src/event.ts
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
'use strict';
|
||||||
|
/**
|
||||||
|
* MiaoScript Event处理类
|
||||||
|
*/
|
||||||
|
import '@ms/core'
|
||||||
|
import '@ms/nashorn'
|
||||||
|
import { injectable } from 'inversify'
|
||||||
|
|
||||||
|
const Thread = Java.type("java.lang.Thread");
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
abstract class EventService {
|
||||||
|
private plugin;
|
||||||
|
private mapEvent = [];
|
||||||
|
private listenerMap = [];
|
||||||
|
private baseEventDir = '';
|
||||||
|
constructor(baseEventDir: string) {
|
||||||
|
this.baseEventDir = baseEventDir;
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 扫描包 org.bukkit.event 下的所有事件
|
||||||
|
* 映射简写名称 org.bukkit.event.player.PlayerLoginEvent => playerloginevent
|
||||||
|
*/
|
||||||
|
mapEventName() {
|
||||||
|
if (this.baseEventDir === "") {
|
||||||
|
throw new Error("事件基础包名为空 无法进行事件映射!");
|
||||||
|
}
|
||||||
|
var count = 0;
|
||||||
|
var dirs = Thread.currentThread().getContextClassLoader().getResources(this.baseEventDir);
|
||||||
|
while (dirs.hasMoreElements()) {
|
||||||
|
var url = dirs.nextElement();
|
||||||
|
var protocol = url.protocol;
|
||||||
|
if (protocol === "jar") {
|
||||||
|
// noinspection JSUnresolvedVariable
|
||||||
|
var jar = url.openConnection().jarFile;
|
||||||
|
var entries = jar.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
var entry = entries.nextElement();
|
||||||
|
var name = entry.name;
|
||||||
|
// 以 org/bukkit/event 开头 并且以 .class 结尾
|
||||||
|
if (name.startsWith(this.baseEventDir) && name.endsWith(".class")) {
|
||||||
|
var i = name.replaceAll('/', '.');
|
||||||
|
try {
|
||||||
|
var clz = base.getClass(i.substring(0, i.length - 6));
|
||||||
|
// 继承于 org.bukkit.event.Event 访问符为Public
|
||||||
|
if (this.isValidEvent(clz)) {
|
||||||
|
var simpleName = this.class2Name(clz).toLowerCase();
|
||||||
|
console.debug(`Mapping Event [${clz.canonicalName}] => ${simpleName}`);
|
||||||
|
this.mapEvent[simpleName] = clz;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
//ignore already loaded class
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
class2Name(clazz) {
|
||||||
|
return clazz.simpleName;
|
||||||
|
};
|
||||||
|
|
||||||
|
name2Class(name, event) {
|
||||||
|
var eventCls = this.mapEvent[event.toLowerCase()] || this.mapEvent[event.toLowerCase() + 'event'];
|
||||||
|
if (!eventCls) {
|
||||||
|
try {
|
||||||
|
eventCls = base.getClass(eventCls);
|
||||||
|
this.mapEvent[event] = eventCls;
|
||||||
|
} catch (ex) {
|
||||||
|
console.console(`§6插件 §b${name} §6注册事件 §c${event} §6失败 §4事件未找到!`);
|
||||||
|
console.ex(new Error(`插件 ${name} 注册事件 ${event} 失败 事件未找到!`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eventCls;
|
||||||
|
};
|
||||||
|
|
||||||
|
execute(name, exec, eventCls) {
|
||||||
|
return (...args) => {
|
||||||
|
try {
|
||||||
|
var time = new Date().getTime()
|
||||||
|
exec(args[args.length - 1]);
|
||||||
|
var cost = new Date().getTime() - time;
|
||||||
|
if (cost > 20) {
|
||||||
|
console.console(`§c注意! §6插件 §b${name} §6处理 §d${this.class2Name(eventCls)} §6事件 §c耗时 §4${cost}ms !`)
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
console.console(`§6插件 §b${name} §6处理 §d${this.class2Name(eventCls)} §6事件时发生异常 §4${ex}`);
|
||||||
|
console.ex(ex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加事件监听
|
||||||
|
* @param jsp
|
||||||
|
* @param event
|
||||||
|
* @param exec {function}
|
||||||
|
* @param priority [LOWEST,LOW,NORMAL,HIGH,HIGHEST,MONITOR]
|
||||||
|
* @param ignoreCancel
|
||||||
|
*/
|
||||||
|
listen(jsp, event, exec, priority, ignoreCancel) {
|
||||||
|
if (!jsp || !jsp.description || !jsp.description.name) throw new TypeError('插件名称为空 请检查传入参数!');
|
||||||
|
var name = jsp.description.name;
|
||||||
|
var eventCls = this.name2Class(name, event);
|
||||||
|
if (!eventCls) { return; }
|
||||||
|
if (typeof priority === 'boolean') {
|
||||||
|
ignoreCancel = priority;
|
||||||
|
priority = 'NORMAL';
|
||||||
|
}
|
||||||
|
priority = priority || 'NORMAL';
|
||||||
|
ignoreCancel = ignoreCancel || false;
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
var listener = this.register(eventCls, this.execute(name, exec, eventCls), priority, ignoreCancel);
|
||||||
|
var listenerMap = this.listenerMap;
|
||||||
|
// 添加到缓存 用于关闭插件的时候关闭事件
|
||||||
|
if (!listenerMap[name]) listenerMap[name] = [];
|
||||||
|
var offExec = () => {
|
||||||
|
this.unregister(eventCls, listener);
|
||||||
|
console.debug(`插件 ${name} 注销事件 ${this.class2Name(eventCls)}`);
|
||||||
|
};
|
||||||
|
var off = {
|
||||||
|
event: eventCls,
|
||||||
|
listener: listener,
|
||||||
|
off: offExec
|
||||||
|
};
|
||||||
|
listenerMap[name].push(off);
|
||||||
|
// noinspection JSUnresolvedVariable
|
||||||
|
console.debug(`插件 ${name} 注册事件 ${this.class2Name(eventCls)} => ${exec.name || '匿名方法'}`);
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract isValidEvent(clazz: any): boolean;
|
||||||
|
abstract register(eventCls: any, exec: Function, priority, ignoreCancel);
|
||||||
|
abstract unregister(event, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
var EventHandler = Object.assign(new EventHandler(), require('event'));
|
||||||
|
// 映射事件名称
|
||||||
|
console.info(`bukkit 事件映射完毕 共计 ${EventHandler.mapEventName().toFixed(0)} 个事件!`);
|
||||||
|
module.exports = {
|
||||||
|
on: EventHandler.listen.bind(EventHandler),
|
||||||
|
disable: function(jsp) {
|
||||||
|
var eventCache = EventHandler.listenerMap[jsp.description.name];
|
||||||
|
if (eventCache) {
|
||||||
|
eventCache.forEach(t => t.off());
|
||||||
|
delete EventHandler.listenerMap[jsp.description.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
5
packages/api/src/index.ts
Normal file
5
packages/api/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import './typings/global'
|
||||||
|
|
||||||
|
export * from './command'
|
||||||
|
export * from './interfaces'
|
||||||
|
export * from './console'
|
2
packages/api/src/interfaces/index.ts
Normal file
2
packages/api/src/interfaces/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './plugin'
|
||||||
|
export * from './server'
|
25
packages/api/src/interfaces/plugin.ts
Normal file
25
packages/api/src/interfaces/plugin.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Container } from "inversify";
|
||||||
|
|
||||||
|
export namespace plugin {
|
||||||
|
/**
|
||||||
|
* MiaoScript Plugin
|
||||||
|
*/
|
||||||
|
export const Plugin = Symbol("Plugin");
|
||||||
|
/**
|
||||||
|
* Runtime Plugin Instance
|
||||||
|
*/
|
||||||
|
export const PluginInstance = Symbol("PluginInstance");
|
||||||
|
/**
|
||||||
|
* MiaoScript Plugin Manager
|
||||||
|
*/
|
||||||
|
export const PluginManager = Symbol("PluginManager");
|
||||||
|
/**
|
||||||
|
* MiaoScript Plugin Manager
|
||||||
|
*/
|
||||||
|
export interface PluginManager {
|
||||||
|
scan(folder: string): void;
|
||||||
|
load(container: Container): void;
|
||||||
|
enable(): void;
|
||||||
|
disable(): void;
|
||||||
|
}
|
||||||
|
}
|
4
packages/api/src/interfaces/server.ts
Normal file
4
packages/api/src/interfaces/server.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export namespace server {
|
||||||
|
export const ServerType = Symbol("ServerType");
|
||||||
|
export const Console = Symbol("Console");
|
||||||
|
}
|
24
packages/api/src/typings/global.ts
Normal file
24
packages/api/src/typings/global.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
declare global {
|
||||||
|
namespace NodeJS {
|
||||||
|
interface Global {
|
||||||
|
logger: any;
|
||||||
|
debug: boolean;
|
||||||
|
noop: Function;
|
||||||
|
console: Console;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var root: string;
|
||||||
|
var base: Core;
|
||||||
|
var ScriptEngineContextHolder: any;
|
||||||
|
function engineLoad(str: string): any;
|
||||||
|
interface Core {
|
||||||
|
getClass(name: String);
|
||||||
|
}
|
||||||
|
interface Console {
|
||||||
|
ex(err: Error): void;
|
||||||
|
stack(err: Error): string[];
|
||||||
|
sender(...args: any): void;
|
||||||
|
console(...args: any): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export { }
|
13
packages/api/src/typings/plugin.ts
Normal file
13
packages/api/src/typings/plugin.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export interface CommandInfo {
|
||||||
|
aliases: string[];
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
export interface PluginInfo {
|
||||||
|
description: PluginDescription;
|
||||||
|
}
|
||||||
|
export interface PluginDescription {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
author: string;
|
||||||
|
commands: { [key: string]: CommandInfo };
|
||||||
|
}
|
7
packages/api/tsconfig.json
Normal file
7
packages/api/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist"
|
||||||
|
}
|
||||||
|
}
|
4
packages/bukkit/.gitignore
vendored
Normal file
4
packages/bukkit/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/package-lock.json
|
||||||
|
/yarn.lock
|
22
packages/bukkit/.npmignore
Normal file
22
packages/bukkit/.npmignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
typings
|
||||||
|
bundled
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
docs
|
||||||
|
wiki
|
||||||
|
gulpfile.js
|
||||||
|
bower.json
|
||||||
|
karma.conf.js
|
||||||
|
tsconfig.json
|
||||||
|
typings.json
|
||||||
|
CONTRIBUTING.md
|
||||||
|
ISSUE_TEMPLATE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
||||||
|
tslint.json
|
||||||
|
wallaby.js
|
||||||
|
.travis.yml
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
type_definitions
|
33
packages/bukkit/package.json
Normal file
33
packages/bukkit/package.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "@ms/bukkit",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "MiaoScript api package",
|
||||||
|
"keywords": [
|
||||||
|
"miaoscript",
|
||||||
|
"minecraft",
|
||||||
|
"bukkit",
|
||||||
|
"sponge"
|
||||||
|
],
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"homepage": "https://github.com/circlecloud/ms.git",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm/"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"watch": "npx tsc --watch",
|
||||||
|
"build": "yarn clean && npx tsc",
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rimraf": "^3.0.0",
|
||||||
|
"typescript": "^3.6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ms/api": "^0.0.0",
|
||||||
|
"inversify": "^5.0.1"
|
||||||
|
}
|
||||||
|
}
|
98
packages/bukkit/src/command.ts
Normal file
98
packages/bukkit/src/command.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import '@ms/nashorn'
|
||||||
|
|
||||||
|
import { injectable, postConstruct, inject } from 'inversify'
|
||||||
|
import { command } from '@ms/api'
|
||||||
|
import * as ref from '@ms/common/dist/reflect'
|
||||||
|
|
||||||
|
var bukkit = require('./server');
|
||||||
|
var plugin = bukkit.plugin.self;
|
||||||
|
var commandMap = ref.on(bukkit.plugin.manager).get('commandMap').get();
|
||||||
|
var PluginCommand = Java.type('org.bukkit.command.PluginCommand');
|
||||||
|
|
||||||
|
var Arrays = Java.type('java.util.Arrays');
|
||||||
|
var TabCompleter = Java.type("org.bukkit.command.TabCompleter");
|
||||||
|
var CommandExecutor = Java.type("org.bukkit.command.CommandExecutor");
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class BukkitCommand extends command.Command {
|
||||||
|
@inject("Plugin.Self")
|
||||||
|
private plugin: any
|
||||||
|
|
||||||
|
@postConstruct()
|
||||||
|
init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enable(jsp) {
|
||||||
|
var commands = jsp.description.commands;
|
||||||
|
if (commands) {
|
||||||
|
var pluginCommands = [];
|
||||||
|
for (var name in commands) {
|
||||||
|
// noinspection JSUnfilteredForInLoop
|
||||||
|
var command = commands[name];
|
||||||
|
if (typeof command !== 'object') continue;
|
||||||
|
command.name = name;
|
||||||
|
// noinspection JSUnfilteredForInLoop
|
||||||
|
var newCmd = this.create(jsp, command);
|
||||||
|
if (command.description) newCmd.setDescription(command.description);
|
||||||
|
if (command.usage) newCmd.setUsage(command.usage);
|
||||||
|
/** @namespace command.aliases */
|
||||||
|
if (command.aliases) newCmd.setAliases(Arrays.asList(command.aliases));
|
||||||
|
if (command.permission) newCmd.setPermission(command.permission);
|
||||||
|
if (command['permission-message']) newCmd.setPermissionMessage(command['permission-message']);
|
||||||
|
pluginCommands.push(newCmd);
|
||||||
|
// noinspection JSUnfilteredForInLoop
|
||||||
|
console.debug(`插件 ${jsp.description.name} 注册命令 ${name} ...`);
|
||||||
|
}
|
||||||
|
commandMap.registerAll(jsp.description.name, Arrays.asList(pluginCommands));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disable(jsp) {
|
||||||
|
var commands = jsp.description.commands;
|
||||||
|
if (commands) {
|
||||||
|
for (var name in commands) {
|
||||||
|
//TODO 删除插件命令
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create(jsp, command) {
|
||||||
|
var cmd = commandMap.getCommand(command.name)
|
||||||
|
if (cmd && cmd instanceof PluginCommand) { return cmd };
|
||||||
|
cmd = ref.on(PluginCommand).create(command.name, plugin).get();
|
||||||
|
commandMap.register(jsp.description.name, cmd);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCommand(jsp, c, cmd) {
|
||||||
|
// 必须指定需要实现的接口类型 否则MOD服会报错
|
||||||
|
c.setExecutor(new CommandExecutor({
|
||||||
|
onCommand: function(sender, _, command, args) {
|
||||||
|
try {
|
||||||
|
return cmd(sender, command, Java.from(args));
|
||||||
|
} catch (ex) {
|
||||||
|
console.console(`§6玩家 §a${sender.name} §6执行 §b${jsp.description.name} §6插件 §d${command} ${Java.from(args).join(' ')} §6命令时发生异常 §4${ex}`);
|
||||||
|
console.ex(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
onTabComplete(jsp, c, tab) {
|
||||||
|
// 必须指定需要实现的接口类型 否则MOD服会报错
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
c.setTabCompleter(new TabCompleter({
|
||||||
|
onTabComplete: function(sender, _, command, args) {
|
||||||
|
try {
|
||||||
|
var token = args[args.length - 1];
|
||||||
|
var complete = tab(sender, command, Java.from(args)) || [];
|
||||||
|
return Arrays.asList(complete.copyPartialMatches(token, []));
|
||||||
|
} catch (ex) {
|
||||||
|
console.console(`§6玩家 §a${sender.name} §6执行 §b${jsp.description.name} §6插件 §d${command} ${Java.from(args).join(' ')} §6补全时发生异常 §4${ex}`);
|
||||||
|
console.ex(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
21
packages/bukkit/src/console.ts
Normal file
21
packages/bukkit/src/console.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { MiaoScriptConsole } from '@ms/api'
|
||||||
|
|
||||||
|
let Bukkit = Java.type("org.bukkit.Bukkit");
|
||||||
|
let CommandSender = Java.type("org.bukkit.command.CommandSender");
|
||||||
|
|
||||||
|
export class BukkitConsole extends MiaoScriptConsole {
|
||||||
|
sender(sender, ...args) {
|
||||||
|
if (!(sender instanceof CommandSender)) {
|
||||||
|
this.error("第一个参数未实现 org.bukkit.command.CommandSender 无法发送消息!")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (args[0].toString() === "[object Array]") {
|
||||||
|
args[0].forEach(line => sender.sendMessage(this.prefix + line))
|
||||||
|
} else {
|
||||||
|
sender.sendMessage(this.prefix + args.join(' '));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console(...args): void {
|
||||||
|
this.sender(Bukkit.consoleSender, args.join(' '));
|
||||||
|
}
|
||||||
|
}
|
11
packages/bukkit/src/index.ts
Normal file
11
packages/bukkit/src/index.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { server, plugin } from '@ms/api'
|
||||||
|
import { DefaultContainer as container } from '@ms/container'
|
||||||
|
|
||||||
|
import { BukkitConsole } from './console'
|
||||||
|
|
||||||
|
let BukkitServerType = 'bukkit';
|
||||||
|
let Bukkit = Java.type("org.bukkit.Bukkit");
|
||||||
|
|
||||||
|
container.bind(server.Console).toConstantValue(BukkitConsole);
|
||||||
|
container.bind(server.ServerType).toConstantValue(BukkitServerType);
|
||||||
|
container.bind(plugin.PluginInstance).toConstantValue(Bukkit.pluginManager.getPlugin('MiaoScript'));
|
7
packages/bukkit/tsconfig.json
Normal file
7
packages/bukkit/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist"
|
||||||
|
}
|
||||||
|
}
|
4
packages/common/.gitignore
vendored
Normal file
4
packages/common/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/package-lock.json
|
||||||
|
/yarn.lock
|
22
packages/common/.npmignore
Normal file
22
packages/common/.npmignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
typings
|
||||||
|
bundled
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
docs
|
||||||
|
wiki
|
||||||
|
gulpfile.js
|
||||||
|
bower.json
|
||||||
|
karma.conf.js
|
||||||
|
tsconfig.json
|
||||||
|
typings.json
|
||||||
|
CONTRIBUTING.md
|
||||||
|
ISSUE_TEMPLATE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
||||||
|
tslint.json
|
||||||
|
wallaby.js
|
||||||
|
.travis.yml
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
type_definitions
|
32
packages/common/package.json
Normal file
32
packages/common/package.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "@ms/common",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "MiaoScript api package",
|
||||||
|
"keywords": [
|
||||||
|
"miaoscript",
|
||||||
|
"minecraft",
|
||||||
|
"bukkit",
|
||||||
|
"sponge"
|
||||||
|
],
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"homepage": "https://github.com/circlecloud/ms.git",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm/"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"watch": "npx tsc --watch",
|
||||||
|
"build": "yarn clean && npx tsc",
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rimraf": "^3.0.0",
|
||||||
|
"typescript": "^3.6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ms/nashorn": "^0.0.0"
|
||||||
|
}
|
||||||
|
}
|
155
packages/common/src/fs.ts
Normal file
155
packages/common/src/fs.ts
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import '@ms/nashorn'
|
||||||
|
|
||||||
|
/*global Java, base, module, exports, require, __FILE__*/
|
||||||
|
const Path = Java.type("java.nio.file.Path");
|
||||||
|
const JavaString = Java.type("java.lang.String");
|
||||||
|
const File = Java.type("java.io.File");
|
||||||
|
const Files = Java.type("java.nio.file.Files");
|
||||||
|
const Collector = Java.type("java.util.stream.Collector")
|
||||||
|
const separatorChar = File.separatorChar;
|
||||||
|
const StandardCopyOption = Java.type("java.nio.file.StandardCopyOption");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用文件分割符合并路径
|
||||||
|
*/
|
||||||
|
export function concat() {
|
||||||
|
return Array.prototype.join.call(arguments, separatorChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得文件
|
||||||
|
* @constructor(file)
|
||||||
|
* @constructor(dir,file)
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export function file(...opts: any[]): any {
|
||||||
|
if (!arguments[0]) {
|
||||||
|
console.warn("文件名称不得为 undefined 或者 null !");
|
||||||
|
}
|
||||||
|
switch (arguments.length) {
|
||||||
|
case 1:
|
||||||
|
var f = arguments[0];
|
||||||
|
if (f instanceof File) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
if (typeof f === "string") {
|
||||||
|
return new File(f);
|
||||||
|
}
|
||||||
|
if (f instanceof Path) {
|
||||||
|
return f.toFile();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new File(file(arguments[0]), arguments[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建目录
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
export function mkdirs(path) {
|
||||||
|
// noinspection JSUnresolvedVariable
|
||||||
|
file(path).parentFile.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建文件
|
||||||
|
* @param file
|
||||||
|
*/
|
||||||
|
export function create(path) {
|
||||||
|
var f = file(path);
|
||||||
|
if (!f.exists()) {
|
||||||
|
mkdirs(f);
|
||||||
|
f.createNewFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得文件规范路径
|
||||||
|
* @param file
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export function path(f) {
|
||||||
|
return file(f).canonicalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制文件
|
||||||
|
* @param inputStream 输入流
|
||||||
|
* @param target 目标文件
|
||||||
|
* @param override 是否覆盖
|
||||||
|
*/
|
||||||
|
export function copy(inputStream, target, override) {
|
||||||
|
Files.copy(inputStream, target.toPath(), StandardCopyOption[override ? 'REPLACE_EXISTING' : 'ATOMIC_MOVE']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件
|
||||||
|
* @param path 文件路径
|
||||||
|
*/
|
||||||
|
export function read(path) {
|
||||||
|
var file = file(path);
|
||||||
|
if (!file.exists()) {
|
||||||
|
console.warn('读取文件', file, '错误 文件不存在!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// noinspection JSPrimitiveTypeWrapperUsage
|
||||||
|
return new JavaString(Files.readAllBytes(file.toPath()), "UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存内容文件
|
||||||
|
* @param path 路径
|
||||||
|
* @param content 内容
|
||||||
|
* @param override 是否覆盖
|
||||||
|
*/
|
||||||
|
export function save(path, content, override) {
|
||||||
|
var file = file(path);
|
||||||
|
if (file.parentFile) {
|
||||||
|
file.parentFile.mkdirs();
|
||||||
|
}
|
||||||
|
Files.write(file.toPath(), new JavaString(content).getBytes("UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列出目录文件
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
export function list(path) {
|
||||||
|
var dir = file(path);
|
||||||
|
// noinspection JSValidateTypes
|
||||||
|
if (dir.isDirectory()) {
|
||||||
|
return Files.list(dir.toPath());
|
||||||
|
}
|
||||||
|
console.debug('路径', path, '不是一个目录 返回空数组!');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动文件
|
||||||
|
* @param src 原始目录
|
||||||
|
* @param des 目标目录
|
||||||
|
* @param override 是否覆盖
|
||||||
|
*/
|
||||||
|
export function move(src, des, override) {
|
||||||
|
Files.move(file(src).toPath(), file(des).toPath(),
|
||||||
|
override ? StandardCopyOption['REPLACE_EXISTING'] : StandardCopyOption['ATOMIC_MOVE'])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function del(file) {
|
||||||
|
file = file(file);
|
||||||
|
if (!file.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
Files.list(file.toPath()).collect(Collector.toList()).forEach(function(f) {
|
||||||
|
del(f);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Files.delete(file.toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exists(f) {
|
||||||
|
return file(f).exists()
|
||||||
|
}
|
155
packages/common/src/http.ts
Normal file
155
packages/common/src/http.ts
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
'use strict';
|
||||||
|
/**
|
||||||
|
* HTTP 网络类
|
||||||
|
* Created by 蒋天蓓 on 2017/2/9 0009.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*global Java, base, module, exports, require, __FILE__*/
|
||||||
|
|
||||||
|
var URL = Java.type("java.net.URL");
|
||||||
|
var UUID = Java.type("java.util.UUID");
|
||||||
|
var System = Java.type("java.lang.System");
|
||||||
|
var Files = Java.type("java.nio.file.Files");
|
||||||
|
var Paths = Java.type("java.nio.file.Paths");
|
||||||
|
var JavaString = Java.type("java.lang.String");
|
||||||
|
var SecureRandom = Java.type("java.security.SecureRandom");
|
||||||
|
|
||||||
|
var SSLContext = Java.type("javax.net.ssl.SSLContext");
|
||||||
|
var HttpsURLConnection = Java.type("javax.net.ssl.HttpsURLConnection");
|
||||||
|
|
||||||
|
var HostnameVerifier = Java.type("javax.net.ssl.HostnameVerifier");
|
||||||
|
var X509TrustManager = Java.type("javax.net.ssl.X509TrustManager");
|
||||||
|
|
||||||
|
// noinspection JSUnusedGlobalSymbols,JSUnusedLocalSymbols
|
||||||
|
var TrustAnyHostnameVerifier = new HostnameVerifier({
|
||||||
|
verify: function(hostname, session) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var SSLSocketFactory = function initSSLSocketFactory() {
|
||||||
|
var sslContext = SSLContext.getInstance("TLS");
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
sslContext.init(null, [new X509TrustManager({
|
||||||
|
getAcceptedIssuers: function() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
checkClientTrusted: function(chain, authType) {
|
||||||
|
},
|
||||||
|
checkServerTrusted: function(chain, authType) {
|
||||||
|
}
|
||||||
|
})], new SecureRandom());
|
||||||
|
return sslContext.getSocketFactory();
|
||||||
|
}();
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
Charset: 'UTF-8',
|
||||||
|
ConnectTimeout: 10000,
|
||||||
|
ReadTimeout: 10000,
|
||||||
|
Debug: false
|
||||||
|
};
|
||||||
|
|
||||||
|
function open(url, method, header) {
|
||||||
|
// conn.setRequestProperty
|
||||||
|
var conn = new URL(url).openConnection();
|
||||||
|
if (conn instanceof HttpsURLConnection) {
|
||||||
|
conn.setHostnameVerifier(TrustAnyHostnameVerifier);
|
||||||
|
conn.setSSLSocketFactory(SSLSocketFactory);
|
||||||
|
}
|
||||||
|
conn.setRequestMethod(method);
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
conn.setDoInput(true);
|
||||||
|
conn.setConnectTimeout(config.ConnectTimeout);
|
||||||
|
conn.setReadTimeout(config.ReadTimeout);
|
||||||
|
if (header) {
|
||||||
|
for (var key in header) {
|
||||||
|
// noinspection JSUnfilteredForInLoop
|
||||||
|
conn.setRequestProperty(key, header[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildUrl(url, params) {
|
||||||
|
if (params && Object.keys(params).length > 0) {
|
||||||
|
var queryStart = url.indexOf('?');
|
||||||
|
if (queryStart === -1) {
|
||||||
|
url += '?';
|
||||||
|
}
|
||||||
|
return url += object2URLSearchParams(params);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function request(config) {
|
||||||
|
var conn = open(buildUrl(config.url, config.query), config.method, config.header);
|
||||||
|
try {
|
||||||
|
conn.connect();
|
||||||
|
var data = config.data;
|
||||||
|
if (data) {
|
||||||
|
var out = conn.getOutputStream();
|
||||||
|
if (typeof data === "object") {
|
||||||
|
var type = config.header['Content-Type'];
|
||||||
|
switch (type) {
|
||||||
|
case "application/x-www-form-urlencoded":
|
||||||
|
data = object2URLSearchParams(data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
data = JSON.stringify(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.write(new JavaString(data).getBytes(config.Charset));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
return response(conn);
|
||||||
|
} finally {
|
||||||
|
conn.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function response(conn) {
|
||||||
|
var temp = Paths.get(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString());
|
||||||
|
Files.copy(conn.getInputStream(), temp);
|
||||||
|
var result = new JavaString(Files.readAllBytes(temp), config.Charset);
|
||||||
|
var tempFile = temp.toFile();
|
||||||
|
tempFile.delete() || tempFile.deleteOnExit();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function object2URLSearchParams(params) {
|
||||||
|
var temp: string[] = [];
|
||||||
|
for (var key in params) {
|
||||||
|
temp.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
|
||||||
|
}
|
||||||
|
return temp.join('&')
|
||||||
|
}
|
||||||
|
|
||||||
|
var http = {
|
||||||
|
config: config,
|
||||||
|
request: request
|
||||||
|
};
|
||||||
|
|
||||||
|
['GET', 'DELETE', 'HEAD', 'OPTIONS'].forEach(function(method) {
|
||||||
|
http[method.toLowerCase()] = function __likeGet__(url, data, config = {}) {
|
||||||
|
return this.request({
|
||||||
|
...config,
|
||||||
|
url: url,
|
||||||
|
method: method,
|
||||||
|
query: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
['POST', 'PUT', 'PATCH'].forEach(function(method) {
|
||||||
|
http[method.toLowerCase()] = function __likePost__(url, data, config) {
|
||||||
|
return this.request({
|
||||||
|
...config,
|
||||||
|
url: url,
|
||||||
|
method: method,
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export = http;
|
191
packages/common/src/reflect.ts
Normal file
191
packages/common/src/reflect.ts
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import '@ms/core'
|
||||||
|
/**
|
||||||
|
* 反射工具类
|
||||||
|
* Created by 蒋天蓓 on 2017/2/9 0009.
|
||||||
|
*/
|
||||||
|
var JavaClass = Java.type('java.lang.Class');
|
||||||
|
var JavaObject = Java.type('java.lang.Object')
|
||||||
|
var NoSuchFieldException = Java.type('java.lang.NoSuchFieldException');
|
||||||
|
var methodCache = [];
|
||||||
|
|
||||||
|
class Reflect {
|
||||||
|
private obj: any;
|
||||||
|
private class: any
|
||||||
|
|
||||||
|
constructor(obj: any) {
|
||||||
|
if (obj instanceof JavaClass) {
|
||||||
|
this.obj = null;
|
||||||
|
this.class = obj;
|
||||||
|
} else {
|
||||||
|
this.obj = obj;
|
||||||
|
this.class = obj.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
method(...args: any[]) {
|
||||||
|
return declaredMethod(this.class, args[0], types(args.slice(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
methods() {
|
||||||
|
return Java.from(declaredMethods(this.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
field(name) {
|
||||||
|
try {
|
||||||
|
// Try getting a public field
|
||||||
|
var field = this.class.field(name);
|
||||||
|
return on(field.get(this.obj));
|
||||||
|
} catch (ex) {
|
||||||
|
// Try again, getting a non-public field
|
||||||
|
return on(accessible(declaredField(this.class, name)).get(this.obj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fields(declared) {
|
||||||
|
return Java.from(declared ? this.class.declaredFields : this.class.fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
values(declared) {
|
||||||
|
var cache = {};
|
||||||
|
var feds = declared ? this.class.declaredFields : this.class.fields;
|
||||||
|
Java.from(feds).forEach(function(fed) {
|
||||||
|
cache[fed.name] = this.field(fed.name).get();
|
||||||
|
}.bind(this))
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
call(...args) {
|
||||||
|
var params = args.slice(1);
|
||||||
|
var method = declaredMethod(this.class, args[0], types(params));
|
||||||
|
return on(method.invoke(this.get(), params));
|
||||||
|
};
|
||||||
|
|
||||||
|
get(...args) {
|
||||||
|
return args.length === 1 ? this.field(args[0]) : this.obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
set(name, value) {
|
||||||
|
accessible(declaredField(this.class, name)).set(this.obj, value);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
create(...args) {
|
||||||
|
return on(declaredConstructor(this.class, args).newInstance(args));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of types for an array of objects
|
||||||
|
*/
|
||||||
|
function types(values, def?) {
|
||||||
|
if (values === null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
var result = [];
|
||||||
|
values.forEach(t => result.push((t || def) ? JavaObject.class : t instanceof JavaClass ? t : t.class));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function accessible(accessible) {
|
||||||
|
if (accessible === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!accessible.isAccessible()) {
|
||||||
|
accessible.setAccessible(true);
|
||||||
|
}
|
||||||
|
return accessible;
|
||||||
|
}
|
||||||
|
|
||||||
|
function declaredConstructor(clazz, param) {
|
||||||
|
var constructor;
|
||||||
|
try {
|
||||||
|
constructor = clazz.getDeclaredConstructor(types(param));
|
||||||
|
} catch (ex) {
|
||||||
|
try {
|
||||||
|
constructor = clazz.getDeclaredConstructor(types(param, true));
|
||||||
|
} catch (ex) {
|
||||||
|
constructor = clazz.getDeclaredConstructors()[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accessible(constructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function declaredField(clazz, name) {
|
||||||
|
var field = null;
|
||||||
|
// noinspection JSUnresolvedVariable
|
||||||
|
while (clazz !== JavaObject.class) {
|
||||||
|
try {
|
||||||
|
field = clazz.getDeclaredField(name);
|
||||||
|
if (field !== null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
clazz = clazz.getSuperclass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (field === null) {
|
||||||
|
throw new NoSuchFieldException(name + " is not found in " + clazz.name);
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
function declaredMethod(clazz, name, clazzs) {
|
||||||
|
var key = clazz.name + '.' + name + ':' + (clazzs || []).join(':');
|
||||||
|
if (!methodCache[key]) {
|
||||||
|
try {
|
||||||
|
methodCache[key] = clazz.getMethod(name, clazzs);
|
||||||
|
} catch (ex) {
|
||||||
|
methodCache[key] = clazz.getDeclaredMethod(name, clazzs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methodCache[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
function declaredMethods(clazz) {
|
||||||
|
return clazz.declaredMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
var classMethodsCache = [];
|
||||||
|
|
||||||
|
function mapToObject(javaObj) {
|
||||||
|
if (!javaObj || !javaObj.class) { throw new TypeError(`参数 ${javaObj} 不是一个Java对象!`) }
|
||||||
|
var target = {};
|
||||||
|
getJavaObjectMethods(javaObj).forEach(t => mapMethod(target, javaObj, t));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getJavaObjectMethods(javaObj) {
|
||||||
|
var className = javaObj.class.name;
|
||||||
|
if (!classMethodsCache[className]) {
|
||||||
|
var names = [];
|
||||||
|
var methods = javaObj.class.methods;
|
||||||
|
for (var i in methods) {
|
||||||
|
names.push(methods[i].name);
|
||||||
|
}
|
||||||
|
classMethodsCache[className] = names;
|
||||||
|
}
|
||||||
|
return classMethodsCache[className];
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapMethod(target, source, name) {
|
||||||
|
target[name] = function __SimpleDynamicMethod__(...args) {
|
||||||
|
if (args.length > 0) {
|
||||||
|
return source[name](args);
|
||||||
|
} else {
|
||||||
|
return source[name]();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function on(obj) {
|
||||||
|
if (!obj || !obj.class) { throw new TypeError(`参数 ${obj} 不是一个Java对象!`) }
|
||||||
|
return new Reflect(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
export = {
|
||||||
|
on,
|
||||||
|
accessible,
|
||||||
|
declaredMethods,
|
||||||
|
mapToObject
|
||||||
|
};
|
29
packages/common/src/template.ts
Normal file
29
packages/common/src/template.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
function Template(tpl: string) {
|
||||||
|
var match: RegExpExecArray;
|
||||||
|
var code = ['var r=[];'];
|
||||||
|
var re = /\{\{\s*([a-zA-Z\.\_0-9()]+)\s*\}\}/m;
|
||||||
|
function addLine(text: string) {
|
||||||
|
code.push('r.push(\'' + text.replace(/\'/g, '\\\'').replace(/\n/g, '\\n').replace(/\r/g, '\\r') + '\');');
|
||||||
|
};
|
||||||
|
while (match = re.exec(tpl)) {
|
||||||
|
if (match.index > 0) {
|
||||||
|
addLine(tpl.slice(0, match.index));
|
||||||
|
}
|
||||||
|
code.push('r.push(this.' + match[1] + ');');
|
||||||
|
tpl = tpl.substring(match.index + match[0].length);
|
||||||
|
}
|
||||||
|
addLine(tpl);
|
||||||
|
code.push('return r.join(\'\');');
|
||||||
|
// 创建函数:
|
||||||
|
var fn = new Function(code.join('\n'));
|
||||||
|
// 用render()调用函数并绑定this参数:
|
||||||
|
this.render = function(model) {
|
||||||
|
return fn.apply(model);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export = {
|
||||||
|
create: function(tpl: string) {
|
||||||
|
return new Template(tpl);
|
||||||
|
}
|
||||||
|
}
|
23
packages/common/src/tgz.ts
Normal file
23
packages/common/src/tgz.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import '@ms/nashorn'
|
||||||
|
|
||||||
|
let Files = Java.type("java.nio.file.Files");
|
||||||
|
let Paths = Java.type("java.nio.file.Paths");
|
||||||
|
let StandardCopyOption = Java.type("java.nio.file.StandardCopyOption");
|
||||||
|
|
||||||
|
let TarInputStream = Java.type("org.kamranzafar.jtar.TarInputStream");
|
||||||
|
let GZIPInputStream = Java.type("java.util.zip.GZIPInputStream");
|
||||||
|
let BufferedInputStream = Java.type("java.io.BufferedInputStream");
|
||||||
|
|
||||||
|
function decompression(input: any, target: string) {
|
||||||
|
let tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(input)));
|
||||||
|
let entry: any;
|
||||||
|
while ((entry = tis.getNextEntry()) != null) {
|
||||||
|
let targetPath = Paths.get(target + "/" + entry.getName().substring("package/".length));
|
||||||
|
targetPath.toFile().getParentFile().mkdirs();
|
||||||
|
Files.copy(tis, targetPath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export = {
|
||||||
|
decompression
|
||||||
|
}
|
8
packages/common/tsconfig.json
Normal file
8
packages/common/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist",
|
||||||
|
"declaration": true
|
||||||
|
}
|
||||||
|
}
|
4
packages/container/.gitignore
vendored
Normal file
4
packages/container/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/package-lock.json
|
||||||
|
/yarn.lock
|
22
packages/container/.npmignore
Normal file
22
packages/container/.npmignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
typings
|
||||||
|
bundled
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
docs
|
||||||
|
wiki
|
||||||
|
gulpfile.js
|
||||||
|
bower.json
|
||||||
|
karma.conf.js
|
||||||
|
tsconfig.json
|
||||||
|
typings.json
|
||||||
|
CONTRIBUTING.md
|
||||||
|
ISSUE_TEMPLATE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
||||||
|
tslint.json
|
||||||
|
wallaby.js
|
||||||
|
.travis.yml
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
type_definitions
|
32
packages/container/package.json
Normal file
32
packages/container/package.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "@ms/container",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "MiaoScript container package",
|
||||||
|
"keywords": [
|
||||||
|
"miaoscript",
|
||||||
|
"minecraft",
|
||||||
|
"bukkit",
|
||||||
|
"sponge"
|
||||||
|
],
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"homepage": "https://github.com/circlecloud/ms.git",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm/"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"watch": "npx tsc --watch",
|
||||||
|
"build": "yarn clean && npx tsc",
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rimraf": "^3.0.0",
|
||||||
|
"typescript": "^3.6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"inversify-binding-decorators": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
104
packages/container/src/decorators.ts
Normal file
104
packages/container/src/decorators.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { interfaces, Container } from "inversify";
|
||||||
|
|
||||||
|
let _container: Container;
|
||||||
|
|
||||||
|
const CONTAINER = Symbol.for("@ms/ioc:Container");
|
||||||
|
const INJECTION = Symbol.for("INJECTION");
|
||||||
|
|
||||||
|
function _proxyGetter(
|
||||||
|
proto: any,
|
||||||
|
key: string,
|
||||||
|
resolve: () => any,
|
||||||
|
doCache: boolean
|
||||||
|
) {
|
||||||
|
function getter() {
|
||||||
|
if (doCache && !Reflect.hasMetadata(INJECTION, this, key)) {
|
||||||
|
Reflect.defineMetadata(INJECTION, resolve(), this, key);
|
||||||
|
}
|
||||||
|
if (Reflect.hasMetadata(INJECTION, this, key)) {
|
||||||
|
return Reflect.getMetadata(INJECTION, this, key);
|
||||||
|
} else {
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setter(newVal: any) {
|
||||||
|
Reflect.defineMetadata(INJECTION, newVal, this, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(proto, key, {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
get: getter,
|
||||||
|
set: setter
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initContainer(container: Container) {
|
||||||
|
Reflect.defineMetadata(CONTAINER, container, Reflect);
|
||||||
|
_container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContainer(): Container {
|
||||||
|
return _container || Reflect.getMetadata(CONTAINER, Reflect)
|
||||||
|
}
|
||||||
|
|
||||||
|
function makePropertyInjectDecorator(doCache: boolean) {
|
||||||
|
return function(serviceIdentifier: interfaces.ServiceIdentifier<any>) {
|
||||||
|
return function(proto: any, key: string): void {
|
||||||
|
let resolve = () => {
|
||||||
|
return getContainer().get(serviceIdentifier);
|
||||||
|
};
|
||||||
|
_proxyGetter(proto, key, resolve, doCache);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function makePropertyInjectNamedDecorator(doCache: boolean) {
|
||||||
|
return function(serviceIdentifier: interfaces.ServiceIdentifier<any>, named: string) {
|
||||||
|
return function(proto: any, key: string): void {
|
||||||
|
let resolve = () => {
|
||||||
|
return getContainer().getNamed(serviceIdentifier, named);
|
||||||
|
};
|
||||||
|
_proxyGetter(proto, key, resolve, doCache);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function makePropertyInjectTaggedDecorator(doCache: boolean) {
|
||||||
|
return function(serviceIdentifier: interfaces.ServiceIdentifier<any>, key: string, value: any) {
|
||||||
|
return function(proto: any, propertyName: string): void {
|
||||||
|
let resolve = () => {
|
||||||
|
return getContainer().getTagged(serviceIdentifier, key, value);
|
||||||
|
};
|
||||||
|
_proxyGetter(proto, propertyName, resolve, doCache);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function makePropertyMultiInjectDecorator(doCache: boolean) {
|
||||||
|
return function(serviceIdentifier: interfaces.ServiceIdentifier<any>) {
|
||||||
|
return function(proto: any, key: string): void {
|
||||||
|
let resolve = () => {
|
||||||
|
return getContainer().getAll(serviceIdentifier);
|
||||||
|
};
|
||||||
|
_proxyGetter(proto, key, resolve, doCache);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let doCache = true;
|
||||||
|
|
||||||
|
let lazyInject = makePropertyInjectDecorator(doCache)
|
||||||
|
let lazyInjectNamed = makePropertyInjectNamedDecorator(doCache)
|
||||||
|
let lazyInjectTagged = makePropertyInjectTaggedDecorator(doCache)
|
||||||
|
let lazyMultiInject = makePropertyMultiInjectDecorator(doCache)
|
||||||
|
|
||||||
|
export {
|
||||||
|
initContainer,
|
||||||
|
getContainer,
|
||||||
|
lazyInject,
|
||||||
|
lazyInjectNamed,
|
||||||
|
lazyInjectTagged,
|
||||||
|
lazyMultiInject
|
||||||
|
};
|
23
packages/container/src/index.ts
Normal file
23
packages/container/src/index.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import "reflect-metadata";
|
||||||
|
import { interfaces, Container } from 'inversify';
|
||||||
|
import { fluentProvide } from 'inversify-binding-decorators';
|
||||||
|
|
||||||
|
const provideNamed = (identifier: interfaces.ServiceIdentifier<any>, name: string) => {
|
||||||
|
return fluentProvide(identifier).whenTargetNamed(name).done();
|
||||||
|
};
|
||||||
|
|
||||||
|
const provideSingleton = (identifier: interfaces.ServiceIdentifier<any>) => {
|
||||||
|
return fluentProvide(identifier).inSingletonScope().done();
|
||||||
|
};
|
||||||
|
|
||||||
|
const DefaultContainer = new Container();
|
||||||
|
|
||||||
|
export * from 'inversify'
|
||||||
|
export * from './decorators'
|
||||||
|
export * from 'inversify-binding-decorators'
|
||||||
|
export {
|
||||||
|
fluentProvide,
|
||||||
|
provideNamed,
|
||||||
|
provideSingleton,
|
||||||
|
DefaultContainer
|
||||||
|
};
|
7
packages/container/tsconfig.json
Normal file
7
packages/container/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist"
|
||||||
|
}
|
||||||
|
}
|
4
packages/core/.gitignore
vendored
Normal file
4
packages/core/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/package-lock.json
|
||||||
|
/yarn.lock
|
22
packages/core/.npmignore
Normal file
22
packages/core/.npmignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
typings
|
||||||
|
bundled
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
docs
|
||||||
|
wiki
|
||||||
|
gulpfile.js
|
||||||
|
bower.json
|
||||||
|
karma.conf.js
|
||||||
|
tsconfig.json
|
||||||
|
typings.json
|
||||||
|
CONTRIBUTING.md
|
||||||
|
ISSUE_TEMPLATE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
||||||
|
tslint.json
|
||||||
|
wallaby.js
|
||||||
|
.travis.yml
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
type_definitions
|
33
packages/core/package.json
Normal file
33
packages/core/package.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "@ms/core",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "MiaoScript api package",
|
||||||
|
"keywords": [
|
||||||
|
"miaoscript",
|
||||||
|
"minecraft",
|
||||||
|
"bukkit",
|
||||||
|
"sponge"
|
||||||
|
],
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"homepage": "https://github.com/circlecloud/ms.git",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm/"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"watch": "npx tsc --watch",
|
||||||
|
"build": "yarn clean && npx tsc",
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rimraf": "^3.0.0",
|
||||||
|
"typescript": "^3.6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ms/container": "^0.0.0",
|
||||||
|
"@ms/plugin": "^0.0.0"
|
||||||
|
}
|
||||||
|
}
|
17
packages/core/src/index.ts
Normal file
17
packages/core/src/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import '@ms/nashorn'
|
||||||
|
|
||||||
|
import { plugin, server, MiaoScriptConsole } from '@ms/api'
|
||||||
|
import { DefaultContainer as container } from '@ms/container'
|
||||||
|
import { PluginManagerImpl } from '@ms/plugin'
|
||||||
|
|
||||||
|
import '@ms/bukkit'
|
||||||
|
|
||||||
|
let Console: MiaoScriptConsole = container.get(server.Console);
|
||||||
|
global.console = new Console();
|
||||||
|
|
||||||
|
container.bind(plugin.PluginManager).to(PluginManagerImpl).inSingletonScope();
|
||||||
|
|
||||||
|
let manager = container.get<plugin.PluginManager>(plugin.PluginManager);
|
||||||
|
manager.scan('plugins');
|
||||||
|
manager.load(container);
|
||||||
|
manager.enable();
|
7
packages/core/tsconfig.json
Normal file
7
packages/core/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist"
|
||||||
|
}
|
||||||
|
}
|
4
packages/nashorn/.gitignore
vendored
Normal file
4
packages/nashorn/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/package-lock.json
|
||||||
|
/yarn.lock
|
22
packages/nashorn/.npmignore
Normal file
22
packages/nashorn/.npmignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
typings
|
||||||
|
bundled
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
docs
|
||||||
|
wiki
|
||||||
|
gulpfile.js
|
||||||
|
bower.json
|
||||||
|
karma.conf.js
|
||||||
|
tsconfig.json
|
||||||
|
typings.json
|
||||||
|
CONTRIBUTING.md
|
||||||
|
ISSUE_TEMPLATE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
||||||
|
tslint.json
|
||||||
|
wallaby.js
|
||||||
|
.travis.yml
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
type_definitions
|
30
packages/nashorn/package.json
Normal file
30
packages/nashorn/package.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@ms/nashorn",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "MiaoScript api package",
|
||||||
|
"keywords": [
|
||||||
|
"miaoscript",
|
||||||
|
"minecraft",
|
||||||
|
"bukkit",
|
||||||
|
"sponge"
|
||||||
|
],
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"homepage": "https://github.com/circlecloud/ms.git",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm/"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"watch": "npx tsc --watch",
|
||||||
|
"build": "yarn clean && npx tsc",
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rimraf": "^3.0.0",
|
||||||
|
"typescript": "^3.6.2"
|
||||||
|
}
|
||||||
|
}
|
9
packages/nashorn/src/index.ts
Normal file
9
packages/nashorn/src/index.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
declare global {
|
||||||
|
namespace Java {
|
||||||
|
function type(clazz: string): any;
|
||||||
|
function from(javaObj: any): any[];
|
||||||
|
function to(array: any[]): any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { };
|
7
packages/nashorn/tsconfig.json
Normal file
7
packages/nashorn/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist"
|
||||||
|
}
|
||||||
|
}
|
4
packages/plugin/.gitignore
vendored
Normal file
4
packages/plugin/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/package-lock.json
|
||||||
|
/yarn.lock
|
22
packages/plugin/.npmignore
Normal file
22
packages/plugin/.npmignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
typings
|
||||||
|
bundled
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
docs
|
||||||
|
wiki
|
||||||
|
gulpfile.js
|
||||||
|
bower.json
|
||||||
|
karma.conf.js
|
||||||
|
tsconfig.json
|
||||||
|
typings.json
|
||||||
|
CONTRIBUTING.md
|
||||||
|
ISSUE_TEMPLATE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
||||||
|
tslint.json
|
||||||
|
wallaby.js
|
||||||
|
.travis.yml
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
type_definitions
|
34
packages/plugin/package.json
Normal file
34
packages/plugin/package.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "@ms/plugin",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "MiaoScript api package",
|
||||||
|
"keywords": [
|
||||||
|
"miaoscript",
|
||||||
|
"minecraft",
|
||||||
|
"bukkit",
|
||||||
|
"sponge"
|
||||||
|
],
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"homepage": "https://github.com/circlecloud/ms.git",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm/"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"watch": "npx tsc --watch",
|
||||||
|
"build": "yarn clean && npx tsc",
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rimraf": "^3.0.0",
|
||||||
|
"typescript": "^3.6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ms/api": "^0.0.0",
|
||||||
|
"es6-map": "^0.1.5",
|
||||||
|
"inversify": "^5.0.1"
|
||||||
|
}
|
||||||
|
}
|
3
packages/plugin/src/constants.ts
Normal file
3
packages/plugin/src/constants.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const METADATA_KEY = {
|
||||||
|
plugin: "@ms/plugin:plugin",
|
||||||
|
};
|
20
packages/plugin/src/decorators.ts
Normal file
20
packages/plugin/src/decorators.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { interfaces } from './interfaces'
|
||||||
|
import { METADATA_KEY } from './constants'
|
||||||
|
import { injectable, decorate } from "inversify";
|
||||||
|
import { getPluginMetadatas } from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MiaoScript plugin
|
||||||
|
* @param name namespace name default is '/'
|
||||||
|
* @param middleware middleware array
|
||||||
|
*/
|
||||||
|
export function plugin(currentMetadata: interfaces.PluginMetadata) {
|
||||||
|
return function(target: any) {
|
||||||
|
target.description = currentMetadata;
|
||||||
|
currentMetadata.target = target;
|
||||||
|
decorate(injectable(), target);
|
||||||
|
Reflect.defineMetadata(METADATA_KEY.plugin, currentMetadata, target);
|
||||||
|
const previousMetadata: interfaces.PluginMetadata[] = getPluginMetadatas();
|
||||||
|
Reflect.defineMetadata(METADATA_KEY.plugin, [currentMetadata, ...previousMetadata], Reflect);
|
||||||
|
};
|
||||||
|
}
|
3
packages/plugin/src/index.ts
Normal file
3
packages/plugin/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './manager'
|
||||||
|
export * from './decorators'
|
||||||
|
export * from './interfaces'
|
25
packages/plugin/src/interfaces.ts
Normal file
25
packages/plugin/src/interfaces.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { injectable, postConstruct } from "inversify";
|
||||||
|
import { getPluginMetadata } from './utils'
|
||||||
|
|
||||||
|
export namespace interfaces {
|
||||||
|
@injectable()
|
||||||
|
export abstract class Plugin {
|
||||||
|
public description: PluginMetadata;
|
||||||
|
protected logger: Console;
|
||||||
|
|
||||||
|
@postConstruct()
|
||||||
|
private init() {
|
||||||
|
this.logger = global.console;
|
||||||
|
}
|
||||||
|
|
||||||
|
public load() { }
|
||||||
|
public enable() { }
|
||||||
|
public disable() { }
|
||||||
|
}
|
||||||
|
export interface PluginMetadata {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
author: string | string[];
|
||||||
|
target?: any;
|
||||||
|
}
|
||||||
|
}
|
136
packages/plugin/src/manager.ts
Normal file
136
packages/plugin/src/manager.ts
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import { plugin, server } from '@ms/api'
|
||||||
|
import { injectable, inject, postConstruct, Container } from '@ms/container'
|
||||||
|
import * as fs from '@ms/common/dist/fs'
|
||||||
|
|
||||||
|
import { getPluginMetadatas } from './utils'
|
||||||
|
import { interfaces } from './interfaces';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class PluginManagerImpl implements plugin.PluginManager {
|
||||||
|
@inject(plugin.PluginInstance)
|
||||||
|
private pluginInstance: any;
|
||||||
|
@inject(server.ServerType)
|
||||||
|
private serverType: string;
|
||||||
|
|
||||||
|
private pluginMap: Map<string, interfaces.Plugin>;
|
||||||
|
|
||||||
|
@postConstruct()
|
||||||
|
init() {
|
||||||
|
if (this.pluginInstance !== null) {
|
||||||
|
// 如果plugin不等于null 则代表是正式环境
|
||||||
|
console.info(`Initialization MiaoScript Plugin System: ${this.pluginInstance} ...`);
|
||||||
|
this.pluginMap = new Map();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scan(folder: string): void {
|
||||||
|
var plugin = fs.file(root, folder);
|
||||||
|
var files = []
|
||||||
|
// load common plugin
|
||||||
|
.concat(this.scanFloder(plugin))
|
||||||
|
// load space plugin
|
||||||
|
.concat(this.scanFloder(fs.file(plugin, this.serverType)))
|
||||||
|
this.loadPlugins(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
load(container: Container): void {
|
||||||
|
this.buildPlugins(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
enable(): void {
|
||||||
|
this.pluginMap.forEach(pl => this.runCatch(pl, 'load'));
|
||||||
|
this.pluginMap.forEach(pl => this.runCatch(pl, 'enable'));
|
||||||
|
}
|
||||||
|
|
||||||
|
disable(): void {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private runCatch(pl: any, func: string) {
|
||||||
|
console.log(JSON.stringify(pl));
|
||||||
|
try {
|
||||||
|
pl[func].call(pl);
|
||||||
|
} catch (ex) {
|
||||||
|
console.console(`§6插件 §b${pl.description.name} §6执行 §d${func} §6方法时发生错误 §4${ex}`);
|
||||||
|
console.ex(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private scanFloder(plugin: any): string[] {
|
||||||
|
var files = [];
|
||||||
|
console.info(`Start Scan Plugins in ${plugin} ...`);
|
||||||
|
this.checkUpdateFolder(plugin);
|
||||||
|
fs.list(plugin).forEach(function searchPlugin(file) {
|
||||||
|
files.push(file.toFile());
|
||||||
|
});
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新插件
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
private checkUpdateFolder(path) {
|
||||||
|
var update = fs.file(path, "update");
|
||||||
|
if (!update.exists()) {
|
||||||
|
update.mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadPlugins(files: any[]): void {
|
||||||
|
this.loadJsPlugins(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JS类型插件预加载
|
||||||
|
*/
|
||||||
|
private loadJsPlugins(files: any[]) {
|
||||||
|
files.filter(file => file.name.endsWith(".js")).forEach(file => {
|
||||||
|
try {
|
||||||
|
this.loadPlugin(file)
|
||||||
|
} catch (ex) {
|
||||||
|
console.console(`§6插件 §b${file.name} §6初始化时发生错误 §4${ex.message}`);
|
||||||
|
console.ex(ex);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadPlugin(file: any) {
|
||||||
|
this.updatePlugin(file);
|
||||||
|
this.createPlugin(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updatePlugin(file: any) {
|
||||||
|
var update = fs.file(fs.file(file.parentFile, 'update'), file.name);
|
||||||
|
if (update.exists()) {
|
||||||
|
console.info(`Auto Update Plugin ${file.name} ...`);
|
||||||
|
fs.move(update, file, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createPlugin(file) {
|
||||||
|
//@ts-ignore
|
||||||
|
require(file, {
|
||||||
|
cache: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private beforeLoadHook(origin) {
|
||||||
|
var result = origin;
|
||||||
|
// // 注入 console 对象 // 给插件注入单独的 console
|
||||||
|
// result += '\nvar console = new Console(); module.exports.console = console;';
|
||||||
|
// // 插件注入 self 对象
|
||||||
|
// result += '\nvar self = {}; module.exports.self = self;';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildPlugins(container: Container) {
|
||||||
|
let pluginMetadatas = getPluginMetadatas();
|
||||||
|
for (const metadata of pluginMetadatas) {
|
||||||
|
container.bind(plugin.Plugin).to(metadata.target).inSingletonScope().whenTargetNamed(metadata.name);
|
||||||
|
this.pluginMap.set(metadata.name, container.getNamed(plugin.Plugin, metadata.name));
|
||||||
|
let pluginInstance = this.pluginMap.get(metadata.name)
|
||||||
|
pluginInstance.description = metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
packages/plugin/src/utils.ts
Normal file
28
packages/plugin/src/utils.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { interfaces } from './interfaces'
|
||||||
|
import { METADATA_KEY } from './constants'
|
||||||
|
|
||||||
|
function getPlugins() {
|
||||||
|
return getPluginMetadatas().map((target) => target.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginMetadatas() {
|
||||||
|
let pluginMetadatas: interfaces.PluginMetadata[] = Reflect.getMetadata(
|
||||||
|
METADATA_KEY.plugin,
|
||||||
|
Reflect
|
||||||
|
) || [];
|
||||||
|
return pluginMetadatas;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginMetadata(target: any) {
|
||||||
|
let pluginMetadata: interfaces.PluginMetadata = Reflect.getMetadata(
|
||||||
|
METADATA_KEY.plugin,
|
||||||
|
target
|
||||||
|
) || {};
|
||||||
|
return pluginMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getPlugins,
|
||||||
|
getPluginMetadatas,
|
||||||
|
getPluginMetadata
|
||||||
|
}
|
7
packages/plugin/tsconfig.json
Normal file
7
packages/plugin/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist"
|
||||||
|
}
|
||||||
|
}
|
4
packages/sponge/.gitignore
vendored
Normal file
4
packages/sponge/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/package-lock.json
|
||||||
|
/yarn.lock
|
22
packages/sponge/.npmignore
Normal file
22
packages/sponge/.npmignore
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
typings
|
||||||
|
bundled
|
||||||
|
build
|
||||||
|
coverage
|
||||||
|
docs
|
||||||
|
wiki
|
||||||
|
gulpfile.js
|
||||||
|
bower.json
|
||||||
|
karma.conf.js
|
||||||
|
tsconfig.json
|
||||||
|
typings.json
|
||||||
|
CONTRIBUTING.md
|
||||||
|
ISSUE_TEMPLATE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
||||||
|
tslint.json
|
||||||
|
wallaby.js
|
||||||
|
.travis.yml
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
type_definitions
|
32
packages/sponge/package.json
Normal file
32
packages/sponge/package.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "@ms/sponge",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "MiaoScript api package",
|
||||||
|
"keywords": [
|
||||||
|
"miaoscript",
|
||||||
|
"minecraft",
|
||||||
|
"bukkit",
|
||||||
|
"sponge"
|
||||||
|
],
|
||||||
|
"author": "MiaoWoo <admin@yumc.pw>",
|
||||||
|
"homepage": "https://github.com/circlecloud/ms.git",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://repo.yumc.pw/repository/npm/"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"watch": "npx tsc --watch",
|
||||||
|
"build": "yarn clean && npx tsc",
|
||||||
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rimraf": "^3.0.0",
|
||||||
|
"typescript": "^3.6.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"inversify": "^5.0.1"
|
||||||
|
}
|
||||||
|
}
|
1
packages/sponge/src/index.ts
Normal file
1
packages/sponge/src/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default {}
|
7
packages/sponge/tsconfig.json
Normal file
7
packages/sponge/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist"
|
||||||
|
}
|
||||||
|
}
|
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "src",
|
||||||
|
"outDir": "dist",
|
||||||
|
"target": "es5",
|
||||||
|
"module": "commonjs",
|
||||||
|
"sourceMap": false,
|
||||||
|
"declaration": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"allowUnreachableCode": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"lib": []
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user