@spintax/core 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -909,6 +909,7 @@ var NotImplementedError = class extends SpintaxError {
909
909
 
910
910
  // src/internal/render.ts
911
911
  var MAX_VARIABLE_DEPTH = 50;
912
+ var MAX_EXPANSION_CHARS = 1024 * 1024;
912
913
  var INCLUDE_LINE_RE = /^[ \t]*#include[ \t\n\r\f\x0B]+"([^"]+)"[ \t\n\r\f\x0B]*$/gmu;
913
914
  function renderAst(ast, ctx) {
914
915
  const base = buildVars(ast.setDefs, ctx.runtimeContext);
@@ -916,7 +917,8 @@ function renderAst(ast, ctx) {
916
917
  rng: ctx.rng,
917
918
  locale: ctx.locale,
918
919
  depth: 0,
919
- onPluralError: ctx.onPluralError
920
+ onPluralError: ctx.onPluralError,
921
+ budget: ctx.budget
920
922
  };
921
923
  const vars = Object.keys(ast.defDefs).length > 0 ? { ...base, ...rollDefinitions(ast.defDefs, base, ctx.runtimeContext, walkOpts) } : base;
922
924
  const text = renderNodes(ast.nodes, { ...walkOpts, vars });
@@ -1029,6 +1031,8 @@ function resolveVariable(name, opts) {
1029
1031
  const value = opts.vars[name.toLowerCase()];
1030
1032
  if (value === void 0) return `%${name}%`;
1031
1033
  if (opts.depth >= MAX_VARIABLE_DEPTH || !/[{[%]/u.test(value)) return value;
1034
+ if (opts.budget.left <= 0) return `%${name}%`;
1035
+ opts.budget.left -= value.length;
1032
1036
  return renderNodes(parseSequence(value), { ...opts, depth: opts.depth + 1 });
1033
1037
  }
1034
1038
  function expandVarsOnly(text, opts) {
@@ -1038,6 +1042,8 @@ function expandVarsOnly(text, opts) {
1038
1042
  out = out.replace(/%(\w+)%/gu, (m, name) => {
1039
1043
  const value = opts.vars[name.toLowerCase()];
1040
1044
  if (value === void 0) return m;
1045
+ if (opts.budget.left <= 0) return m;
1046
+ opts.budget.left -= value.length;
1041
1047
  changed = true;
1042
1048
  return value;
1043
1049
  });
@@ -1352,7 +1358,10 @@ function renderWith(input, rng, opts = {}) {
1352
1358
  resolver: opts.includeResolver,
1353
1359
  maxDepth: opts.maxDepth ?? DEFAULT_MAX_DEPTH,
1354
1360
  includeStack: [],
1355
- onPluralError: opts.onPluralError
1361
+ onPluralError: opts.onPluralError,
1362
+ // One allowance for the whole call. Created here rather than in renderAst because
1363
+ // includes re-enter renderAst, and a budget made there is a budget per subtree.
1364
+ budget: { left: MAX_EXPANSION_CHARS }
1356
1365
  };
1357
1366
  const ast = resolveAst(input);
1358
1367
  let out = renderAst(ast, ctx);