diff --git a/hammer.mjs b/hammer.mjs index 14de323..20935fe 100644 --- a/hammer.mjs +++ b/hammer.mjs @@ -1,5 +1,5 @@ -export async function clean() { - console.log('clean') +export async function clean(a, b) { + console.log('clean', a, b) } export async function start() { diff --git a/package.json b/package.json index 58efc1d..19ec935 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sinclair/hammer", - "version": "0.15.6", + "version": "0.15.7", "description": "Build Tool for Browser and Node Applications", "author": "sinclairzx81", "keywords": [ diff --git a/src/evaluate/compile/compile.ts b/src/evaluate/compile/compile.ts new file mode 100644 index 0000000..be38ace --- /dev/null +++ b/src/evaluate/compile/compile.ts @@ -0,0 +1,53 @@ +/*-------------------------------------------------------------------------- + +MIT License + +Copyright (c) Hammer 2021 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { buildSync } from 'esbuild' +import * as fs from 'fs' +import * as path from 'path' + +export interface CompileResult { + filename: string + dirname: string + code: string +} + +/** Compiles the given code into single executable script. */ +export function compile(scriptPath: string): CompileResult { + const filename = path.resolve(scriptPath) + if(!fs.existsSync(filename)) throw Error(`Cannot locate scriptPath ${scriptPath}`) + const dirname = path.dirname(filename) + const result = buildSync({ + entryPoints: [scriptPath], + platform: 'node', + target: 'esnext', + bundle: true, + write: false, + outdir: 'out', + }) + const uint8 = result.outputFiles[0].contents + const code = Buffer.from(uint8).toString() + return { filename, dirname, code } +} \ No newline at end of file diff --git a/src/evaluate/compile/index.ts b/src/evaluate/compile/index.ts new file mode 100644 index 0000000..6571920 --- /dev/null +++ b/src/evaluate/compile/index.ts @@ -0,0 +1,27 @@ +/*-------------------------------------------------------------------------- + +MIT License + +Copyright (c) Hammer 2021 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './compile' \ No newline at end of file diff --git a/src/evaluate/evaluate.ts b/src/evaluate/evaluate.ts new file mode 100644 index 0000000..4442fd7 --- /dev/null +++ b/src/evaluate/evaluate.ts @@ -0,0 +1,34 @@ +/*-------------------------------------------------------------------------- + +MIT License + +Copyright (c) Hammer 2021 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { execute, AdditionalGlobals } from './execute/index' +import { compile } from './compile/index' + +/** Executes the given script in memory, and returns it's exports. */ +export function evaluate(scriptPath: string, additional: AdditionalGlobals = {}) { + const result = compile(scriptPath) + return execute(result, additional) +} \ No newline at end of file diff --git a/src/evaluate/execute/execute.ts b/src/evaluate/execute/execute.ts new file mode 100644 index 0000000..83a3905 --- /dev/null +++ b/src/evaluate/execute/execute.ts @@ -0,0 +1,56 @@ +/*-------------------------------------------------------------------------- + +MIT License + +Copyright (c) Hammer 2021 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { CompileResult } from '../compile/index' +import * as path from 'path' +import * as vm from 'vm' + +export type AdditionalGlobals = { [name: string]: any } + +/** + * Evaluates a compilation result. The script is evaluated inside a Node + * context as a module. Any exports from the module are returned as a + * result. + */ +export function execute(result: CompileResult, additional: AdditionalGlobals): {[key: string]: any } { + const exports = {} + const context = vm.createContext({ + ...global, + ...additional, + require: (module: string) => { + try { return require(module) } catch { /** ignore */ } + return require(path.join(process.cwd(), module)) + }, + __dirname: result.dirname, + __filename: path.resolve(result.filename), + Buffer, + process, + console, + exports, + }) + vm.runInNewContext(result.code, context) + return exports +} \ No newline at end of file diff --git a/src/evaluate/execute/index.ts b/src/evaluate/execute/index.ts new file mode 100644 index 0000000..1a18abe --- /dev/null +++ b/src/evaluate/execute/index.ts @@ -0,0 +1,27 @@ +/*-------------------------------------------------------------------------- + +MIT License + +Copyright (c) Hammer 2021 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './execute' \ No newline at end of file diff --git a/src/evaluate/index.ts b/src/evaluate/index.ts new file mode 100644 index 0000000..8082c1a --- /dev/null +++ b/src/evaluate/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +MIT License + +Copyright (c) Hammer 2021 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './compile/index' +export * from './execute/index' +export * from './evaluate' \ No newline at end of file diff --git a/src/task/task.ts b/src/task/task.ts index 350fc64..7977671 100644 --- a/src/task/task.ts +++ b/src/task/task.ts @@ -24,63 +24,11 @@ SOFTWARE. ---------------------------------------------------------------------------*/ -import { buildSync } from 'esbuild' - import { file, folder, shell, watch, delay } from './global/index' -import * as path from 'path' -import * as vm from 'vm' -import * as fs from 'fs' - -export class TaskError extends Error { - constructor(public readonly task: string, public readonly reason: string) { - super(`${task}: ${reason}`) - } -} - -export type TaskExports = { [key: string]: Function } - -function build(scriptPath: string): string { - try { - const result = buildSync({ - entryPoints: [scriptPath], - platform: 'node', - target: 'esnext', - bundle: true, - write: false, - outdir: 'out', - }) - const uint8 = result.outputFiles[0].contents - return Buffer.from(uint8).toString() - } catch (error) { - console.error(error.message) - return '' - } -} - -function instance(scriptPath: string, code: string): TaskExports { - const context = vm.createContext({ - ...global, - require: (module: string) => { - try { return require(module) } catch { /** ignore */ } - return require(path.join(process.cwd(), module)) - }, - __dirname: process.cwd(), - __filename: path.resolve(scriptPath), - delay, - file, - folder, - shell, - watch, - Buffer, - process, - console, - exports: {} - }) - vm.runInNewContext(code, context) - return context.exports -} +import { evaluate } from '../evaluate/index' +import * as fs from 'fs' -export function print(exports: TaskExports) { +function print(exports: any) { console.log() console.log('The following tasks are available') console.log() @@ -89,22 +37,22 @@ export function print(exports: TaskExports) { console.log() } -async function execute(exports: TaskExports, name: string, params: any[]) { +async function call(exports: any, name: string, params: any[]) { const task = exports[name] if(task === undefined) return print(exports) await task.apply(null, params) } +/** Executes a task in the given scriptPath. */ export async function task(scriptPath: string, name: string, params: any[]) { if(!fs.existsSync(scriptPath)) { console.log(`Task: Task file 'hammer.mjs' not found.`) process.exit(1) } try { - const code = build(scriptPath) - const exports = instance(scriptPath, code) - await execute(exports, name, params) - } catch(error) { + const exports = evaluate(scriptPath, { delay, file, folder, shell, watch }) + await call(exports, name, params) + } catch(error: any) { const message = error.message || error console.log(`Error: [${name}] ${message}`) process.exit(1)