diff --git a/src/askvm/lib/factory.ts b/src/askvm/lib/factory.ts new file mode 100644 index 00000000..90518bd5 --- /dev/null +++ b/src/askvm/lib/factory.ts @@ -0,0 +1,25 @@ +import { resource, Resource } from './resource'; +import { any } from './type'; + +/** + * Resource factory generates the resource wrappers around all the methods which are on `whitelist` of the `module` passed. Implementation of https://github.com/CatchTheTornado/askql/issues/580 for limited JS function calls inside AskScript + * @param module JS object which methods will be wrapped as resource handlers + * @param whitelist list of strings including function/method names of the module to be wrapped out + */ +export function factory( + jsModule: any, + whitelist: string[] +): Record> { + const res: Record> = {}; + whitelist.forEach((k) => { + if (k in jsModule) { + res[k] = resource({ + type: any, + async resolver(...args: any) { + return jsModule[k](...args); + }, + }); + } + }); + return res; +} diff --git a/src/askvm/lib/index.ts b/src/askvm/lib/index.ts index 25f0ba08..d0756735 100644 --- a/src/askvm/lib/index.ts +++ b/src/askvm/lib/index.ts @@ -3,3 +3,4 @@ export * from './resource'; export * from './run'; export * from './type'; export * from './typed'; +export * from './factory'; diff --git a/src/askvm/resources/core/__tests__/factory.test.ts b/src/askvm/resources/core/__tests__/factory.test.ts new file mode 100644 index 00000000..a18578f2 --- /dev/null +++ b/src/askvm/resources/core/__tests__/factory.test.ts @@ -0,0 +1,48 @@ +import { runUntyped } from '../../../index'; +import { parse } from '../../../../askcode/lib'; +import { factory } from '../../../lib/factory'; +import * as core from '..'; + +const values = {}; +const moduleToBeWrapped = { + wrapMe1: () => { + return 100; + }, + wrapMe2: (arg: string) => { + return arg; + }, + dontWrapMe: () => { + return 0; + }, +}; +const wrappedResources = factory(moduleToBeWrapped, ['wrapMe1', 'wrapMe2']); + +function ask(code: string) { + return runUntyped( + { + resources: { ...core, ...wrappedResources }, + values, + }, + parse(code) + ); +} + +describe(`factory`, function () { + it(`factory should wrap only whitelisted resources`, async function () { + await expect( + Promise.resolve(Object.keys(wrappedResources)) + ).resolves.toStrictEqual(['wrapMe1', 'wrapMe2']); + }); + it(`should wrap wrapMe1 js method and return 100`, async function () { + const expectedResult = 100; + await expect(ask(`ask(call(get('wrapMe1')))`)).resolves.toStrictEqual( + expectedResult + ); + }); + it(`should wrap wrapMe2 js method and return arg`, async function () { + const expectedResult = 'arg'; + await expect( + ask(`ask(call(get('wrapMe2'), 'arg'))`) + ).resolves.toStrictEqual(expectedResult); + }); +});