diff --git a/package.json b/package.json index 326c4d3656..b5665fcdf4 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "private": true, "workspaces": [ "atri", + "addons", "shiki", "shiki/core", "shiki/cosmos", @@ -11,6 +12,7 @@ ], "scripts": { "atri": "yarn workspace atri", + "addons": "yarn workspace addons", "build": "tsc -b && yarn workspace koishi-plugin-eval wrap", "build:ci": "tsc -b --listEmittedFiles && yarn workspace koishi-plugin-eval wrap", "bump": "ts-node build/bump", diff --git a/packages/plugin-eval-addons/package.json b/packages/plugin-eval-addons/package.json index 294a02f688..49e35f0767 100644 --- a/packages/plugin-eval-addons/package.json +++ b/packages/plugin-eval-addons/package.json @@ -41,8 +41,12 @@ }, "dependencies": { "js-yaml": "^3.14.0", + "json5": "^2.1.3", "koishi-utils": "^3.1.0", "simple-git": "^2.20.1", "typescript": "^4.0.2" + }, + "devDependencies": { + "@types/json5": "^0.0.30" } } diff --git a/packages/plugin-eval-addons/src/worker.ts b/packages/plugin-eval-addons/src/worker.ts index 88bf4afbe0..5e2d6e0ea1 100644 --- a/packages/plugin-eval-addons/src/worker.ts +++ b/packages/plugin-eval-addons/src/worker.ts @@ -1,9 +1,10 @@ -import { config, context, internal, WorkerAPI, createContext, response } from 'koishi-plugin-eval/dist/worker' +import { config, context, internal, WorkerAPI, createContext, response, mapDirectory } from 'koishi-plugin-eval/dist/worker' import { promises, readFileSync } from 'fs' import { resolve, posix, dirname } from 'path' import { User } from 'koishi-core' -import { Logger } from 'koishi-utils' +import { Logger, Time, CQCode, Random } from 'koishi-utils' import { Config } from '.' +import json5 from 'json5' import ts from 'typescript' const logger = new Logger('addon') @@ -57,16 +58,28 @@ interface Module { evaluate(): Promise } -const builtinIdentifier = 'koishi/addons.ts' -const builtin = new SyntheticModule(['registerCommand'], function () { - this.setExport('registerCommand', function registerCommand(name: string, callback: AddonAction) { +const root = resolve(process.cwd(), config.moduleRoot) +const modules: Record = {} + +export function createSynthetic(identifier: string, exports: {}) { + const module = new SyntheticModule(Object.keys(exports), function () { + for (const key in exports) { + this.setExport(key, exports[key]) + } + }, { context, identifier }) + modules[identifier] = module + config.addonNames.unshift(identifier) +} + +createSynthetic('koishi/addons.ts', { + registerCommand(name: string, callback: AddonAction) { commandMap[name] = callback - }) -}, { context, identifier: builtinIdentifier }) + }, +}) -const root = resolve(process.cwd(), config.moduleRoot) -const modules: Record = { [builtinIdentifier]: builtin } -config.addonNames.unshift(...Object.keys(modules)) +createSynthetic('koishi/utils.ts', { + Time, CQCode, Random, +}) const suffixes = ['', '.ts', '/index.ts'] const relativeRE = /^\.\.?[\\/]/ @@ -98,7 +111,7 @@ async function linker(specifier: string, { identifier }: Module) { throw new Error(`Unable to resolve dependency "${specifier}" in "${identifier}"`) } -const json = JSON.parse(readFileSync(resolve(root, 'tsconfig.json'), 'utf8')) +const json = json5.parse(readFileSync(resolve(root, 'tsconfig.json'), 'utf8')) const { options: compilerOptions } = ts.parseJsonConfigFileContent(json, ts.sys, root) async function loadSource(path: string) { @@ -124,14 +137,17 @@ async function createModule(path: string) { logger.debug('creating module %c', module.identifier) await module.link(linker) await module.evaluate() + + if (module instanceof SourceTextModule) { + internal.setGlobal(path, module.namespace) + } return module } -export default Promise.all(config.addonNames.map(path => createModule(path).then((module) => { - internal.setGlobal(path, module.namespace) -}, (error) => { +export default Promise.all(config.addonNames.map(path => createModule(path).catch((error) => { logger.warn(`cannot load module %c\n` + error.stack, path) - delete modules[path] }))).then(() => { response.commands = Object.keys(commandMap) + mapDirectory('koishi/utils/', require.resolve('koishi-utils')) + internal.setGlobal('utils', modules['koishi/utils.ts'].namespace) }) diff --git a/packages/plugin-eval/src/worker.ts b/packages/plugin-eval/src/worker.ts index b5dd756bb7..e4a730e58b 100644 --- a/packages/plugin-eval/src/worker.ts +++ b/packages/plugin-eval/src/worker.ts @@ -2,6 +2,7 @@ import { Logger, escapeRegExp } from 'koishi-utils' import { parentPort, workerData } from 'worker_threads' import { InspectOptions, formatWithOptions } from 'util' import { findSourceMap } from 'module' +import { dirname, sep } from 'path' /* eslint-disable import/first */ @@ -119,9 +120,13 @@ export class WorkerAPI { } } +export function mapDirectory(identifier: string, filename: string) { + const path = dirname(findSourceMap(filename).payload.sources[0].slice(7)) + sep + pathMapper[identifier] = new RegExp(`(at | \\()${escapeRegExp(path)}`, 'g') +} + Promise.all(Object.values(config.setupFiles).map(file => require(file).default)).then(() => { - const path = findSourceMap(__filename).payload.sources[0].slice(7, -9) - pathMapper['koishi/'] = new RegExp(`(at | \\()${escapeRegExp(path)}`, 'g') + mapDirectory('koishi/', __filename) Object.entries(config.setupFiles).forEach(([name, path]) => { const sourceMap = findSourceMap(path) if (sourceMap) path = sourceMap.payload.sources[0].slice(7)