String identity template tag
Mike Samuel
mikesamuel at gmail.com
Fri Dec 14 19:55:12 UTC 2018
On Fri, Dec 14, 2018 at 2:26 PM Isiah Meadows <isiahmeadows at gmail.com>
wrote:
> The main difference with that loop is that it's generalized to any number
> of arrays, not just two with the second array having length one less than
> the first. Otherwise, it'd look exactly the same. BTW, I like this route
> (`Array.interleave`) better since it doesn't have to result in just a
> single string result - it could just be an array of strings plugged into
> some API instead, or it could be procedurally streamed out in chunks.
>
Fair enough.
If you're not looking for something template tag specific then a simple zip
over iterators should do it?
function *ziperator(iterators) {
let progressed;
do {
progressed = false;
for (let iterator of iterators) {
for (let element of iterator) {
yield element;
progressed = true;
break;
}
}
} while (progressed);
}
console.log(Array.from(ziperator([ ['a', 'b', 'c'][Symbol.iterator](), [1,
2][Symbol.iterator]() ])).join(''));
// -> a1b2c
(but optimized :)
> On Fri, Dec 14, 2018 at 14:04 Mike Samuel <mikesamuel at gmail.com> wrote:
>
>>
>>
>> On Fri, Dec 14, 2018 at 12:51 PM Isiah Meadows <isiahmeadows at gmail.com>
>> wrote:
>>
>>> I'll point out Kai could be on to something, although I disagree `zip`
>>> would be the right abstraction. Maybe `Array.interleave(...arrays)`? You
>>> could do `Array.interleave(template, args).map(String).join("")` for
>>> similar effect, and it'd be more generally useful.
>>>
>>> The key here is that iteration would stop after the index hits any
>>> array's length, so it'd be polyfilled kinda like this:
>>>
>>> ```js
>>> Array.interpolate = (...args) => {
>>> let ret = []
>>> let lengths = []
>>> let count = 0
>>> for (let i = 0; i < args.length; i++) {
>>> lengths[i] = args[i].count
>>> }
>>> for (let index = 0; ; index++) {
>>> for (let i = 0; i < args.length; i++) {
>>> if (index === lengths[i]) return ret
>>> ret[count++] = args[i][index]
>>> }
>>> }
>>> }
>>> ```
>>>
>>> (This could be optimized, though.)
>>>
>>
>> As a data point, something like this loop appears in most of the template
>> tags I've written but
>> it's never had these precise semantics so I didn't bother putting it into
>> template-tag-common <https://www.npmjs.com/package/template-tag-common>.
>>
>> That library makes it easy to split the operation of a template tag into
>> 3 stages:
>> 1. An optional configuration stage accessed by calling the template tag
>> as a regular function: mytag({ /* options */)`...`
>> 2. Static analysis over the strings. This is memoized.
>> 3. Computing a result from (options, strings, results of step 2,
>> interoplated values)
>>
>> The final loop (step 3) in the template tags I maintain tends to looks
>> like
>>
>> function computeResult(options, staticState /* from step 2 */, strings,
>> ...values) {
>> let n = values.length; // Could do Math.max(strings.length - 1,
>> values.length);
>> let result = strings[0]; // Usually strings.raw
>> for (let i = 0; i < n;) {
>> const interpolatedValue = f(options, staticState[i], values[i]);
>> // Sometimes code here looks backwards at the result to see if it
>> needs to avoid token-merging hazards.
>> result += interpolatedValue;
>> result += strings[++i];
>> }
>> return wrapResult(result); // Produce a value of a type that
>> encapsulates the tag's security guarantees.
>> }
>>
>>
>>
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20181214/b6ce48b2/attachment-0001.html>
More information about the es-discuss
mailing list