String identity template tag

Isiah Meadows isiahmeadows at gmail.com
Fri Dec 14 19:25:51 UTC 2018


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.
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/71bb0673/attachment.html>


More information about the es-discuss mailing list