Skip to content

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

@pearmini

Description

@pearmini

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions