Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

npm run build時のコンパイルエラーに対処 #140

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 25 additions & 13 deletions src/ai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import chalk from 'chalk';
import { v4 as uuid } from 'uuid';

import config from '@/config.js';
import Module from '@/module.js';
import Module, { InstalledModule } from '@/module.js';
import Message from '@/message.js';
import Friend, { FriendDoc } from '@/friend.js';
import type { User } from '@/misskey/user.js';
import Stream from '@/stream.js';
import log from '@/utils/log.js';
import { sleep } from './utils/sleep.js';
import pkg from '../package.json' assert { type: 'json' };
import { Note } from '@/misskey/note.js';

type MentionHook = (msg: Message) => Promise<boolean | HandlerResult>;
type ContextHook = (key: any, msg: Message, data?: any) => Promise<void | boolean | HandlerResult>;
Expand All @@ -37,6 +38,11 @@ export type Meta = {
lastWakingAt: number;
};

export type ModuleDataDoc<Data = any> = {
module: string;
data: Data;
}

/**
* 藍
*/
Expand Down Expand Up @@ -77,10 +83,8 @@ export default class 藍 {
* @param account 藍として使うアカウント
* @param modules モジュール。先頭のモジュールほど高優先度
*/
constructor(account: User, modules: Module[]) {
this.account = account;
this.modules = modules;

@bindThis
public static start(account: User, modules: Module[]) {
let memoryDir = '.';
if (config.memoryDir) {
memoryDir = config.memoryDir;
Expand All @@ -89,7 +93,7 @@ export default class 藍 {

this.log(`Lodaing the memory from ${file}...`);

this.db = new loki(file, {
const db = new loki(file, {
autoload: true,
autosave: true,
autosaveInterval: 1000,
Expand All @@ -98,19 +102,27 @@ export default class 藍 {
this.log(chalk.red(`Failed to load the memory: ${err}`));
} else {
this.log(chalk.green('The memory loaded successfully'));
this.run();
new 藍(account, modules, db);
}
}
});
}

@bindThis
public log(msg: string) {
log(`[${chalk.magenta('AiOS')}]: ${msg}`);
藍.log(msg);
}

@bindThis
private run() {
private static log(msg: string) {
log(`[${chalk.magenta('AiOS')}]: ${msg}`);
}

private constructor(account: User, modules: Module[], db: loki) {
this.account = account;
this.modules = modules;
this.db = db;

//#region Init DB
this.meta = this.getCollection('meta', {});

Expand Down Expand Up @@ -187,7 +199,7 @@ export default class 藍 {
this.modules.forEach(m => {
this.log(`Installing ${chalk.cyan.italic(m.name)}\tmodule...`);
m.init(this);
const res = m.install();
const res = m.install(this);
if (res != null) {
if (res.mentionHook) this.mentionHooks.push(res.mentionHook);
if (res.contextHook) this.contextHooks[m.name] = res.contextHook;
Expand Down Expand Up @@ -361,7 +373,7 @@ export default class 藍 {
*/
@bindThis
public async post(param: any) {
const res = await this.api('notes/create', param);
const res = await this.api<{ createdNote: Note }>('notes/create', param);
return res.createdNote;
}

Expand All @@ -380,13 +392,13 @@ export default class 藍 {
* APIを呼び出します
*/
@bindThis
public api(endpoint: string, param?: any) {
public api<ReturnType = unknown>(endpoint: string, param?: any) {
this.log(`API: ${endpoint}`);
return got.post(`${config.apiUrl}/${endpoint}`, {
json: Object.assign({
i: config.i
}, param)
}).json();
}).json<ReturnType>();
};

/**
Expand Down
103 changes: 99 additions & 4 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,104 @@ type Config = {
memoryDir?: string;
};

import config from '../config.json' assert { type: 'json' };
import chalk from 'chalk';
import fs from "fs";
import { warn } from '@/utils/log.js';

config.wsUrl = config.host.replace('http', 'ws');
config.apiUrl = config.host + '/api';
const uncheckedConfig = JSON.parse(fs.readFileSync('./config.json', 'utf8'));

export default config as Config;
function warnWithPrefix(msg: string): void {
warn(`[Config]: ${chalk.red(msg)}`);
}

class Type<T> {
public static readonly string = new Type<string>('string');
public static readonly boolean = new Type<boolean>('boolean');

public readonly name: string;

private constructor(name: string) {
this.name = name;
}

check(value: unknown): value is T {
return typeof value == this.name;
}
}

class OptionalProperty<K extends keyof Config> {
protected readonly key: K;
protected readonly type: Type<Config[K]>

public constructor(key: K, type: Type<Config[K]>) {
this.key = key;
this.type = type;
}

check(config: Object): config is { [J in K]?: Config[K] } {
const key = this.key;
if (!(key in config)) {
return true;
}
const result = this.type.check((config as { [J in K]?: unknown})[key]);
if (!result) {
warnWithPrefix(`config.json: The type of property '${key}' must be ${this.type.name}`);
}
return result;
}
}

class Property<K extends keyof Config> extends OptionalProperty<K> {
check(config: Object): config is { [J in K]: Config[K] } {
const result = this.key in config && this.type.check((config as { [J in K]?: unknown })[this.key]);
if (!result) {
warnWithPrefix(`config.json: Property '${this.key}': ${this.type.name} required`);
}
return result;
}
}

type Intersection<P extends unknown[]> = P extends [infer Q, ...infer R] ? Q & Intersection<R> : unknown;

function checkProperties<P extends OptionalProperty<keyof Config>[]>(config: Object, ...properties: P):
config is object & Intersection<{ [I in keyof P]: P[I] extends OptionalProperty<infer K> ? { [J in K]: Config[K] } : never }> {
// メッセージを表示するためすべてのプロパティをチェックしてから結果を返す
return properties.map(p => p.check(config)).every(c => c);
}

function setProperty<K extends keyof Config>(config: Object, key: K, value: Config[K]): asserts config is { [L in K]: Config[K] } {
(config as { [L in K]?: Config[K] })[key] = value;
}

function validate(config: unknown): Config {
if (!(config instanceof Object)) {
warnWithPrefix('config.json: Root object required');
} else if (
checkProperties(
config,
new Property('host', Type.string),
new OptionalProperty('serverName', Type.string),
new Property('i', Type.string),
new OptionalProperty('master', Type.string),
new Property('keywordEnabled', Type.boolean),
new Property('reversiEnabled', Type.boolean),
new Property('notingEnabled', Type.boolean),
new Property('chartEnabled', Type.boolean),
new Property('serverMonitoring', Type.boolean),
new OptionalProperty('checkEmojisEnabled', Type.boolean),
new OptionalProperty('checkEmojisAtOnce', Type.boolean),
new OptionalProperty('mecab', Type.string),
new OptionalProperty('mecabDic', Type.string),
new OptionalProperty('memoryDir', Type.string)
)
) {
setProperty(config, 'wsUrl', config.host.replace('http', 'ws'));
setProperty(config, 'apiUrl', config.host + '/api');
return config;
}
throw new TypeError('config.json has an invalid type');
}

const config = validate(uncheckedConfig);

export default config;
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import NotingModule from './modules/noting/index.js';
import PollModule from './modules/poll/index.js';
import ReminderModule from './modules/reminder/index.js';
import CheckCustomEmojisModule from './modules/check-custom-emojis/index.js';
import { User } from '@/misskey/user.js';

console.log(' __ ____ _____ ___ ');
console.log(' /__\\ (_ _)( _ )/ __)');
Expand Down Expand Up @@ -61,7 +62,7 @@ promiseRetry(retry => {
json: {
i: config.i
}
}).json().catch(retry);
}).json<User>().catch(retry);
}, {
retries: 3
}).then(account => {
Expand All @@ -71,7 +72,7 @@ promiseRetry(retry => {
log('Starting AiOS...');

// 藍起動
new 藍(account, [
藍.start(account, [
new CoreModule(),
new EmojiModule(),
new EmojiReactModule(),
Expand Down
19 changes: 17 additions & 2 deletions src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import includes from '@/utils/includes.js';
import or from '@/utils/or.js';
import config from '@/config.js';
import { sleep } from '@/utils/sleep.js';
import { Note } from '@/misskey/note.js';

export default class Message {
private ai: 藍;
Expand Down Expand Up @@ -61,20 +62,34 @@ export default class Message {
this.friend = new Friend(ai, { user: this.user });

// メッセージなどに付いているユーザー情報は省略されている場合があるので完全なユーザー情報を持ってくる
this.ai.api('users/show', {
this.ai.api<User>('users/show', {
userId: this.userId
}).then(user => {
this.friend.updateUser(user);
});
}

public async reply(text: string, opts?: {
file?: any;
cw?: string;
renote?: string;
immediate?: boolean;
}): Promise<Note>;

public async reply(text: string | null, opts?: {
file?: any;
cw?: string;
renote?: string;
immediate?: boolean;
}): Promise<void>;

@bindThis
public async reply(text: string | null, opts?: {
file?: any;
cw?: string;
renote?: string;
immediate?: boolean;
}) {
}): Promise<Note | void> {
if (text == null) return;

this.ai.log(`>>> Sending reply to ${chalk.underline(this.id)}`);
Expand Down
2 changes: 2 additions & 0 deletions src/misskey/note.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export type Note = {
id: string;
text: string | null;
cw: string | null;
userId: string;
reply: any | null;
poll?: {
choices: {
Expand Down
Loading