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: add default export even if there's an export already in the code (strict check for default export, not just /export/) #831

Open
doc-han opened this issue Nov 23, 2024 · 6 comments
Assignees
Labels
bug Something isn't working good first issue Good for newcomers

Comments

@doc-han
Copy link
Collaborator

doc-han commented Nov 23, 2024

Description.

Runtime seems to always require a compiled job to have a default export of an array. Hence, those without a default export break the runtime.

Because

  1. we access the default export.
    const operations = exports.default;
  2. we expect an array and want to iterate it
    ...operations.map((op, idx) =>

Currently,

We create a default export and then put all top-level-expressions in it. If there's no top-level-expression and empty array is exported to make the runtime happy.

export default []; // to make runtime happy!

But,

when there's an export (either named or not) that isn't a default export, we ignore the creation of the default export which makes the runtime sad.

There might be programs to be run in this job but because of a single non-default export. They don't get executed.

eg.

import {fn} from "@openfn/common"

fn(state => {
  state.data.name = "doc-han"
  return state;
})

export const han = "Han"; // prevents our runtime from running

fn(() => {
  state.data.isGithub = true;
  return state;
})

Is there a reason we don't accommodate this? @josephjclark
I feel we can have other exports and still generate our default export. Also, if the user provides a default export(which isn't encouraged) we can also check if it exports an Array.

Here we do a regex match.

const currentExport = path.node.body.find(({ type }) => type.match(/Export/));

For the concern of having several types of export nodes. A default export seems to always have only one type of Node representation. The name of the node only changes across ast-generator.

Proposed solution.

  1. Instead of regex matching the type 'Export ', Look for default export node instead.
  2. check if the default export node has declaration that's an Array
@doc-han doc-han added bug Something isn't working good first issue Good for newcomers labels Nov 23, 2024
@doc-han doc-han self-assigned this Nov 23, 2024
@github-project-automation github-project-automation bot moved this to New Issues in v2 Nov 23, 2024
@doc-han
Copy link
Collaborator Author

doc-han commented Nov 23, 2024

I don't even think that export there should be allowed. It's on the same level as

some-job.js

console.log("here")

because the export doesn't consume state and return state.

@josephjclark
Copy link
Collaborator

Hiya @doc-han

The default export is the basic contract between the a job and the runtime. I suppose you can look at it like this: the runtime will load a JS module that exports an array of functions as its default export. And then it'll execute those functions in series. It's a nice clean interface between a job and the rumtime.

There's no need for a job expression to export anything today.

Saying that, I would like it to support named exports so that we can unit test job code later on.

You're absolutely right - we should be doing a stricter check for export default rather than just that lazy regex.

But this isn't an issue I'm looking to fix in the short-medium term. We've got way more interesting problems to fix.

@josephjclark
Copy link
Collaborator

I'll rename this issue so that we can keep it in the backlog

@josephjclark josephjclark changed the title Unexpected exports in a job breaks the runtime Compiler: add default export even if there's an export already in the code (strict check for default export, not just /export/) Nov 23, 2024
@josephjclark
Copy link
Collaborator

@doc-han why do you want to add an export anyway?

@doc-han
Copy link
Collaborator Author

doc-han commented Nov 25, 2024

@doc-han why do you want to add an export anyway?

I actually don't want to.

  1. I saw the regex match and tried it out.
  2. I then saw a test guarding that behaviour.
    test('do not add default exports if exports exist', (t) => {
    const source = 'export const x = 10;';
    const expected = 'export const x = 10;';
    const result = compile(source);
    t.is(result, expected);
    });

@josephjclark
Copy link
Collaborator

@doc-han Got it - eagle eyes you have there 🦅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good first issue Good for newcomers
Projects
Status: New Issues
Development

No branches or pull requests

2 participants