diff --git a/.changeset/tasty-pets-marry.md b/.changeset/tasty-pets-marry.md new file mode 100644 index 00000000..1a2f543a --- /dev/null +++ b/.changeset/tasty-pets-marry.md @@ -0,0 +1,5 @@ +--- +"@mod-protocol/core": minor +--- + +feat: expressive content replacement syntax via `mustache.js` diff --git a/packages/core/package.json b/packages/core/package.json index 8457ebd8..7bc1dede 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -17,6 +17,7 @@ "@types/lodash.set": "^4.3.7", "@types/lodash.tonumber": "^4.0.7", "@types/lodash.tostring": "^4.1.7", + "@types/mustache": "^4.2.5", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "eslint": "^7.32.0", @@ -33,6 +34,7 @@ "lodash.mapvalues": "^4.6.0", "lodash.set": "^4.3.2", "lodash.tonumber": "^4.0.3", - "lodash.tostring": "^4.1.4" + "lodash.tostring": "^4.1.4", + "mustache": "^4.2.0" } } diff --git a/packages/core/src/renderer.ts b/packages/core/src/renderer.ts index 743decbd..4a957a14 100644 --- a/packages/core/src/renderer.ts +++ b/packages/core/src/renderer.ts @@ -16,6 +16,12 @@ import { HTTPAction, } from "./manifest"; import { Embed } from "./embeds"; +import Mustache from "mustache"; + +// Prevent default HTML escaping behaviour +Mustache.escape = function (value) { + return value; +}; export type ModElementRef = | { @@ -315,7 +321,18 @@ export interface ExitActionResolver { } function replaceInlineContext(target: string, context: any): string { - return target.replace(/{{([^{{}}]+)}}/g, (_, key) => get(context, key, ``)); + 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; } function matchesOp(value: string, op: Op, context: any): boolean { diff --git a/yarn.lock b/yarn.lock index 99c52297..d7d36cf9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4255,6 +4255,11 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== +"@types/mustache@^4.2.5": + version "4.2.5" + resolved "https://registry.yarnpkg.com/@types/mustache/-/mustache-4.2.5.tgz#9129f0d6857f976e00e171bbb3460e4b702f84ef" + integrity sha512-PLwiVvTBg59tGFL/8VpcGvqOu3L4OuveNvPi0EYbWchRdEVP++yRUXJPFl+CApKEq13017/4Nf7aQ5lTtHUNsA== + "@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^20.8.8": version "20.10.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2" @@ -12137,7 +12142,7 @@ murmurhash3js-revisited@^3.0.0: resolved "https://registry.yarnpkg.com/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz#6bd36e25de8f73394222adc6e41fa3fac08a5869" integrity sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g== -mustache@^4.0.0: +mustache@^4.0.0, mustache@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==