diff --git a/packages/transform-eventual-send/package.json b/packages/transform-eventual-send/package.json index 9f79863753e..307f1f128e9 100644 --- a/packages/transform-eventual-send/package.json +++ b/packages/transform-eventual-send/package.json @@ -7,20 +7,13 @@ "test": "tape -r esm 'test/**/*.js'", "lint-fix": "eslint --fix '**/*.js'", "lint-check": "eslint '**/*.js'", - "build": "node -r esm ./scripts/build-esend.js" + "build": "exit 0" }, "devDependencies": { "@agoric/acorn-eventual-send": "^2.0.5", "@agoric/babel-parser": "^7.6.4", - "@agoric/bundle-source": "^1.1.5", - "@agoric/eventual-send": "^0.9.2", - "@agoric/harden": "^0.0.8", "@babel/generator": "^7.5.0", - "astring": "^1.4.0", "esm": "^3.2.5", - "rollup": "^1.16.6", - "rollup-plugin-node-resolve": "^5.2.0", - "ses": "^0.6.5", "tap-spec": "^5.0.0", "tape": "^4.9.2", "tape-promise": "^4.0.0" diff --git a/packages/transform-eventual-send/rollup.config.js b/packages/transform-eventual-send/rollup.config.js deleted file mode 100644 index e77809ebf06..00000000000 --- a/packages/transform-eventual-send/rollup.config.js +++ /dev/null @@ -1,23 +0,0 @@ -import resolve from 'rollup-plugin-node-resolve'; - -export default [ - { - input: 'src/index.js', - output: [ - { - file: 'dist/transform-eventual-send.umd.js', - format: 'umd', - name: 'makeEventalSendTransformer', - }, - { - file: 'dist/transform-eventual-send.esm.js', - format: 'esm', - }, - { - file: 'dist/transform-eventual-send.cjs.js', - format: 'cjs', - }, - ], - plugins: [resolve()], - }, -]; diff --git a/packages/transform-eventual-send/scripts/build-esend.js b/packages/transform-eventual-send/scripts/build-esend.js deleted file mode 100755 index abf9c5687b5..00000000000 --- a/packages/transform-eventual-send/scripts/build-esend.js +++ /dev/null @@ -1,27 +0,0 @@ -#! /usr/bin/env node -import fs from 'fs'; -import process from 'process'; -import bundleSource from '@agoric/bundle-source'; - -async function main() { - const esend = require.resolve(`@agoric/eventual-send`); - const bundle = await bundleSource(esend); - const fileContents = `export default ${JSON.stringify(bundle)};`; - try { - await fs.promises.mkdir('src/bundles'); - } catch (e) { - if (!e || e.code !== 'EEXIST') { - throw e; - } - } - await fs.promises.writeFile('src/bundles/eventual-send.js', fileContents); -} - -main().then( - _ => process.exit(0), - err => { - console.log('error creating src/bundles/eventual-send.js:'); - console.log(err); - process.exit(1); - }, -); diff --git a/packages/transform-eventual-send/src/rewriter.js b/packages/transform-eventual-send/src/rewriter.js deleted file mode 100644 index d5208d26b5d..00000000000 --- a/packages/transform-eventual-send/src/rewriter.js +++ /dev/null @@ -1,86 +0,0 @@ -import { makeTransform } from './index'; -import eventualSendBundle from './bundles/eventual-send'; - -// this transformer is meant for the SES1 evaluation format, with mutable -// endowments and stuff - -function makeEventualSendTransformer(parser, generate) { - const transformer = makeTransform(parser, generate); - let HandledPromise; - let evaluateProgram; - let myRequire; - let recursive = false; - const transform = { - closeOverSES(s) { - // FIXME: This will go away when we can bundle an @agoric/harden that understands SES. - myRequire = name => { - if (name === '@agoric/harden') { - return s.global.SES.harden; - } - throw Error(`Unrecognized require ${name}`); - }; - // FIXME: This should be replaced with ss.evaluateProgram support in SES. - evaluateProgram = (src, endowments = {}) => s.evaluate(src, endowments); - }, - rewrite(ss) { - const source = ss.src; - const endowments = ss.endowments || {}; - if (!recursive && !('HandledPromise' in endowments)) { - // Use a getter to postpone initialization. - Object.defineProperty(endowments, 'HandledPromise', { - get() { - if (!HandledPromise) { - // Get a HandledPromise endowment for the evaluator. - // It will be hardened in the evaluator's context. - const nestedEvaluate = src => - (evaluateProgram || ss.evaluateProgram)(src, { - require: myRequire || require, - nestedEvaluate, - }); - const { - source: evSendSrc, - moduleFormat, - sourceMap, - } = eventualSendBundle; - if ( - moduleFormat === 'getExport' || - moduleFormat === 'nestedEvaluate' - ) { - recursive = true; - try { - const ns = nestedEvaluate(`(${evSendSrc}\n${sourceMap})`)(); - HandledPromise = ns.HandledPromise; - } finally { - recursive = false; - } - } else { - throw Error(`Unrecognized moduleFormat ${moduleFormat}`); - } - } - return HandledPromise; - }, - }); - } - - const maybeSource = transformer(source); - - // Work around Babel appending semicolons. - const actualSource = - ss.sourceType === 'expression' && - maybeSource.endsWith(';') && - !source.endsWith(';') - ? maybeSource.slice(0, -1) - : maybeSource; - - return { - ...ss, - endowments, - src: actualSource, - }; - }, - }; - - return [transform]; -} - -export default makeEventualSendTransformer; diff --git a/packages/transform-eventual-send/test/ses-test.js b/packages/transform-eventual-send/test/ses-test.js deleted file mode 100644 index 2cf8b4a6e2a..00000000000 --- a/packages/transform-eventual-send/test/ses-test.js +++ /dev/null @@ -1,204 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -/* eslint-disable no-await-in-loop */ -import { test } from 'tape-promise/tape'; -import SES from 'ses'; - -import * as babelParser from '@agoric/babel-parser'; -import babelGenerate from '@babel/generator'; - -import eventualSend from '@agoric/acorn-eventual-send'; -import * as acorn from 'acorn'; -import * as astring from 'astring'; - -import makeEventualSendTransformer from '../src/rewriter'; - -// FIXME: This should be unnecessary when SES has support -// for passing `evaluateProgram` through to the rewriter state. -const closeOverSES = (transforms, ses) => - transforms.forEach(t => t.closeOverSES && t.closeOverSES(ses)); - -const AcornParser = acorn.Parser.extend(eventualSend(acorn)); -const acornParser = { - parse(src) { - return AcornParser.parse(src); - }, - parseExpression(src) { - return AcornParser.parseExpressionAt(src, 0); - }, -}; -const acornGenerate = (ast, _options, _src) => { - const code = astring.generate(ast); - return { code }; -}; - -test('eventual send is disabled by default', t => { - try { - const s = SES.makeSESRootRealm(); - t.throws( - () => - s.evaluate('"abc"~.length', { - HandledPromise: { - get(target, _prop) { - return target; - }, - }, - }), - SyntaxError, - `eventual send fails`, - ); - t.equals(s.evaluate('(1,eval)("123")'), 123, `indirect eval works`); - } catch (e) { - t.assert(false, e); - } finally { - t.end(); - } -}); - -test('expression source is parsable', async t => { - try { - const s = SES.makeSESRootRealm({ - transforms: makeEventualSendTransformer(babelParser, babelGenerate), - }); - t.equal( - s.evaluate(`123; 456`, {}, { sourceType: 'program' }), - 456, - 'program succeeds', - ); - t.equal( - s.evaluate(`123;`, {}, { sourceType: 'program' }), - 123, - 'semicolon program succeeds', - ); - /* FIXME: Do when Realms honour sourceType. - t.throws( - () => s.evaluate(`123;`, {}, { sourceType: 'expression' }), - SyntaxError, - 'non-expression fails', - ); - */ - t.equal( - s.evaluate(`123`, {}, { sourceType: 'expression' }), - 123, - 'expression succeeds', - ); - } catch (e) { - t.assert(false, e); - } finally { - t.end(); - } -}); - -test('eventual send can be enabled twice', async t => { - try { - const transforms = [ - ...makeEventualSendTransformer(babelParser, babelGenerate), - ...makeEventualSendTransformer(babelParser, babelGenerate), - ]; - const s = SES.makeSESRootRealm({ transforms }); - closeOverSES(transforms, s); - t.equal( - await s.evaluate('"abc"~.[2]'), - 'c', - `babel double transform works`, - ); - const transforms2 = [ - ...makeEventualSendTransformer(acornParser, acornGenerate), - ...makeEventualSendTransformer(acornParser, acornGenerate), - ]; - const s2 = SES.makeSESRootRealm({ transforms: transforms2 }); - closeOverSES(transforms2, s2); - t.equal( - await s2.evaluate('"abc"~.[2]'), - 'c', - `acorn double transform works`, - ); - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } -}); - -test('eventual send can be enabled', async t => { - try { - for (const [name, parser, generate] of [ - ['babel', babelParser, babelGenerate], - ['acorn', acornParser, acornGenerate], - ]) { - const transforms = [...makeEventualSendTransformer(parser, generate)]; - const s = SES.makeSESRootRealm({ transforms }); - closeOverSES(transforms, s); - - // console.log(parser('"abc"~.length', { plugins: ['eventualSend'] })); - t.equals(await s.evaluate(`"abc"~.length`), 3, `${name} .get() works`); - t.equals( - await s.evaluate( - `({foo(nick) { return "hello " + nick; }})~.foo('person')`, - ), - 'hello person', - `${name} .applyMethod() works`, - ); - t.equals( - await s.evaluate(`((punct) => "world" + punct)~.('!')`), - 'world!', - `${name} .applyFunction() works`, - ); - t.equals( - await s.evaluate(`["a", "b", "c"]~.[2]`), - 'c', - `${name} computed .get works`, - ); - - t.equals( - await s.evaluate( - `({foo(greeting) { return greeting + ' world';}})~.foo~.('hello')`, - ), - 'hello world', - `${name} double eventual send evaluates`, - ); - - const noReject = fn => fn(); - - let directEval = noReject; - // eslint-disable-next-line no-constant-condition - if (true) { - // FIXME: Should be noReject. - directEval = fn => - t.rejects( - fn(), - /possible direct eval expression rejected/, - `${name} direct eval fails (FIXME)`, - ); - } - await directEval(async () => - t.equals( - await s.evaluate(`eval('"abc"~.length')`), - 3, - `${name} direct eval works`, - ), - ); - await directEval(async () => - t.equals( - await s.evaluate(`eval('eval(\\'"abc"~.length\\')')`), - 3, - `${name} nested direct eval works`, - ), - ); - - t.equals( - await s.evaluate(`(1,eval)('"abc"~.length')`), - 3, - `${name} indirect eval works`, - ); - t.equals( - await s.evaluate(`(1,eval)('(1,eval)(\\'"abc"~.length\\')')`), - 3, - `${name} nested indirect eval works`, - ); - } - } catch (e) { - t.isNot(e, e, 'unexpected exception'); - } finally { - t.end(); - } -}); diff --git a/packages/transform-eventual-send/test/test-transformer.js b/packages/transform-eventual-send/test/test-transformer.js index b5ab469fa85..ca2d9770a20 100644 --- a/packages/transform-eventual-send/test/test-transformer.js +++ b/packages/transform-eventual-send/test/test-transformer.js @@ -11,5 +11,39 @@ test('transformer', t => { output, `let p = HandledPromise.applyMethod(bob, "foo", [arg1, arg2]);`, ); + t.equal( + transformer(output), + `let p = HandledPromise.applyMethod(bob, "foo", [arg1, arg2]);`, + ); + t.equal(transformer('123;456'), '123;456;'); + t.equal(transformer('123;'), '123;'); + t.equal(transformer('123'), '123;'); + t.equal( + transformer(`"abc"~.length`), + 'HandledPromise.get("abc", "length");', + '.get() works', + ); + t.equal( + transformer(`({foo(nick) { return "hello " + nick; }})~.foo('person')`), + `HandledPromise.applyMethod({ foo(nick) {return "hello " + nick;} }, "foo", ['person']);`, + '.applyMethod() works', + ); + t.equal( + transformer(`((punct) => "world" + punct)~.('!')`), + `HandledPromise.applyFunction(punct => "world" + punct, ['!']);`, + '.applyFunction() works', + ); + t.equal( + transformer(`["a", "b", "c"]~.[2]`), + `HandledPromise.get(["a", "b", "c"], 2);`, + 'computed .get works', + ); + t.equal( + transformer( + `({foo(greeting) { return greeting + ' world';}})~.foo~.('hello')`, + ), + `HandledPromise.applyFunction(HandledPromise.get({ foo(greeting) {return greeting + ' world';} }, "foo"), ['hello']);`, + 'double eventual send works', + ); t.end(); });