@kotori-bot/core 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/lib/components/config.d.ts +16 -0
- package/lib/components/config.js +39 -0
- package/lib/components/core.d.ts +31 -0
- package/lib/components/core.js +30 -0
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +17 -0
- package/lib/components/message.d.ts +25 -0
- package/lib/components/message.js +135 -0
- package/lib/components/modules.d.ts +12 -0
- package/lib/components/modules.js +127 -0
- package/lib/consts.d.ts +12 -8
- package/lib/consts.js +14 -8
- package/lib/context/context.d.ts +35 -0
- package/lib/context/context.js +111 -0
- package/lib/context/events.d.ts +18 -0
- package/lib/context/index.d.ts +5 -0
- package/lib/context/index.js +21 -0
- package/lib/context/modules.d.ts +39 -0
- package/lib/context/modules.js +65 -0
- package/lib/context/service.d.ts +16 -0
- package/lib/context/service.js +22 -0
- package/lib/context/symbols.d.ts +12 -0
- package/lib/context/symbols.js +18 -0
- package/lib/context/test.d.ts +6 -0
- package/lib/context/test.js +12 -0
- package/lib/index.d.ts +6 -11
- package/lib/index.js +13 -21
- package/lib/service/adapter.d.ts +44 -0
- package/lib/service/adapter.js +165 -0
- package/lib/service/api.d.ts +32 -0
- package/lib/{components → service}/api.js +12 -14
- package/lib/service/cache.d.ts +13 -0
- package/lib/service/cache.js +34 -0
- package/lib/service/elements.d.ts +12 -0
- package/lib/service/elements.js +39 -0
- package/lib/service/index.d.ts +4 -0
- package/lib/service/index.js +20 -0
- package/lib/service/service.d.ts +16 -0
- package/lib/service/service.js +22 -0
- package/lib/types/adapter.d.ts +22 -0
- package/lib/types/adapter.js +2 -0
- package/lib/types/config.d.ts +22 -0
- package/lib/types/config.js +2 -0
- package/lib/types/core.d.ts +7 -0
- package/lib/types/core.js +2 -0
- package/lib/types/index.d.ts +3 -0
- package/lib/types/index.js +19 -0
- package/lib/types/message.d.ts +228 -0
- package/lib/types/message.js +17 -0
- package/lib/types/modules.d.ts +39 -0
- package/lib/types/modules.js +2 -0
- package/lib/types/service.d.ts +23 -0
- package/lib/types/service.js +2 -0
- package/lib/utils/command.d.ts +43 -0
- package/lib/utils/command.js +212 -0
- package/lib/utils/commandError.d.ts +7 -0
- package/lib/utils/commandError.js +13 -0
- package/lib/utils/container.d.ts +9 -0
- package/lib/utils/container.js +21 -0
- package/lib/utils/errror.d.ts +5 -21
- package/lib/utils/errror.js +9 -14
- package/lib/utils/factory.d.ts +7 -0
- package/lib/utils/factory.js +25 -0
- package/package.json +10 -7
- package/lib/base/command.d.ts +0 -20
- package/lib/base/command.js +0 -217
- package/lib/base/core.d.ts +0 -30
- package/lib/base/core.js +0 -52
- package/lib/base/events.d.ts +0 -13
- package/lib/base/events.js +0 -41
- package/lib/base/filter.d.ts +0 -1
- package/lib/base/internal.d.ts +0 -34
- package/lib/base/internal.js +0 -89
- package/lib/base/message.d.ts +0 -18
- package/lib/base/message.js +0 -177
- package/lib/base/modules.d.ts +0 -15
- package/lib/base/modules.js +0 -205
- package/lib/components/adapter.d.ts +0 -38
- package/lib/components/adapter.js +0 -128
- package/lib/components/api.d.ts +0 -35
- package/lib/components/elements.d.ts +0 -12
- package/lib/components/elements.js +0 -28
- package/lib/components/service.d.ts +0 -13
- package/lib/components/service.js +0 -7
- package/lib/context.d.ts +0 -13
- package/lib/context.js +0 -35
- package/lib/types.d.ts +0 -417
- package/lib/types.js +0 -81
- package/lib/utils/commandExtra.d.ts +0 -6
- package/lib/utils/commandExtra.js +0 -11
- package/lib/utils/i18n.d.ts +0 -13
- package/lib/utils/i18n.js +0 -65
- /package/lib/{base/filter.js → context/events.js} +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Tsu from 'tsukiko';
|
|
2
|
+
import { CoreConfig } from '../types';
|
|
3
|
+
declare const packageInfoSchema: import("tsukiko").ObjectParser<{
|
|
4
|
+
name: import("tsukiko").StringParser;
|
|
5
|
+
version: import("tsukiko").StringParser;
|
|
6
|
+
description: import("tsukiko").StringParser;
|
|
7
|
+
main: import("tsukiko").StringParser;
|
|
8
|
+
license: import("tsukiko").LiteralParser<"GPL-3.0">;
|
|
9
|
+
author: import("tsukiko").StringParser;
|
|
10
|
+
}>;
|
|
11
|
+
export declare class Config {
|
|
12
|
+
readonly config: CoreConfig;
|
|
13
|
+
readonly pkg: Tsu.infer<typeof packageInfoSchema>;
|
|
14
|
+
constructor(config?: CoreConfig);
|
|
15
|
+
}
|
|
16
|
+
export default Config;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Config = void 0;
|
|
7
|
+
const tsukiko_1 = __importDefault(require("tsukiko"));
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const tools_1 = require("@kotori-bot/tools");
|
|
10
|
+
const consts_1 = require("../consts");
|
|
11
|
+
const packageInfoSchema = tsukiko_1.default.Object({
|
|
12
|
+
name: tsukiko_1.default.String(),
|
|
13
|
+
version: tsukiko_1.default.String(),
|
|
14
|
+
description: tsukiko_1.default.String(),
|
|
15
|
+
main: tsukiko_1.default.String(),
|
|
16
|
+
license: tsukiko_1.default.Literal('GPL-3.0'),
|
|
17
|
+
author: tsukiko_1.default.String()
|
|
18
|
+
});
|
|
19
|
+
class Config {
|
|
20
|
+
config;
|
|
21
|
+
pkg;
|
|
22
|
+
constructor(config = consts_1.DEFAULT_CORE_CONFIG) {
|
|
23
|
+
this.config = config;
|
|
24
|
+
/* load package.json */
|
|
25
|
+
const info = (0, tools_1.loadConfig)((0, path_1.join)(__dirname, '../../package.json'));
|
|
26
|
+
if (!info || Object.values(info).length === 0) {
|
|
27
|
+
process.stderr.write(`Cannot find kotori-bot package.json\n`);
|
|
28
|
+
process.exit();
|
|
29
|
+
}
|
|
30
|
+
const result = packageInfoSchema.parseSafe(info);
|
|
31
|
+
if (!result.value) {
|
|
32
|
+
process.stderr.write(`File package.json format error: ${result.error.message}\n`);
|
|
33
|
+
process.exit();
|
|
34
|
+
}
|
|
35
|
+
this.pkg = result.data;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.Config = Config;
|
|
39
|
+
exports.default = Config;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Http } from '@kotori-bot/tools';
|
|
2
|
+
import I18n from '@kotori-bot/i18n';
|
|
3
|
+
import type { Parser } from 'tsukiko';
|
|
4
|
+
import { Context, Symbols } from '../context';
|
|
5
|
+
import Config from './config';
|
|
6
|
+
import Message from './message';
|
|
7
|
+
import type { AdapterClass } from '../types';
|
|
8
|
+
import { Cache, type Api } from '../service';
|
|
9
|
+
declare module '../context' {
|
|
10
|
+
interface Context {
|
|
11
|
+
readonly [Symbols.adapter]: Core[typeof Symbols.adapter];
|
|
12
|
+
readonly [Symbols.bot]: Core[typeof Symbols.bot];
|
|
13
|
+
readonly config: Config['config'];
|
|
14
|
+
readonly pkg: Config['pkg'];
|
|
15
|
+
readonly [Symbols.midware]: Message[typeof Symbols.midware];
|
|
16
|
+
readonly [Symbols.command]: Message[typeof Symbols.command];
|
|
17
|
+
readonly [Symbols.regexp]: Message[typeof Symbols.regexp];
|
|
18
|
+
midware: Message['midware'];
|
|
19
|
+
command: Message['command'];
|
|
20
|
+
regexp: Message['regexp'];
|
|
21
|
+
http: Http;
|
|
22
|
+
i18n: I18n;
|
|
23
|
+
cache: Cache;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export declare class Core extends Context {
|
|
27
|
+
readonly [Symbols.adapter]: Map<string, [AdapterClass, Parser<unknown>?]>;
|
|
28
|
+
readonly [Symbols.bot]: Map<string, Set<Api>>;
|
|
29
|
+
constructor(config?: ConstructorParameters<typeof Config>[0]);
|
|
30
|
+
}
|
|
31
|
+
export default Core;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Core = void 0;
|
|
7
|
+
const tools_1 = require("@kotori-bot/tools");
|
|
8
|
+
const i18n_1 = __importDefault(require("@kotori-bot/i18n"));
|
|
9
|
+
const context_1 = require("../context");
|
|
10
|
+
const config_1 = __importDefault(require("./config"));
|
|
11
|
+
const message_1 = __importDefault(require("./message"));
|
|
12
|
+
const service_1 = require("../service");
|
|
13
|
+
class Core extends context_1.Context {
|
|
14
|
+
[context_1.Symbols.adapter] = new Map();
|
|
15
|
+
[context_1.Symbols.bot] = new Map();
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super();
|
|
18
|
+
this.provide('config', new config_1.default(config));
|
|
19
|
+
this.mixin('config', ['config', 'pkg']);
|
|
20
|
+
this.provide('message', new message_1.default(this));
|
|
21
|
+
this.mixin('message', ['midware', 'command', 'regexp']);
|
|
22
|
+
this.provide('http', new tools_1.Http({ validateStatus: () => true }));
|
|
23
|
+
this.inject('http');
|
|
24
|
+
this.provide('i18n', new i18n_1.default({ lang: this.config.global.lang }));
|
|
25
|
+
this.inject('i18n');
|
|
26
|
+
this.service('cache', new service_1.Cache(this.extends()));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.Core = Core;
|
|
30
|
+
exports.default = Core;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './core';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./core"), exports);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Context, Symbols } from '../context';
|
|
2
|
+
import { type CommandConfig, type MidwareCallback, type RegexpCallback } from '../types';
|
|
3
|
+
import { Command } from '../utils/command';
|
|
4
|
+
interface MidwareData {
|
|
5
|
+
callback: MidwareCallback;
|
|
6
|
+
priority: number;
|
|
7
|
+
}
|
|
8
|
+
interface RegexpData {
|
|
9
|
+
match: RegExp;
|
|
10
|
+
callback: RegexpCallback;
|
|
11
|
+
}
|
|
12
|
+
export declare class Message {
|
|
13
|
+
readonly [Symbols.midware]: Set<MidwareData>;
|
|
14
|
+
readonly [Symbols.command]: Set<Command>;
|
|
15
|
+
readonly [Symbols.regexp]: Set<RegexpData>;
|
|
16
|
+
private handleMidware;
|
|
17
|
+
private handleRegexp;
|
|
18
|
+
private handleCommand;
|
|
19
|
+
private readonly ctx;
|
|
20
|
+
constructor(ctx: Context);
|
|
21
|
+
midware(callback: MidwareCallback, priority?: number): () => boolean;
|
|
22
|
+
command(template: string, config?: CommandConfig): Command;
|
|
23
|
+
regexp(match: RegExp, callback: RegexpCallback): () => boolean;
|
|
24
|
+
}
|
|
25
|
+
export default Message;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Message = void 0;
|
|
7
|
+
const tools_1 = require("@kotori-bot/tools");
|
|
8
|
+
const context_1 = require("../context");
|
|
9
|
+
const factory_1 = require("../utils/factory");
|
|
10
|
+
const command_1 = require("../utils/command");
|
|
11
|
+
const commandError_1 = __importDefault(require("../utils/commandError"));
|
|
12
|
+
class Message {
|
|
13
|
+
[context_1.Symbols.midware] = new Set();
|
|
14
|
+
[context_1.Symbols.command] = new Set();
|
|
15
|
+
[context_1.Symbols.regexp] = new Set();
|
|
16
|
+
handleMidware(session) {
|
|
17
|
+
const { api } = session;
|
|
18
|
+
api.adapter.status.receivedMsg += 1;
|
|
19
|
+
let isPass = true;
|
|
20
|
+
let midwares = [];
|
|
21
|
+
this[context_1.Symbols.midware].forEach((val) => midwares.push(val));
|
|
22
|
+
midwares = midwares.sort((first, second) => first.priority - second.priority);
|
|
23
|
+
let lastMidwareNum = -1;
|
|
24
|
+
while (midwares.length > 0) {
|
|
25
|
+
if (lastMidwareNum === midwares.length) {
|
|
26
|
+
isPass = false;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
lastMidwareNum = midwares.length;
|
|
30
|
+
session.quick(midwares[0].callback(() => midwares.shift(), session));
|
|
31
|
+
}
|
|
32
|
+
this.ctx.emit('midwares', { isPass, session });
|
|
33
|
+
}
|
|
34
|
+
async handleRegexp(data) {
|
|
35
|
+
const { session } = data;
|
|
36
|
+
if (!data.isPass)
|
|
37
|
+
return;
|
|
38
|
+
this[context_1.Symbols.regexp].forEach((data) => {
|
|
39
|
+
const match = session.message.match(data.match);
|
|
40
|
+
if (!match)
|
|
41
|
+
return;
|
|
42
|
+
session.quick(data.callback(match, session));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
handleCommand(data) {
|
|
46
|
+
const { session } = data;
|
|
47
|
+
const prefix = session.api.adapter.config['command-prefix'] ?? this.ctx.config.global['command-prefix'];
|
|
48
|
+
if (!session.message.startsWith(prefix))
|
|
49
|
+
return;
|
|
50
|
+
const params = {
|
|
51
|
+
session,
|
|
52
|
+
raw: (0, tools_1.stringRightSplit)(session.message, prefix)
|
|
53
|
+
};
|
|
54
|
+
this.ctx.emit('before_parse', params);
|
|
55
|
+
const cancel = (0, factory_1.cancelFactory)();
|
|
56
|
+
this.ctx.emit('before_command', { cancel: cancel.get(), ...params });
|
|
57
|
+
if (cancel.value)
|
|
58
|
+
return;
|
|
59
|
+
let matched;
|
|
60
|
+
this[context_1.Symbols.command].forEach(async (cmd) => {
|
|
61
|
+
if (matched || !cmd.meta.action)
|
|
62
|
+
return;
|
|
63
|
+
const result = command_1.Command.run(params.raw, cmd.meta);
|
|
64
|
+
if (result instanceof commandError_1.default && result.value.type === 'unknown')
|
|
65
|
+
return;
|
|
66
|
+
matched = cmd;
|
|
67
|
+
this.ctx.emit('parse', { command: cmd, result, ...params, cancel: cancel.get() });
|
|
68
|
+
if (cancel.value || result instanceof commandError_1.default)
|
|
69
|
+
return;
|
|
70
|
+
try {
|
|
71
|
+
const executed = await cmd.meta.action({ args: result.args, options: result.options }, session);
|
|
72
|
+
if (executed instanceof commandError_1.default) {
|
|
73
|
+
this.ctx.emit('command', { command: cmd, result: executed, ...params });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (executed !== undefined)
|
|
77
|
+
session.quick(executed);
|
|
78
|
+
this.ctx.emit('command', {
|
|
79
|
+
command: cmd,
|
|
80
|
+
result: executed instanceof commandError_1.default ? result : executed,
|
|
81
|
+
...params
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
this.ctx.emit('command', {
|
|
86
|
+
command: matched,
|
|
87
|
+
result: new commandError_1.default({ type: 'error', error }),
|
|
88
|
+
...params
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
if (matched)
|
|
93
|
+
return;
|
|
94
|
+
this.ctx.emit('parse', {
|
|
95
|
+
command: new command_1.Command(''),
|
|
96
|
+
result: new commandError_1.default({ type: 'unknown', input: params.raw }),
|
|
97
|
+
...params,
|
|
98
|
+
cancel: cancel.get()
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
ctx;
|
|
102
|
+
constructor(ctx) {
|
|
103
|
+
this.ctx = ctx;
|
|
104
|
+
this.ctx.on('on_message', (session) => this.handleMidware(session));
|
|
105
|
+
this.ctx.on('midwares', (data) => this.handleCommand(data));
|
|
106
|
+
this.ctx.on('midwares', (data) => this.handleRegexp(data));
|
|
107
|
+
this.ctx.on('before_send', (data) => {
|
|
108
|
+
const { api } = data;
|
|
109
|
+
api.adapter.status.sentMsg += 1;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
midware(callback, priority = 100) {
|
|
113
|
+
const data = { callback, priority };
|
|
114
|
+
this[context_1.Symbols.midware].add(data);
|
|
115
|
+
const dispose = () => this[context_1.Symbols.midware].delete(data);
|
|
116
|
+
(0, factory_1.disposeFactory)(this.ctx, dispose);
|
|
117
|
+
return dispose;
|
|
118
|
+
}
|
|
119
|
+
command(template, config) {
|
|
120
|
+
const command = new command_1.Command(template, config);
|
|
121
|
+
this[context_1.Symbols.command].add(command);
|
|
122
|
+
const dispose = () => this[context_1.Symbols.command].delete(command);
|
|
123
|
+
(0, factory_1.disposeFactory)(this.ctx, dispose);
|
|
124
|
+
return command;
|
|
125
|
+
}
|
|
126
|
+
regexp(match, callback) {
|
|
127
|
+
const data = { match, callback };
|
|
128
|
+
this[context_1.Symbols.regexp].add(data);
|
|
129
|
+
const dispose = () => this[context_1.Symbols.regexp].delete(data);
|
|
130
|
+
(0, factory_1.disposeFactory)(this.ctx, dispose);
|
|
131
|
+
return dispose;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
exports.Message = Message;
|
|
135
|
+
exports.default = Message;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ModuleInstance, ModuleConfig } from '../types';
|
|
2
|
+
import { type Context } from '../context';
|
|
3
|
+
type ModuleInstanceClass = new (ctx: Context, config: ModuleConfig) => void;
|
|
4
|
+
type ModuleInstanceFunction = (ctx: Context, config: ModuleConfig) => void;
|
|
5
|
+
export declare class Modules {
|
|
6
|
+
private handleExports;
|
|
7
|
+
private readonly ctx;
|
|
8
|
+
constructor(ctx: Context);
|
|
9
|
+
use(modules: ModuleInstance | string | ModuleInstanceFunction | ModuleInstanceClass, config: ModuleConfig): Promise<void>;
|
|
10
|
+
dispose(modules: ModuleInstance | string): void;
|
|
11
|
+
}
|
|
12
|
+
export default Modules;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Modules = void 0;
|
|
4
|
+
const tools_1 = require("@kotori-bot/tools");
|
|
5
|
+
const tsukiko_1 = require("tsukiko");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const errror_1 = require("../utils/errror");
|
|
8
|
+
const context_1 = require("../context");
|
|
9
|
+
const service_1 = require("../service");
|
|
10
|
+
const consts_1 = require("../consts");
|
|
11
|
+
const factory_1 = require("../utils/factory");
|
|
12
|
+
function isServiceConsructor(Fn) {
|
|
13
|
+
return service_1.Service.isPrototypeOf.call(service_1.Service, Fn);
|
|
14
|
+
}
|
|
15
|
+
function isAdapterClass(Fn) {
|
|
16
|
+
return service_1.Adapter.isPrototypeOf.call(service_1.Adapter, Fn);
|
|
17
|
+
}
|
|
18
|
+
/* static isDatabaseClass(Obj: object): Obj is DatabaseClass {
|
|
19
|
+
return Database.isPrototypeOf.call(Database, Obj);
|
|
20
|
+
} */
|
|
21
|
+
function handleFunction(func, ctx, config) {
|
|
22
|
+
func(ctx, config);
|
|
23
|
+
}
|
|
24
|
+
function handleCconstructor(Class, ctx, config) {
|
|
25
|
+
(0, tools_1.none)(new Class(ctx, config));
|
|
26
|
+
}
|
|
27
|
+
function checkConfig(schema, config) {
|
|
28
|
+
if (!(schema instanceof tsukiko_1.Parser))
|
|
29
|
+
return config;
|
|
30
|
+
const result = schema.parseSafe(config);
|
|
31
|
+
if (result && !result.value)
|
|
32
|
+
return result.error;
|
|
33
|
+
return result.data;
|
|
34
|
+
}
|
|
35
|
+
class Modules {
|
|
36
|
+
handleExports(identity, ctx, exports, config) {
|
|
37
|
+
/* before handle */
|
|
38
|
+
const { lang, inject, config: schema, default: defaults, main, Main } = exports.default;
|
|
39
|
+
if (lang)
|
|
40
|
+
this.ctx.i18n.use(Array.isArray(lang) ? (0, path_1.resolve)(...lang) : (0, path_1.resolve)(lang));
|
|
41
|
+
/* handle */
|
|
42
|
+
/* service */
|
|
43
|
+
if (isServiceConsructor(defaults)) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/* adapter */
|
|
47
|
+
if (isAdapterClass(defaults)) {
|
|
48
|
+
const adapterName = identity.split(consts_1.ADAPTER_PREFIX)[1];
|
|
49
|
+
if (adapterName)
|
|
50
|
+
this.ctx[context_1.Symbols.adapter].set(adapterName, [defaults, schema]);
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/* plugin */
|
|
54
|
+
if (inject && Array.isArray(inject)) {
|
|
55
|
+
inject.forEach((identity) => {
|
|
56
|
+
ctx[context_1.Symbols.container].forEach((service, name) => {
|
|
57
|
+
if (!(service instanceof service_1.Service) || service.identity !== identity)
|
|
58
|
+
return;
|
|
59
|
+
ctx.inject(name);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const moduleConfig = checkConfig(schema, config);
|
|
64
|
+
if (moduleConfig instanceof tsukiko_1.TsuError)
|
|
65
|
+
return new errror_1.ModuleError(`Config format of module ${identity} is error: ${moduleConfig.message}`);
|
|
66
|
+
if (defaults !== undefined) {
|
|
67
|
+
if ((0, tools_1.isClass)(defaults)) {
|
|
68
|
+
return handleCconstructor(defaults, ctx, moduleConfig);
|
|
69
|
+
}
|
|
70
|
+
if (defaults instanceof Function) {
|
|
71
|
+
return handleFunction(defaults, ctx, moduleConfig);
|
|
72
|
+
}
|
|
73
|
+
return new errror_1.DevError(`Module instance of default export is not function or constructor at ${identity}`);
|
|
74
|
+
}
|
|
75
|
+
if (main instanceof Function) {
|
|
76
|
+
if ((0, tools_1.isClass)(main)) {
|
|
77
|
+
return new errror_1.DevError(`Module instance is constructor,export name should be 'Main' not 'main' at ${identity}`);
|
|
78
|
+
}
|
|
79
|
+
return handleFunction(main, ctx, moduleConfig);
|
|
80
|
+
}
|
|
81
|
+
if (Main instanceof Function) {
|
|
82
|
+
if (!(0, tools_1.isClass)(Main)) {
|
|
83
|
+
return new errror_1.DevError(`Module instance is function,export name should be 'main' not 'Main' at ${identity}`);
|
|
84
|
+
}
|
|
85
|
+
return handleCconstructor(Main, ctx, moduleConfig);
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
ctx;
|
|
90
|
+
constructor(ctx) {
|
|
91
|
+
this.ctx = ctx;
|
|
92
|
+
}
|
|
93
|
+
async use(modules, config) {
|
|
94
|
+
const isObject = typeof modules === 'object';
|
|
95
|
+
const ctx = this.ctx.extends({}, !this.ctx.identity && isObject ? modules.pkg.name : this.ctx.identity);
|
|
96
|
+
if (modules instanceof Function) {
|
|
97
|
+
if ((0, tools_1.isClass)(modules))
|
|
98
|
+
handleCconstructor(modules, ctx, config);
|
|
99
|
+
else
|
|
100
|
+
handleFunction(modules, ctx, config);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
(0, factory_1.disposeFactory)(this.ctx, () => this.dispose(modules));
|
|
104
|
+
const identity = isObject ? modules.pkg.name : modules;
|
|
105
|
+
try {
|
|
106
|
+
const exports = await import(`file://${isObject ? modules.main : (0, path_1.resolve)(modules)}`);
|
|
107
|
+
const error = this.handleExports(identity, ctx, exports, config);
|
|
108
|
+
if (error)
|
|
109
|
+
throw error;
|
|
110
|
+
this.ctx.emit('ready_module', { module: modules });
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
this.ctx.emit('ready_module', { module: modules, error });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
dispose(modules) {
|
|
117
|
+
if (typeof modules === 'object') {
|
|
118
|
+
modules.files.forEach((file) => delete require.cache[require.resolve(file)]);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
delete require.cache[require.resolve(modules)];
|
|
122
|
+
}
|
|
123
|
+
this.ctx.emit('dispose_module', { module: modules });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.Modules = Modules;
|
|
127
|
+
exports.default = Modules;
|
package/lib/consts.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { LocaleType } from '@kotori-bot/i18n';
|
|
2
1
|
export declare const OFFICIAL_MODULES_SCOPE = "@kotori-bot/";
|
|
3
2
|
export declare const PLUGIN_PREFIX = "kotori-plugin-";
|
|
3
|
+
export declare const DATABASE_PREFIX = "kotori-plugin-database-";
|
|
4
4
|
export declare const ADAPTER_PREFIX = "kotori-plugin-adapter-";
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
export declare const CUSTOM_PREFIX = "kotori-plugin-custom-";
|
|
6
|
+
export declare const DEFAULT_PORT = 720;
|
|
7
|
+
export declare const DEFAULT_CORE_CONFIG: {
|
|
8
|
+
global: {
|
|
9
|
+
lang: "en_US" | "en_GB" | "en_AU" | "zh_CN" | "zh_HK" | "zh_TW" | "zh_SG" | "es_ES" | "es_MX" | "ar_EG" | "ar_AE" | "ru_RU" | "fr_FR" | "fr_CA" | "de_DE" | "de_CH" | "it_IT" | "it_CH" | "hi_IN" | "pt_BR" | "pt_PT" | "tr_TR" | "ja_JP" | "id_ID" | "uk_UA" | "vi_VN" | "th_TH" | "sv_SE" | "nb_NO" | "da_DK" | "fi_FI" | "he_IL" | "sk_SK" | "bg_BG" | "lt_LT" | "sl_SI" | "sr_RS" | "mk_MK" | "sq_AL" | "et_EE" | "mt_MT";
|
|
10
|
+
'command-prefix': string;
|
|
11
|
+
port: number;
|
|
12
|
+
};
|
|
13
|
+
adapter: {};
|
|
14
|
+
plugin: {};
|
|
15
|
+
};
|
package/lib/consts.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.DEFAULT_CORE_CONFIG = exports.DEFAULT_PORT = exports.CUSTOM_PREFIX = exports.ADAPTER_PREFIX = exports.DATABASE_PREFIX = exports.PLUGIN_PREFIX = exports.OFFICIAL_MODULES_SCOPE = void 0;
|
|
4
|
+
const i18n_1 = require("@kotori-bot/i18n");
|
|
4
5
|
exports.OFFICIAL_MODULES_SCOPE = '@kotori-bot/';
|
|
5
6
|
exports.PLUGIN_PREFIX = 'kotori-plugin-';
|
|
7
|
+
exports.DATABASE_PREFIX = `${exports.PLUGIN_PREFIX}database-`;
|
|
6
8
|
exports.ADAPTER_PREFIX = `${exports.PLUGIN_PREFIX}adapter-`;
|
|
7
|
-
exports.
|
|
8
|
-
exports.
|
|
9
|
-
exports.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
exports.
|
|
9
|
+
exports.CUSTOM_PREFIX = `${exports.PLUGIN_PREFIX}custom-`;
|
|
10
|
+
exports.DEFAULT_PORT = 720;
|
|
11
|
+
exports.DEFAULT_CORE_CONFIG = {
|
|
12
|
+
global: {
|
|
13
|
+
lang: i18n_1.DEFAULT_LANG,
|
|
14
|
+
'command-prefix': '/',
|
|
15
|
+
port: exports.DEFAULT_PORT
|
|
16
|
+
},
|
|
17
|
+
adapter: {},
|
|
18
|
+
plugin: {}
|
|
19
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Symbols from './symbols';
|
|
2
|
+
import './events';
|
|
3
|
+
interface obj {
|
|
4
|
+
[propName: string | number | symbol]: any;
|
|
5
|
+
}
|
|
6
|
+
interface ContextOrigin {
|
|
7
|
+
readonly [Symbols.container]: Map<string, obj>;
|
|
8
|
+
readonly [Symbols.table]: Map<string, string[]>;
|
|
9
|
+
root: Context;
|
|
10
|
+
get(prop: string): obj | undefined;
|
|
11
|
+
inject<T extends Keys>(prop: T): void;
|
|
12
|
+
provide<T extends obj>(prop: string, value: T): void;
|
|
13
|
+
mixin<K extends Keys>(prop: string, keys: K[]): void;
|
|
14
|
+
extends<T extends obj>(meta?: T, identity?: string): Context;
|
|
15
|
+
}
|
|
16
|
+
interface ContextImpl extends ContextOrigin {
|
|
17
|
+
}
|
|
18
|
+
declare module './context' {
|
|
19
|
+
interface Context {
|
|
20
|
+
identity?: string;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
type Keys = keyof Omit<Context, keyof ContextOrigin> & string;
|
|
24
|
+
export declare class Context implements ContextImpl {
|
|
25
|
+
readonly [Symbols.container]: Map<string, obj>;
|
|
26
|
+
readonly [Symbols.table]: Map<string, string[]>;
|
|
27
|
+
root: Context;
|
|
28
|
+
constructor(root?: Context);
|
|
29
|
+
get<T = obj | undefined>(prop: string): T;
|
|
30
|
+
inject<T extends Keys>(prop: T): void;
|
|
31
|
+
provide<T extends obj>(prop: string, value: T): void;
|
|
32
|
+
mixin<K extends Keys>(prop: string, keys: K[]): void;
|
|
33
|
+
extends<T extends obj = object>(meta?: T, identity?: string): Context;
|
|
34
|
+
}
|
|
35
|
+
export default Context;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Context = void 0;
|
|
7
|
+
/*
|
|
8
|
+
* @Author: Hotaru biyuehuya@gmail.com
|
|
9
|
+
* @Blog: https://hotaru.icu
|
|
10
|
+
* @Date: 2024-02-07 13:44:38
|
|
11
|
+
* @LastEditors: Hotaru biyuehuya@gmail.com
|
|
12
|
+
* @LastEditTime: 2024-02-21 10:38:39
|
|
13
|
+
*/
|
|
14
|
+
const tools_1 = require("@kotori-bot/tools");
|
|
15
|
+
const symbols_1 = __importDefault(require("./symbols"));
|
|
16
|
+
const modules_1 = __importDefault(require("./modules"));
|
|
17
|
+
const handler = (value, ctx) => {
|
|
18
|
+
if (!value || typeof value !== 'object' || !(value.ctx instanceof Context))
|
|
19
|
+
return value;
|
|
20
|
+
return new Proxy(value, {
|
|
21
|
+
get(target, prop, receiver) {
|
|
22
|
+
if (prop === 'ctx')
|
|
23
|
+
return ctx;
|
|
24
|
+
return Reflect.get(target, prop, receiver);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
class Context {
|
|
29
|
+
[symbols_1.default.container] = new Map();
|
|
30
|
+
[symbols_1.default.table] = new Map();
|
|
31
|
+
root;
|
|
32
|
+
constructor(root) {
|
|
33
|
+
this.root = root || this;
|
|
34
|
+
this.provide('events', root ? root.get('events') : new tools_1.Events());
|
|
35
|
+
this.mixin('events', ['emit', 'on', 'once', 'off', 'offAll']);
|
|
36
|
+
this.provide('modules', new modules_1.default(this));
|
|
37
|
+
this.mixin('modules', ['load', 'unload', 'service']);
|
|
38
|
+
}
|
|
39
|
+
get(prop) {
|
|
40
|
+
return this[symbols_1.default.container].get(prop);
|
|
41
|
+
}
|
|
42
|
+
inject(prop) {
|
|
43
|
+
if (this[prop] && !this[symbols_1.default.container].has(prop))
|
|
44
|
+
return;
|
|
45
|
+
this[prop] = this.get(prop);
|
|
46
|
+
}
|
|
47
|
+
provide(prop, value) {
|
|
48
|
+
if (this[symbols_1.default.container].has(prop))
|
|
49
|
+
return;
|
|
50
|
+
this[symbols_1.default.container].set(prop, value);
|
|
51
|
+
}
|
|
52
|
+
mixin(prop, keys) {
|
|
53
|
+
this[symbols_1.default.table].set(prop, keys);
|
|
54
|
+
const instance = this.get(prop);
|
|
55
|
+
if (!instance)
|
|
56
|
+
return;
|
|
57
|
+
this[symbols_1.default.table].set(prop, keys);
|
|
58
|
+
keys.forEach((key) => {
|
|
59
|
+
if (this[key] || !instance[key])
|
|
60
|
+
return;
|
|
61
|
+
this[key] = instance[key];
|
|
62
|
+
if (typeof this[key] === 'function') {
|
|
63
|
+
this[key] = this[key]?.bind(instance);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
extends(meta, identity) {
|
|
68
|
+
const metaHandle = meta ?? {};
|
|
69
|
+
/* clear function */
|
|
70
|
+
Object.keys(metaHandle).forEach((key) => {
|
|
71
|
+
if (typeof this[key] === 'function')
|
|
72
|
+
delete metaHandle[key];
|
|
73
|
+
});
|
|
74
|
+
/* set proxy */
|
|
75
|
+
const ctx = new Proxy(new Context(this.root), {
|
|
76
|
+
get: (target, prop) => {
|
|
77
|
+
if (prop === 'identity')
|
|
78
|
+
return identity ?? this.identity ?? 'sub';
|
|
79
|
+
if (target[prop])
|
|
80
|
+
return handler(target[prop], ctx);
|
|
81
|
+
let value;
|
|
82
|
+
this[symbols_1.default.table].forEach((keys, key) => {
|
|
83
|
+
if (value || (typeof prop === 'string' && !keys.includes(prop)))
|
|
84
|
+
return;
|
|
85
|
+
const instance = ctx[symbols_1.default.container].get(key);
|
|
86
|
+
if (!instance)
|
|
87
|
+
return;
|
|
88
|
+
value = instance[prop];
|
|
89
|
+
if (typeof value === 'function')
|
|
90
|
+
value = value.bind(instance);
|
|
91
|
+
});
|
|
92
|
+
if (value !== undefined)
|
|
93
|
+
return value;
|
|
94
|
+
if (metaHandle[prop])
|
|
95
|
+
return handler(metaHandle[prop], ctx);
|
|
96
|
+
return handler(this[prop], ctx);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
/* set table */
|
|
100
|
+
this[symbols_1.default.table].forEach((value, key) => ctx[symbols_1.default.table].set(key, value));
|
|
101
|
+
/* set container */
|
|
102
|
+
this[symbols_1.default.container].forEach((value, key) => {
|
|
103
|
+
if (!value.ctx)
|
|
104
|
+
return ctx[symbols_1.default.container].set(key, value);
|
|
105
|
+
return ctx[symbols_1.default.container].set(key, handler(value, ctx));
|
|
106
|
+
});
|
|
107
|
+
return ctx;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.Context = Context;
|
|
111
|
+
exports.default = Context;
|