UNPKG

@ainc/script

Version:

Script compiler for typescript

182 lines (143 loc) 4.41 kB
/** ***************************************** * Created by edonet@163.com * Created on 2020-05-21 14:03:13 ***************************************** */ 'use strict'; /** ***************************************** * 加载依赖 ***************************************** */ import * as path from 'path'; import * as vm from './vm'; import { watch, Watcher } from './watcher'; /** ***************************************** * 执行文件接口 ***************************************** */ export function invoke(file: string, args: unknown[] = [], context: unknown = null): unknown { const script = execute(file); // 处理函数 if (typeof script === 'function') { return script.apply(context, args); } // 处理默认函数 if (script && typeof script === 'object') { const { default: handler } = script as { default?(...args: any[]): unknown }; // 执行默认函数 if (typeof handler === 'function') { return handler.apply(context, args); } } } /** ***************************************** * 执行代码 ***************************************** */ export function run<T>(code: string, filename = '_script.js'): T { if (code && typeof code === 'string') { return vm.load<T>(path.resolve(filename), code).exports; } // 返回空对象 return {} as T; } /** ***************************************** * 执行文件 ***************************************** */ export function execute<T>(filename: string, context = process.cwd()): T { return run<T>( `module.exports = require(${JSON.stringify(path.resolve(context, filename))});` ); } /** ***************************************** * 脚本 ***************************************** */ export class Script<T> { /** 脚本对象 */ private $script?: vm.Script; /** 文件列表 */ public get files(): string[] { return this.$script ? vm.findDependencies(this.$script) : []; } /** 抛出接口 */ public get exports(): T { return (this.$script ? this.$script.exports : {}) as T; } /** 脚本目录 */ public get dirname(): string { return path.dirname(this.filename); } /** 脚本文件 */ public get filename(): string { return this.$script ? this.$script.filename : path.resolve('_script.js'); } /** 执行文件 */ public execute(filename: string, context = process.cwd()): T { return this.run( `module.exports = require(${JSON.stringify(path.resolve(context, filename))});` ); } /** 执行代码 */ public run(code: string, filename = '_script.js'): T { // 校验参数 if (typeof code !== 'string') { throw new Error('expect `code` to be string!'); } // 生成脚本 const script = vm.load<T>(path.resolve(filename), code); // 缓存脚本对象 Object.defineProperty(this, '$script', { value: script, enumerable: false, configurable: true, }); // 返回结果 return script.exports; } /** 重载模块 */ public reload(files?: string[]): T { // 不存在脚本文件 if (!this.$script) { return {} as T; } // 获取代码 const code = this.$script._code || ''; const filename = this.$script.filename; // 刷新依赖文件 vm.refresh(this.$script, files || []); // 执行模块 return this.run(code, filename); } /** 监听模块变更 */ public watch(callback: (data: T) => void): Watcher { const watcher = watch(this.files); // 监听文件变更 watcher.on('change', (file: string) => { const deps = new Set(this.files); // 执行回调 callback(this.reload([file])); // 添加依赖 this.files.forEach(file => { deps.has(file) ? deps.delete(file) : watcher.add(file); }); // 清除依赖 deps.forEach(file => watcher.unwatch(vm.clear(file))); }); // 返回监听器 return watcher; } } /** ***************************************** * 抛出接口 ***************************************** */ export default Script;