From a3b529765cbfb5ce60a2df5b147bb45631527ba1 Mon Sep 17 00:00:00 2001 From: Shigma <1700011071@pku.edu.cn> Date: Tue, 13 Apr 2021 16:12:14 +0800 Subject: [PATCH] feat(eval): support yaml loader --- packages/plugin-eval/src/loaders/default.ts | 2 + packages/plugin-eval/src/loaders/esbuild.ts | 2 + .../plugin-eval/src/loaders/typescript.ts | 2 + packages/plugin-eval/src/loaders/yaml.ts | 9 +++++ packages/plugin-eval/src/worker/index.ts | 2 + packages/plugin-eval/src/worker/loader.ts | 38 ++++++++++++------- 6 files changed, 42 insertions(+), 13 deletions(-) create mode 100644 packages/plugin-eval/src/loaders/yaml.ts diff --git a/packages/plugin-eval/src/loaders/default.ts b/packages/plugin-eval/src/loaders/default.ts index 49624b68a3..6c1389507b 100644 --- a/packages/plugin-eval/src/loaders/default.ts +++ b/packages/plugin-eval/src/loaders/default.ts @@ -1,5 +1,7 @@ import { Script } from 'vm' +export const name = 'default' + export function extractScript(expr: string) { try { Reflect.construct(Script, [expr]) diff --git a/packages/plugin-eval/src/loaders/esbuild.ts b/packages/plugin-eval/src/loaders/esbuild.ts index 7f70f6f1e6..0596657914 100644 --- a/packages/plugin-eval/src/loaders/esbuild.ts +++ b/packages/plugin-eval/src/loaders/esbuild.ts @@ -1,5 +1,7 @@ import esbuild from 'esbuild' +export const name = 'typescript' + export function extractScript(expr: string) { try { esbuild.transformSync(expr, { diff --git a/packages/plugin-eval/src/loaders/typescript.ts b/packages/plugin-eval/src/loaders/typescript.ts index 340310c7bf..da683ee3ac 100644 --- a/packages/plugin-eval/src/loaders/typescript.ts +++ b/packages/plugin-eval/src/loaders/typescript.ts @@ -7,6 +7,8 @@ import { Logger } from 'koishi-utils' export { extractScript } from './default' +export const name = 'typescript' + const compilerOptions: ts.CompilerOptions = { inlineSourceMap: true, module: ts.ModuleKind.ES2020, diff --git a/packages/plugin-eval/src/loaders/yaml.ts b/packages/plugin-eval/src/loaders/yaml.ts new file mode 100644 index 0000000000..5b8d31d9f6 --- /dev/null +++ b/packages/plugin-eval/src/loaders/yaml.ts @@ -0,0 +1,9 @@ +import { load } from 'js-yaml' + +export const name = 'yaml' + +export const isTextLoader = false + +export function transformModule(source: string) { + return load(source) +} diff --git a/packages/plugin-eval/src/worker/index.ts b/packages/plugin-eval/src/worker/index.ts index 26f1af4db1..e20ac6eca4 100644 --- a/packages/plugin-eval/src/worker/index.ts +++ b/packages/plugin-eval/src/worker/index.ts @@ -41,6 +41,8 @@ export interface WorkerData extends WorkerConfig { } export interface Loader { + name: string + isTextLoader: boolean prepare(config: WorkerData): void | Promise extractScript(expr: string): string transformScript(expr: string): string | Promise diff --git a/packages/plugin-eval/src/worker/loader.ts b/packages/plugin-eval/src/worker/loader.ts index 2f64d1b548..3b2ae5b875 100644 --- a/packages/plugin-eval/src/worker/loader.ts +++ b/packages/plugin-eval/src/worker/loader.ts @@ -30,6 +30,7 @@ export function synthetize(identifier: string, namespace: {}, globalName?: strin modules[identifier] = module config.addonNames?.unshift(identifier) if (globalName) synthetics[globalName] = module + return module } const suffixes = ['', '.js', '.ts', '/index.js', '/index.ts'] @@ -102,10 +103,6 @@ export async function safeWriteFile(filename: string, data: any) { } } -declare const BUILTIN_LOADERS: string[] - -const loaders: Record = {} - export default async function prepare() { if (!config.root) return const cachePath = resolve(config.root, config.cacheFile || '.koishi/cache') @@ -132,6 +129,10 @@ function exposeGlobal(name: string, namespace: {}) { internal.setGlobal(name, outer) } +declare const BUILTIN_LOADERS: string[] +const fileAssoc: Record = {} +const loaderSet = new Set() + function resolveLoader(extension: string) { const filename = config.moduleLoaders[extension] if (BUILTIN_LOADERS.includes(filename)) { @@ -140,6 +141,8 @@ function resolveLoader(extension: string) { return require(resolve(process.cwd(), filename)) } else if (extension === '.js') { return require('../loaders/default') + } else if (extension === '.yml' || extension === '.yaml') { + return require('../loaders/yaml') } else if (extension === '.ts') { for (const filename of ['esbuild', 'typescript']) { try { @@ -148,14 +151,18 @@ function resolveLoader(extension: string) { } throw new Error('cannot resolve loader for ".ts", you should install either esbuild or typescript + json5 by yourself') } else { - throw new Error(`cannot resolve loader for "${extension}", you should specify a custom loader through "config.moduleLoaders"`) + throw new Error(`cannot resolve loader for "${extension}", you should specify a custom loader via "config.moduleLoaders"`) } } async function createLoader(extension: string) { const loader: Loader = resolveLoader(extension) - logger.debug('creating loader for %c', extension) - await loader.prepare?.(config) + // loader.prepare() should only be called once + if (!loaderSet.has(loader)) { + loaderSet.add(loader) + logger.debug('creating loader %c', loader.name) + await loader.prepare?.(config) + } return loader } @@ -169,13 +176,18 @@ async function createModule(path: string) { const { outputText, cachedData } = files[source] = cache module = new SourceTextModule(outputText, { context, identifier, cachedData }) } else { - type = 'source text' const extension = extname(identifier) - const loader = loaders[extension] ||= await createLoader(extension) - const outputText = await loader.transformModule(source) - module = new SourceTextModule(outputText, { context, identifier }) - const cachedData = module.createCachedData() - files[source] = { outputText, cachedData } + const loader = fileAssoc[extension] ||= await createLoader(extension) + if (loader.isTextLoader !== false) { + type = 'source text' + const outputText = await loader.transformModule(source) + module = new SourceTextModule(outputText, { context, identifier }) + const cachedData = module.createCachedData() + files[source] = { outputText, cachedData } + } else { + const exports = await loader.transformModule(source) + module = synthetize(identifier, { default: exports }) + } } modules[identifier] = module } else if (module.status !== 'unlinked') {