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

How to define top-level thenable and generatorish variable with function attributes in Notebook? #375

Open
pearmini opened this issue Jan 24, 2025 · 0 comments

Comments

@pearmini
Copy link

pearmini commented Jan 24, 2025

I implemented a proxy object (source) called shape to build SVG elements, such as:

const svg = shape.svg({width: 100, height: 100}, [
  shape.rect({x: 0, y: 0, height: 100, width: 100, fill: "black"}),
  shape.circle({cx: 50, cy: 50, r: 40, fill: "white"}),
]);

document.body.append(svg);

A simple implementation is as follows:

shape = new Proxy({}, {get: (_, name) => () => document.createElement("name")})

But it threw an error when I defined it at the top-level:

Image

I found that it automatically called shape.then, shape.next and shape.return. After reading the source code, I discovered actual issue: the runtime can't handle thenable and generatorish variable as expected, especially when they have function attributes:

Image

The generatorish issue is easy to solve relatively with a stricter check in generatorish.js:

export function generatorish(value) {
  if (!value) return false;
  const tag = value[Symbol.toStringTag];
  return tag === "Generator" || tag === "AsyncGenerator";
}

If "generatorish" is required, it is also possible to make it work with proxies like shape:

export function generatorish(value) {
  return value
      && 'next' in value && typeof value.next === "function"
      && 'return' in value && typeof value.return === "function";
}

However the thenable issue is not as easy to solve, because runtime use promises to wrap the value:

// https://github.com/observablehq/runtime/blob/622a1974087f03545b5e91c8625b46874e82e4df/src/runtime.js#L231
 variable._promise = variable._promise
    .then(init, init)
    // This will return a promise that never resolves, 
    // because the return value has a "then" attribute,
    // which is a function but does not call resolve.
    .then(define) 
    .then(generate);

function define(inputs) {
  // ....
  return definition.apply(value0, inputs); // Returns the value itself.
}

I made som attempts but failed. Before going further, I just want to confirm if I'm on the right track:

  • Are these real issues? I didn't find any docs or tests that shows runtime supports thenable and generatorish variable (if I missed them, please let me know!). I think they should act like normal variables.
  • If they are real issues, is fixing them necessary? This seems like a rare situation.

If they are real issues and should be fixed, I'm willing to open a PR to address them! If not, I'd love to hear suggestions to make shape compatible with Notebook. While I can modify the source code of shape to filter then, next, and return, I'd prefer not to do this solely for Notebook!

Anyway, thanks for the great work of Notebook!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant