Skip to content

Commit

Permalink
Enable VM ESM loading for sidecar-dump util (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
huan committed Sep 4, 2021
1 parent 80c1cd3 commit f2b52a7
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 38 deletions.
2 changes: 1 addition & 1 deletion bin/sidecar-dump.ts
Original file line number Diff line number Diff line change
@@ -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
*
Expand Down
2 changes: 1 addition & 1 deletion src/dump/extract-class-names.spec.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
32 changes: 18 additions & 14 deletions src/dump/metadata-handler.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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 <metadata>', source)
log.silly('sidecar-dump <metadata>', 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')
Expand Down
2 changes: 1 addition & 1 deletion src/dump/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down
3 changes: 2 additions & 1 deletion src/dump/source-handler.spec.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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)
Expand Down
45 changes: 26 additions & 19 deletions src/dump/source-handler.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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 <source>', 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 }
2 changes: 1 addition & 1 deletion src/dump/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down
36 changes: 36 additions & 0 deletions src/dump/vm.ts
Original file line number Diff line number Diff line change
@@ -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<void>
evaluate (): Promise<void>

}
}

export { vm }
export default vm

0 comments on commit f2b52a7

Please sign in to comment.