feat(core): expressive content replacement by stephancill · Pull Request #139 · mod-protocol/mod · GitHub
Skip to content

feat(core): expressive content replacement#139

Draft
stephancill wants to merge 1 commit into
mainfrom
feat/expressive-context-replacement
Draft

feat(core): expressive content replacement#139
stephancill wants to merge 1 commit into
mainfrom
feat/expressive-context-replacement

Conversation

@stephancill

@stephancill stephancill commented Dec 23, 2023

Copy link
Copy Markdown
Contributor

Change Summary

This PR proposes a standard syntax for string manipulation inside Mod elements by adopting mustache.js. This library is lightweight at 6.5kb minified or 2.7kb minified+gzipped (bundlephobia) and uses a familiar {{}} syntax for replacement as well as path.to.value syntax for accessing nested context values, making it backwards compatible.

Arbitrary functions can be exposed to the mustache syntax in the replaceInlineContext function by passing anonymous function builders along with the context to the rendering function (see the Lambdas section in the manual and spec).

An example adjustment to the replaceInlineContext function which introduces a decimals operator which displays a number to a fixed number of decimals would look like this:

function replaceInlineContext(target: string, context: any): string {
  const output = Mustache.render(target, {
    ...context,
    decimals: function () {
      return function (text: string, render: (text: string) => string) {
        var parts = text.split(" ");
        var value = parseFloat(render(parts[0]));
        var decimalPlaces = parseInt(render(parts[1]), 10);
        return value.toFixed(decimalPlaces);
      };
    },
  });
  return output;
}

And would be used like this:

console.log(
  replaceInlineContext(
    "Output: {{#decimals}}{{refs.sample.value}} 3{{/decimals}}",
    { refs: { sample: { value: 0.12345678 } } }
  )
);

Output: 0.123

Merge Checklist

  • PR has a changeset
  • PR includes documentation if necessary
  • PR updates the rich-embed examples if necessary
  • includes a parallel PR for Mod-starter and the gateway if necessary

@changeset-bot

changeset-bot Bot commented Dec 23, 2023

Copy link
Copy Markdown

@vercel

vercel Bot commented Dec 23, 2023

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
api ✅ Ready (Inspect) Visit Preview Dec 23, 2023 3:18pm
docs ✅ Ready (Inspect) Visit Preview Dec 23, 2023 3:18pm
example-nextjs-shadcn ✅ Ready (Inspect) Visit Preview Dec 23, 2023 3:18pm

@stephancill stephancill added the enhancement New feature or request label Dec 23, 2023

@davidfurlong davidfurlong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like using existing standards for this.

however I'm a bit hesitant of this exact implementation, as

  • mustache hasn't had a commit in a year
  • I'm concerned about how many functions will be needed to support all the edge cases

however I think it'll be reasonably easy to change later so I'm ok with going with it

import Mustache from "mustache";

// Prevent default HTML escaping behaviour
Mustache.escape = function (value) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overriding globals is probably not a good idea given that this code is executed in the same context as other apps

return target.replace(/{{([^{{}}]+)}}/g, (_, key) => get(context, key, ``));
const output = Mustache.render(target, {
...context,
decimals: function () {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with this pattern, this list of functions is going to grow very long and it'll be bundled into every app.

@stephancill

Copy link
Copy Markdown
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants