Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler release #642

Merged
merged 8 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions integration-tests/worker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @openfn/integration-tests-worker

## 1.0.37

### Patch Changes

- @openfn/[email protected]
- @openfn/[email protected]
- @openfn/[email protected]

## 1.0.36

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/worker/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@openfn/integration-tests-worker",
"private": true,
"version": "1.0.36",
"version": "1.0.37",
"description": "Lightning WOrker integration tests",
"author": "Open Function Group <[email protected]>",
"license": "ISC",
Expand Down
8 changes: 8 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @openfn/cli

## 1.1.3

### Patch Changes

- Updated dependencies [6dcce3d]
- Updated dependencies [1d37ca1]
- @openfn/[email protected]

## 1.1.2

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openfn/cli",
"version": "1.1.2",
"version": "1.1.3",
"description": "CLI devtools for the openfn toolchain.",
"engines": {
"node": ">=18",
Expand Down
7 changes: 7 additions & 0 deletions packages/compiler/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @openfn/compiler

## 0.1.0

### Minor Changes

- 6dcce3d: Support latest ecmascript version
- 1d37ca1: Basic support for lazy state ($) operator

## 0.0.41

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openfn/compiler",
"version": "0.0.41",
"version": "0.1.0",
"description": "Compiler and language tooling for openfn jobs.",
"author": "Open Function Group <[email protected]>",
"license": "ISC",
Expand Down
5 changes: 2 additions & 3 deletions packages/compiler/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ export default function parse(source: string) {
range: true,
parser: {
parse: (source: string) =>
// TODO this can't parse nullish coalescence, so maybe we just need a more modern ecma version!
acorn.parse(source, {
sourceType: 'module', // Note: this is different to v1 (but back compatible I think)
ecmaVersion: 10,
sourceType: 'module',
ecmaVersion: 'latest',
allowHashBang: true,
locations: true,
}),
Expand Down
7 changes: 5 additions & 2 deletions packages/compiler/src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import createLogger, { Logger } from '@openfn/logger';

import addImports, { AddImportsOptions } from './transforms/add-imports';
import ensureExports from './transforms/ensure-exports';
import lazyState from './transforms/lazy-state';
import topLevelOps, {
TopLevelOpsOptions,
} from './transforms/top-level-operations';
Expand All @@ -13,7 +14,8 @@ export type TransformerName =
| 'add-imports'
| 'ensure-exports'
| 'top-level-operations'
| 'test';
| 'test'
| 'lazy-state';

type TransformFunction = (
path: NodePath<any, any>,
Expand All @@ -36,6 +38,7 @@ export type TransformOptions = {
['ensure-exports']?: boolean;
['top-level-operations']?: TopLevelOpsOptions | boolean;
['test']?: any;
['lazy-state']?: any;
};

const defaultLogger = createLogger();
Expand All @@ -46,7 +49,7 @@ export default function transform(
options: TransformOptions = {}
) {
if (!transformers) {
transformers = [ensureExports, topLevelOps, addImports] as Transformer[];
transformers = [lazyState, ensureExports, topLevelOps, addImports] as Transformer[];
}
const logger = options.logger || defaultLogger;
const transformerIndex = indexTransformers(transformers, options);
Expand Down
2 changes: 2 additions & 0 deletions packages/compiler/src/transforms/add-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import type { Transformer } from '../transform';
import type { Logger } from '@openfn/logger';

const globals = [
'\\$', // TMP hack to fix a problem with lazy-state (needs double escaping to work)

'AggregateError',
'Array',
'ArrayBuffer',
Expand Down
46 changes: 46 additions & 0 deletions packages/compiler/src/transforms/lazy-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Convert $.a.b.c references into (state) => state.a.b.c
* Should this only run at top level?
* Ideally it would run on all arguments to operations - but we probably don't really know what an operation is
* So for now, first pass, it's only top level.
* (alternatively I guess it just dumbly converts everything and if it breaks, it breaks)
*
* TODO (maybe):
* - only convert $-expressions which are arguments to operations (needs type defs)
* - warn if converting a non-top-level $-expression
* - if not top level, convert to state.a.b.c (ie don't wrap the function)
*/
import { builders as b, namedTypes } from 'ast-types';
import type { NodePath } from 'ast-types/lib/node-path';
import type { Transformer } from '../transform';

function visitor(path: NodePath<namedTypes.MemberExpression>) {
let first = path.node.object;
while(first.hasOwnProperty('object')) {
first = (first as namedTypes.MemberExpression).object;
}

let firstIdentifer = first as namedTypes.Identifier;

if (first && firstIdentifer.name === "$") {
// rename $ to state
firstIdentifer.name = "state";

// Now nest the whole thing in an arrow
const params = b.identifier('state')
const arrow = b.arrowFunctionExpression(
[params],
path.node
)
path.replace(arrow)
}

// Stop parsing this member expression
return;
}

export default {
id: 'lazy-state',
types: ['MemberExpression'],
visitor,
} as Transformer;
2 changes: 1 addition & 1 deletion packages/compiler/test/asts/cjs.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/compiler/test/asts/multiple-operations.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/compiler/test/asts/simple-operation.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"program":{"type":"Program","start":0,"end":5,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":5,"token":4},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"indent":0,"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}]},"body":[{"type":"ExpressionStatement","start":0,"end":5,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":5,"token":4},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}],"indent":0},"expression":{"type":"CallExpression","start":0,"end":4,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":4,"token":3},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}],"indent":0},"callee":{"type":"Identifier","start":0,"end":2,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":2,"token":1},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}],"indent":0},"name":"fn"},"arguments":[]}}],"sourceType":"module","errors":[]},"name":null,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":5,"token":4},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"indent":0,"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}]},"type":"File","comments":null,"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}]}
{"program":{"type":"Program","start":0,"end":5,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":5,"token":4},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"indent":0,"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}]},"body":[{"type":"ExpressionStatement","start":0,"end":5,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":5,"token":4},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}],"indent":0},"expression":{"type":"CallExpression","start":0,"end":4,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":4,"token":3},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}],"indent":0},"callee":{"type":"Identifier","start":0,"end":2,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":2,"token":1},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}],"indent":0},"name":"fn"},"arguments":[],"optional":false}}],"sourceType":"module","errors":[]},"name":null,"loc":{"start":{"line":1,"column":0,"token":0},"end":{"line":1,"column":5,"token":4},"lines":{"infos":[{"line":"fn();","indent":0,"locked":false,"sliceStart":0,"sliceEnd":5}],"mappings":[],"cachedSourceMap":null,"length":1,"name":null},"indent":0,"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}]},"type":"File","comments":null,"tokens":[{"type":"Identifier","value":"fn","loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":2}}},{"type":"Punctuator","value":"(","loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}},{"type":"Punctuator","value":")","loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4}}},{"type":"Punctuator","value":";","loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}}]}
40 changes: 40 additions & 0 deletions packages/compiler/test/compile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,43 @@ test('twitter example', async (t) => {
const result = compile(source);
t.deepEqual(result, expected);
});

test('compile with optional chaining', (t) => {
const source = 'fn(a.b?.c);';
const expected = 'export default [fn(a.b?.c)];';
const result = compile(source);
t.assert(result === expected);
});

test('compile with nullish coalescence', (t) => {
const source = 'fn(a ?? b);';
const expected = 'export default [fn(a ?? b)];';
const result = compile(source);
t.assert(result === expected);
});

test('compile a lazy state ($) expression', (t) => {
const source = 'get($.data.endpoint);';
const expected = 'export default [get(state => state.data.endpoint)];';
const result = compile(source);
t.assert(result === expected);
});


test('compile a lazy state ($) expression with dumb imports', (t) => {
const options = {
'add-imports': {
adaptor: {
name: '@openfn/language-common',
exportAll: true,
},
},
};
const source = 'get($.data.endpoint);';
const expected = `import { get } from "@openfn/language-common";
export * from "@openfn/language-common";
export default [get(state => state.data.endpoint)];`

const result = compile(source, options);
t.assert(result === expected);
});
10 changes: 5 additions & 5 deletions packages/compiler/test/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,34 @@ test('parse a simple statement', (t) => {

const ast = loadAst('simple-statement');
const result = parse(source);
t.assert(ast === JSON.stringify(result));
t.is(ast, JSON.stringify(result));
});

test('parse an esm module', (t) => {
const source = `import foo from 'bar'; export const x = 10;`;
const ast = loadAst('esm');
const result = parse(source);
t.assert(ast === JSON.stringify(result));
t.is(ast, JSON.stringify(result));
});

// This will still parse as a module, but it won't freak out when it see module.exports
test('parse a CJS script', (t) => {
const source = `module.exports = 10;`;
const ast = loadAst('cjs');
const result = parse(source);
t.assert(ast === JSON.stringify(result));
t.is(ast, JSON.stringify(result));
});

test('parse a single operation', (t) => {
const source = `fn();`;
const ast = loadAst('simple-operation');
const result = parse(source);
t.assert(ast === JSON.stringify(result));
t.is(ast, JSON.stringify(result));
});

test('parse multiple operations', (t) => {
const source = `fn();fn();fn();`;
const ast = loadAst('multiple-operations');
const result = parse(source);
t.assert(ast === JSON.stringify(result));
t.is(ast, JSON.stringify(result));
});
76 changes: 76 additions & 0 deletions packages/compiler/test/transforms/lazy-state.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import test, { ExecutionContext } from 'ava';
import { print } from 'recast';
import { namedTypes, NodePath, builders as b } from 'ast-types';

import parse from '../../src/parse';

import transform from '../../src/transform';
import visitors from '../../src/transforms/lazy-state';

test('convert a simple dollar reference', (t) => {
const ast = parse('get($.data)');

const transformed = transform(ast, [visitors]);
const { code } = print(transformed)
t.log(code)

t.is(code, 'get(state => state.data)')
})

test('convert a chained dollar reference', (t) => {
const ast = parse('get($.a.b.c.d)');

const transformed = transform(ast, [visitors]);
const { code } = print(transformed)
t.log(code)

t.is(code, 'get(state => state.a.b.c.d)')
})

test('ignore a regular chain reference', (t) => {
const ast = parse('get(a.b.c.d)');

const transformed = transform(ast, [visitors]);
const { code } = print(transformed)
t.log(code)

t.is(code, 'get(a.b.c.d)')
})

test('ignore a string', (t) => {
const ast = parse('get("$.a.b")');

const transformed = transform(ast, [visitors]);
const { code } = print(transformed)
t.log(code)

t.is(code, 'get("$.a.b")')
})

// TODO do we want to support this?
test('convert a nested dollar reference', (t) => {
const ast = parse(`fn(() => {
get($.data)
})`);

const transformed = transform(ast, [visitors]);
const { code } = print(transformed)
t.log(code)

// syntax starts getting a but picky at this level,
// better to do ast tests
t.is(code, `fn(() => {
get(state => state.data)
})`)
})

// TODO does our compiler not support optional chaining??
test.skip('convert an optional chained simple dollar reference', (t) => {
const ast = parse('get($.a?.b.c.d)');

// const transformed = transform(ast, [visitors]);
// const { code } = print(transformed)
// t.log(code)

// t.is(code, 'get(state => state.a?.b.c.d)')
})
9 changes: 9 additions & 0 deletions packages/engine-multi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# engine-multi

## 1.1.2

### Patch Changes

- Updated dependencies [6dcce3d]
- Updated dependencies [1d37ca1]
- @openfn/[email protected]

## 1.1.1

### Patch Changes
Expand All @@ -10,6 +18,7 @@
- @openfn/[email protected]
- @openfn/[email protected]
- @openfn/[email protected]

## 1.1.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/engine-multi/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openfn/engine-multi",
"version": "1.1.1",
"version": "1.1.2",
"description": "Multi-process runtime engine",
"main": "dist/index.js",
"type": "module",
Expand Down
6 changes: 6 additions & 0 deletions packages/lightning-mock/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @openfn/lightning-mock

## 2.0.2

### Patch Changes

- @openfn/[email protected]

## 2.0.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/lightning-mock/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openfn/lightning-mock",
"version": "2.0.1",
"version": "2.0.2",
"private": true,
"description": "A mock Lightning server",
"main": "dist/index.js",
Expand Down
6 changes: 6 additions & 0 deletions packages/ws-worker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# ws-worker

## 1.1.2

### Patch Changes

- @openfn/[email protected]

## 1.1.1

### Patch Changes
Expand Down
Loading