expand arbitrary iterables in default tagged templates

It’s extremely useful that putting an array into one of the default tagged templates like html or md or svg sticks every element into the rendered output, so that notebooks don’t have to add the concatenation logic manually.

Feature request:

It would be nice if this also worked for arbitrary iterables instead of just arrays. Right now if I return an arbitrary iterable the template just puts in [object Object], [object Generator], [object Set], or whatever, which is pretty much never useful.

To make this work the standard library’s template function could just switch from using a for loop to a for-of loop, and switch from testing for arrays to testing for arbitrary iterables.

function isIterable(obj) {
  if (obj == null) return false;
  return typeof obj[Symbol.iterator] === 'function';
}

Here’s the notebook where I was fiddling, for the curious:

I think every browser that supports tagged templates also supports iterables and for-of loops, so there shouldn’t be any additional compatibility concerns.

P.S. the feature of expanding arrays is mentioned in the github docs for the standard library, but not in the @observablehq/standard-library or @observablehq/introduction-to-html notebooks. I would recommend adding a note about it in both places; I only found out about the feature from looking at various notebooks @mbostock made, where this was used but not IIRC explicitly described.

P.P.S. syntax highlighting is broken for generators as object properties; variables inside are not properly highlighted. Maybe the parser doesn’t realize that the part inside is a function? e.g.:

({ *[Symbol.iterator]() {
  const a = 5;
  yield a;
}})

But this seems to get highlighted correctly:

({ [Symbol.iterator]: function*() {
  const a = 5;
  yield a;
}})

[Seems like this discussion site’s highlighter’s JS parser is also broken for the former syntax.]

4 Likes