diff --git a/bin/sidecar-dump.ts b/bin/sidecar-dump.ts index 7742526..61d35a7 100644 --- a/bin/sidecar-dump.ts +++ b/bin/sidecar-dump.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env node --no-warnings --loader ts-node/esm +#!/usr/bin/env node --experimental-vm-modules /** * https://github.com/huan/sidecar * diff --git a/src/dump/extract-class-names.spec.ts b/src/dump/extract-class-names.spec.ts index 06c9683..c268fcd 100755 --- a/src/dump/extract-class-names.spec.ts +++ b/src/dump/extract-class-names.spec.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env -S node --no-warnings --loader ts-node/esm +#!/usr/bin/env -S node --no-warnings --loader ts-node/esm --experimental-vm-modules import { test } from 'tstest' import fs from 'fs' diff --git a/src/dump/metadata-handler.ts b/src/dump/metadata-handler.ts index fad22b2..b41223c 100644 --- a/src/dump/metadata-handler.ts +++ b/src/dump/metadata-handler.ts @@ -1,13 +1,11 @@ /* eslint-disable sort-keys */ -import vm from 'vm' -import path from 'path' - import slash from 'slash' import { log } from '../config.js' import { getMetadataSidecar } from '../decorators/sidecar/metadata-sidecar.js' import { extractClassNameList } from './extract-class-names.js' +import vm from './vm.js' const metadataHandler = async ({ file, @@ -41,25 +39,31 @@ const metadataHandler = async ({ name = classNameList[0] } - const context = { + const context = vm.createContext({ + console, getMetadataSidecar, metadata: undefined, - require, - - __filename: file, - __dirname: path.dirname(require.resolve(file)), - } as { + }) as { metadata?: string, } - const source = [ - `const { ${name} } = require('${file}')`, + const code = [ + `const { ${name} } = await import('${file}')`, `metadata = JSON.stringify(getMetadataSidecar(${name}), null, 2)`, ].join('\n') - log.silly('sidecar-dump ', source) + log.silly('sidecar-dump ', code) + + const importModuleDynamically = ( + identifier: string + ) => import(identifier) + + const module = new vm.SourceTextModule(code, { + context, + importModuleDynamically, + }) - vm.createContext(context) // Contextify the object - vm.runInContext(source, context) + await module.link(() => {}) + await module.evaluate() if (!context.metadata) { throw new Error('no context.metadata found') diff --git a/src/dump/metadata.ts b/src/dump/metadata.ts index 6c542ef..4bbd559 100644 --- a/src/dump/metadata.ts +++ b/src/dump/metadata.ts @@ -6,7 +6,7 @@ import { positional, string, } from 'cmd-ts' -import { File } from 'cmd-ts/dist/cjs/batteries/fs' +import { File } from 'cmd-ts/dist/cjs/batteries/fs.js' import { metadataHandler } from './metadata-handler.js' diff --git a/src/dump/source-handler.spec.ts b/src/dump/source-handler.spec.ts index 5e414f8..f541e0b 100755 --- a/src/dump/source-handler.spec.ts +++ b/src/dump/source-handler.spec.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env -S node --no-warnings --loader ts-node/esm +#!/usr/bin/env -S node --no-warnings --loader ts-node/esm --experimental-vm-modules import { test } from 'tstest' import fs from 'fs' @@ -39,6 +39,7 @@ test('sourceHandler()', async t => { .toString() const source = await sourceHandler({ file: CLASS_FILE }) + // console.info('source:', source) /** * Generate the testing fixture file, Huan(202107) diff --git a/src/dump/source-handler.ts b/src/dump/source-handler.ts index 88dc943..e5a81ac 100644 --- a/src/dump/source-handler.ts +++ b/src/dump/source-handler.ts @@ -1,10 +1,8 @@ /* eslint-disable sort-keys */ -import vm from 'vm' -import path from 'path' - import slash from 'slash' import { log } from '../config.js' +import vm from './vm.js' import { getMetadataSidecar } from '../decorators/sidecar/metadata-sidecar.js' import { buildAgentSource } from '../agent/build-agent-source.js' @@ -46,31 +44,40 @@ const sourceHandler = async ({ ) } - const context = { + const context = vm.createContext({ buildAgentSource, + console, + generated: undefined, getMetadataSidecar, - require, - - __filename : file, - __dirname : path.dirname(require.resolve(file)), + }) as { + generated?: string, } const code = [ - '(async () => {', - [ - `const { ${name} } = require('${file}')`, - `const metadata = getMetadataSidecar(${name})`, - 'const output = await buildAgentSource(metadata)', - 'return output', - ].join('\n'), - '})()', + `const { ${name} } = await import('${file}')`, + `const metadata = getMetadataSidecar(${name})`, + 'generated = await buildAgentSource(metadata)', ].join('\n') + log.silly('sidecar-dump ', code) - const script = new vm.Script(code) - const generatedCode = await script.runInNewContext(context) + const importModuleDynamically = ( + identifier: string + ) => import(identifier) + + const module = new vm.SourceTextModule(code, { + context, + importModuleDynamically, + }) + + await module.link(() => {}) + await module.evaluate() + + if (!context.generated) { + throw new Error('no context.generated found') + } - return generatedCode + return context.generated } export { sourceHandler } diff --git a/src/dump/source.ts b/src/dump/source.ts index 514283c..c3dd79d 100644 --- a/src/dump/source.ts +++ b/src/dump/source.ts @@ -6,7 +6,7 @@ import { positional, string, } from 'cmd-ts' -import { File } from 'cmd-ts/dist/cjs/batteries/fs' +import { File } from 'cmd-ts/dist/cjs/batteries/fs.js' import { sourceHandler } from './source-handler.js' diff --git a/src/dump/vm.ts b/src/dump/vm.ts new file mode 100644 index 0000000..147d040 --- /dev/null +++ b/src/dump/vm.ts @@ -0,0 +1,36 @@ +import vm from 'vm' + +/** + * importModuleDynamically for vm module is cached #36351 + * https://github.com/nodejs/node/issues/36351 + */ +declare module 'vm' { + export interface SourceTextModuleOptions { + importModuleDynamically: ( + specifier: string, + module?: any, + ) => any + context?: vm.Context + } + + export type Linker = ( + specifier: string, + extra: Object, + referencingModule: any, + ) => any + + export class SourceTextModule { + + constructor ( + code: string, + options?: SourceTextModuleOptions, + ) + + link (linker: Linker): Promise + evaluate (): Promise + + } +} + +export { vm } +export default vm