Skip to content

Commit bab4dc4

Browse files
authored
Merge pull request #1066 from OpenFn/release/next
Release/next
2 parents b8a2ff8 + a0dd17f commit bab4dc4

36 files changed

Lines changed: 1132 additions & 607 deletions

packages/cli/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# @openfn/cli
22

3+
## 1.16.1
4+
5+
### Patch Changes
6+
7+
- Updated dependencies [cb97744]
8+
- Updated dependencies [49caf75]
9+
- @openfn/compiler@1.1.5
10+
- @openfn/project@0.5.0
11+
312
## 1.16.0
413

514
### Minor Changes

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openfn/cli",
3-
"version": "1.16.0",
3+
"version": "1.16.1",
44
"description": "CLI devtools for the OpenFn toolchain",
55
"engines": {
66
"node": ">=18",

packages/compiler/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @openfn/compiler
22

3+
## 1.1.5
4+
5+
### Patch Changes
6+
7+
- cb97744: Improve compiler performance for large files
8+
39
## 1.1.4
410

511
### Patch Changes

packages/compiler/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openfn/compiler",
3-
"version": "1.1.4",
3+
"version": "1.1.5",
44
"description": "Compiler and language tooling for openfn jobs.",
55
"author": "Open Function Group <admin@openfn.org>",
66
"license": "ISC",
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { namedTypes as n } from 'ast-types';
2+
import { NodePath } from 'ast-types/lib/node-path';
3+
4+
const IgnoreRules = (path: NodePath<n.Expression>) => {
5+
return {
6+
check: n.ObjectExpression.check(path.node),
7+
shouldSkip: () => {
8+
if (
9+
n.VariableDeclarator.check(path.parentPath.node) &&
10+
n.VariableDeclaration.check(path.parentPath.parentPath.node) &&
11+
n.Program.check(path.parentPath.parentPath.parentPath.parentPath.node)
12+
) {
13+
return true;
14+
}
15+
return false;
16+
},
17+
};
18+
};
19+
20+
export default IgnoreRules;

packages/compiler/src/transform.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ export default function transform(
6868
] as Transformer[];
6969
}
7070
const logger = options.logger || defaultLogger;
71-
7271
transformers
7372
// Ignore transformers which are explicitly disabled
7473
.filter(({ id }) => options[id] ?? true)
@@ -82,11 +81,13 @@ export default function transform(
8281
})
8382
// Run each transformer
8483
.forEach(({ id, types, visitor }) => {
84+
const t = `transformer ${id}`;
85+
console.time?.(t);
8586
const astTypes: Visitor = {};
8687
for (const type of types) {
8788
const name = `visit${type}` as keyof Visitor;
8889
astTypes[name] = function (path: NodePath) {
89-
printHeap(`visit: ${path.name}`);
90+
// printHeap(`visit: ${path.name}`);
9091
const opts = options[id] || {};
9192
const abort = visitor!(path, logger, opts);
9293
if (abort) {
@@ -98,8 +99,15 @@ export default function transform(
9899

99100
// @ts-ignore
100101
visit(ast, astTypes);
102+
if (options.trace) {
103+
console.log();
104+
printHeap(`${t}`);
105+
console.timeEnd?.(t);
106+
}
101107
});
102-
108+
if (options.trace) {
109+
console.log();
110+
}
103111
printHeap(`finished`);
104112
const duration = (Date.now() - start) / 1000;
105113
logger.debug(`Finished in ${duration}s`);

packages/compiler/src/transforms/add-imports.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ export type IdentifierList = Record<string, true>;
107107
export function findAllDanglingIdentifiers(ast: ASTNode) {
108108
const result: IdentifierList = {};
109109
visit(ast, {
110+
visitObjectExpression(path) {
111+
// excaping top-level object variable declarations.
112+
if (
113+
n.VariableDeclarator.check(path.parentPath.node) &&
114+
n.VariableDeclaration.check(path.parentPath.parentPath.node) &&
115+
n.Program.check(path.parentPath.parentPath.parentPath.parentPath.node)
116+
) {
117+
return false;
118+
}
119+
this.traverse(path);
120+
},
110121
visitIdentifier: function (path) {
111122
// If this is part of an import statement, do nothing
112123
if (n.ImportSpecifier.check(path.parent.node)) {

packages/compiler/src/transforms/lazy-state.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import { builders as b, namedTypes as n } from 'ast-types';
1010
import type { NodePath } from 'ast-types/lib/node-path';
1111
import type { Transformer } from '../transform';
12+
import IgnoreRules from '../transform-ignore';
1213

1314
// Walk up the AST and work out where the parent arrow function should go
1415
const ensureParentArrow = (path: NodePath<n.MemberExpression>) => {
@@ -79,6 +80,11 @@ const isOpenFunction = (path: NodePath) => {
7980
};
8081

8182
function visitor(path: NodePath<n.MemberExpression>) {
83+
// if it was called for an ObjectExpression
84+
const ignoreRule = IgnoreRules(path);
85+
if (ignoreRule.check) {
86+
return ignoreRule.shouldSkip();
87+
}
8288
let first = path.node.object;
8389
while (first.hasOwnProperty('object')) {
8490
first = (first as n.MemberExpression).object;
@@ -106,7 +112,7 @@ function visitor(path: NodePath<n.MemberExpression>) {
106112

107113
export default {
108114
id: 'lazy-state',
109-
types: ['MemberExpression'],
115+
types: ['MemberExpression', 'ObjectExpression'],
110116
visitor,
111117
// It's important that $ symbols are escaped before any other transformations can run
112118
order: 0,

packages/compiler/src/transforms/promises.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { namedTypes as n, builders as b } from 'ast-types';
22

33
import type { NodePath } from 'ast-types/lib/node-path';
4+
import IgnoreRules from '../transform-ignore';
45

56
const NO_DEFER_DECLARATION_ERROR = 'No defer declaration found';
67

@@ -146,6 +147,10 @@ const isTopScope = (path: NodePath<any>) => {
146147
};
147148

148149
const visitor = (path: NodePath<n.CallExpression>) => {
150+
const ignoreRule = IgnoreRules(path);
151+
if (ignoreRule.check) {
152+
return ignoreRule.shouldSkip();
153+
}
149154
let root: NodePath<any> = path;
150155
while (!n.Program.check(root.node)) {
151156
root = root.parent;
@@ -166,7 +171,7 @@ const visitor = (path: NodePath<n.CallExpression>) => {
166171

167172
export default {
168173
id: 'promises',
169-
types: ['CallExpression'],
174+
types: ['CallExpression', 'ObjectExpression'],
170175
visitor,
171176
// this should run before top-level operations are moved into the exports array
172177
order: 0,

packages/compiler/src/transforms/top-level-operations.ts

Lines changed: 32 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,71 +8,53 @@ import type { Transformer } from '../transform';
88
// Note that the validator should complain if it see anything other than export default []
99
// What is the relationship between the validator and the compiler?
1010

11-
export type ExtendedProgram = NodePath<namedTypes.Program> & {
12-
operations: Array<{ line: number; name: string; order: number }>;
13-
};
11+
export type ExtendedProgram = NodePath<
12+
namedTypes.Program & {
13+
operations: Array<{ line: number; name: string; order: number }>;
14+
}
15+
>;
1416

1517
export type TopLevelOpsOptions = {
1618
// Wrap operations in a `(state) => op` wrapper
1719
wrap: boolean; // TODO
1820
};
1921

20-
function visitor(path: NodePath<namedTypes.CallExpression>) {
21-
const root = path.parent.parent.node;
22-
// Check if the node is a top level Operation
22+
function visitor(programPath: ExtendedProgram) {
23+
const operations: Array<{ line: number; name: string; order: number }> = [];
24+
const children = programPath.node.body;
25+
const rem = [];
26+
27+
const target = programPath.node.body.at(-1);
2328
if (
24-
// Check this is a top level call expression
25-
// ie, the parent must be an ExpressionStatement, and the statement's parent must be a Program
26-
n.Program.check(root) &&
27-
n.Statement.check(path.parent.node) &&
28-
// An Operation could be an Identifier (fn()) or Member Expression (http.get())
29-
(n.Identifier.check(path.node.callee) ||
30-
n.MemberExpression.check(path.node.callee))
29+
n.ExportDefaultDeclaration.check(target) &&
30+
n.ArrayExpression.check(target.declaration)
3131
) {
32-
appendOperationMetadata(path, root as unknown as ExtendedProgram);
33-
34-
// Now Find the top level exports array
35-
const target = root.body.at(-1);
36-
if (
37-
n.ExportDefaultDeclaration.check(target) &&
38-
n.ArrayExpression.check(target.declaration)
39-
) {
40-
const statement = path.parent;
41-
target.declaration.elements.push(path.node);
42-
// orphan the original expression statement parent
43-
statement.prune();
44-
} else {
45-
// error! there isn't an appropriate export statement
46-
// What do we do?
32+
for (const child of children) {
33+
if (
34+
n.ExpressionStatement.check(child) &&
35+
n.CallExpression.check(child.expression)
36+
) {
37+
const order = operations.length + 1;
38+
// @ts-ignore
39+
const name = child.expression.callee.name;
40+
const line = child.expression.loc?.start.line ?? -1;
41+
operations.push({ name, line, order });
42+
target.declaration.elements.push(child.expression as any);
43+
} else rem.push(child);
4744
}
45+
programPath.node.body = rem;
46+
} else {
47+
// error! there isn't an appropriate export statement
48+
// What do we do?
4849
}
50+
programPath.node.operations = operations;
4951

5052
// if not (for now) we should cancel traversal
5153
return true;
5254
}
5355

54-
// Add metadata to each operation for:
55-
// - the order (do we know? We can guess from the state of the exports array
56-
// - the name of the operation
57-
// - the original line number (do we know?)
58-
function appendOperationMetadata(
59-
path: NodePath<namedTypes.CallExpression>,
60-
root: ExtendedProgram
61-
) {
62-
if (!root.operations) {
63-
root.operations = [];
64-
}
65-
66-
const { operations } = root;
67-
const order = operations.length + 1;
68-
const name = path.value.callee.name;
69-
const line = path.value.loc?.start.line ?? -1;
70-
71-
operations.push({ line, order, name });
72-
}
73-
7456
export default {
7557
id: 'top-level-operations',
76-
types: ['CallExpression'],
58+
types: ['Program'],
7759
visitor,
78-
} as Transformer;
60+
} as unknown as Transformer;

0 commit comments

Comments
 (0)