Macros 2.0 (v0.5.1) - Delayed Macro Argument Resolution for `{{if}}` Macro (#4934) * Add variable shorthand syntax support for local and global variables - Add VariableShorthandType enum and VariableShorthandDefinitions for `.` (local) and `$` (global) prefixes - Add VariableShorthandAutoCompleteOption class for autocomplete of variable shorthand syntax - Implement variable expression parsing in MacroCstWalker to handle `{{.varName}}` and `{{$varName}}` syntax - Add support for variable operations: get, set (=), increment (++), decrement (--), and add (+=) - Route variable expressions to appropriate macro via handler * Add variable shorthand autocomplete support for variable names and operators - Add `isValidVariableShorthandName()` helper to validate variable names against shorthand pattern - Add `VariableNameAutoCompleteOption` class for suggesting existing and new variable names - Add `VariableOperatorAutoCompleteOption` class for suggesting operators (=, ++, --, +=) - Add `VariableOperatorDefinitions` map with operator metadata (symbol, name, description, needsValue) * Add variable shorthand support to {{if}} macro condition autocomplete - Add variable shorthand (.var, $var) support to {{if}} condition evaluation in core-macros.js - Detect and resolve variable shorthands using getvar/getglobalvar macros before condition check - Update {{if}} description and examples to document variable shorthand syntax - Add variable shorthand autocomplete options when typing {{if}} condition - Show variable prefix options (. and $) when no condition is typed yet - Reuse #buildVariableShorthandOptions * refactor: Add Object.freeze to lexer constants and improve JSDoc documentation - Freeze `modes` and `Tokens` objects to prevent accidental mutations - Convert inline comments to proper JSDoc format for better documentation - Add JSDoc block for `Def` lexer definition object - Improve comment clarity and formatting consistency throughout MacroLexer.js - Remove redundant section separator comments in variable shorthand modes * Add inversion prefix (!) autocomplete support to {{if}} macro condition - Add SimpleAutoCompleteOption class for basic autocomplete items with name, symbol, and description - Add ! inversion prefix as autocomplete option in {{if}} condition with 🔁 icon - Show ! as selectable option when nothing typed, non-selectable when already present - Fix condition parsing to handle ! prefix with whitespace (e.g., "! $myvar") - Update identifier extraction to strip ! and whitespace before detecting variable * fix lint * Fix variable shorthand regex in {{if}} macro to properly capture prefix and variable name * Expand comprehensive e2e tests for variable shorthand syntax in lexer and macro engine - Add MacroLexer tests for variable shorthand edge cases (whitespace, numbers, underscores, operators) - Add MacroEngine tests for variable shorthand operations (hyphens, underscores, non-existent vars, chaining) - Add MacroEngine tests for variable shorthand in {{if}} conditions (truthy/falsy, inversion, else branches) - Test variable names with hyphens, underscores, and numbers in both get/set and conditional contexts * Fix macro flags not being allowed inside variable shorthand macros - Move MANY(flags) block from macroBody to macro rule to parse flags before branching - Fix MacroCstWalker to extract flags from children.flags instead of bodyChildren.flags - Ensures flags are available for both variable expressions and regular macros - Fixes flag extraction in visitMacro and visitBlockMacroClose methods * Implement delayed argument resolution for {{if}} macro to prevent side effects in non-chosen branches - Add `delayArgResolution` flag to MacroDefinition to control when nested macros are evaluated - Modify MacroCstWalker to skip nested macro evaluation when delayArgResolution is true - Update {{if}} macro to use delayArgResolution and manually resolve only the chosen branch - Replace ELSE_MARKER splitting with `splitOnTopLevelElse()` that parses CST to find correct {{else}} at depth 0 * Fix delayed resolve on if/else macros being off when a non-scoped if macro was being used inside - Track argument count in MacroCstWalker.extractMacroInfo() to distinguish inline vs scoped macros - Update splitOnTopLevelElse() to only track scoped {{if}} blocks (1 arg) when finding {{else}} at depth 0 - Update findClosingMacro() to only increment depth for macros that can accept scoped content - Add e2e tests for inline {{if::condition::content}} inside scoped {{if}}/{{else}} blocks * Remove eslint exclusion * Remove duplicate tests * Regenerate package-lock.json in /tests --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

81414724b07ac186547babc12c41ea90352b8cca

Wolfsblvt <wolfsblvt@gmail.com>

Signed
6 files changed, +344 -807Showing whitespace changes
public/scripts/macros/definitions/core-macros.js+65 -20
@@ -4,8 +4,9 @@ import { getStringHash, isFalseBoolean } from '../../utils.js';
44import { textgenerationwebui_banned_in_macros } from '../../textgen-settings.js';
55import { inject_ids } from '../../constants.js';
66import { MacroRegistry, MacroCategory, MacroValueType } from '../engine/MacroRegistry.js';
7-import { MacroEngine } from '../engine/MacroEngine.js';
87import { MACRO_VARIABLE_SHORTHAND_PATTERN } from '../engine/MacroLexer.js';
8+import { MacroParser } from '../engine/MacroParser.js';
9+import { MacroCstWalker } from '../engine/MacroCstWalker.js';
910
1011/**
1112 * Marker used by {{else}} to split content in {{if}} blocks.
@@ -92,6 +93,40 @@ export function registerCoreMacros() {
9293 },
9394 });
9495
96+ /**
97+ * Splits raw content on the first {{else}} macro at nesting depth 0.
98+ * Tracks scoped {{if}}/{{/if}} pairs to find the correct top-level else.
99+ * Only {{if}} with 1 argument (condition only) are considered scoped blocks.
100+ *
101+ * @param {string} content - The raw content to split
102+ * @returns {{ thenBranch: string, elseBranch: string | undefined }}
103+ */
104+ function splitOnTopLevelElse(content) {
105+ const { cst } = MacroParser.parseDocument(content);
106+ const macroNodes = /** @type {import('chevrotain').CstNode[]} */ (cst?.children?.macro || []);
107+
108+ let depth = 0;
109+ for (const macroNode of macroNodes) {
110+ const info = MacroCstWalker.extractMacroInfo(macroNode);
111+ if (!info) continue;
112+
113+ // Only track scoped {{if}} blocks (1 arg = condition only, expects {{/if}})
114+ // Inline {{if condition::content}} has 2 args and doesn't affect depth
115+ if (info.name === 'if' && !info.isClosing && info.argCount === 1) {
116+ depth++;
117+ } else if (info.name === 'if' && info.isClosing) {
118+ depth--;
119+ } else if (info.name === 'else' && depth === 0) {
120+ return {
121+ thenBranch: content.slice(0, info.startOffset),
122+ elseBranch: content.slice(info.endOffset + 1),
123+ };
124+ }
125+ }
126+
127+ return { thenBranch: content, elseBranch: undefined };
128+ }
129+
95130 // {{if condition}}content{{/if}} -> conditional content
96131 // {{if condition}}then-content{{else}}else-content{{/if}} -> conditional with else branch
97132 // {{if !condition}}content{{/if}} -> inverted conditional (negated)
@@ -119,16 +154,23 @@ export function registerCoreMacros() {
119154 '{{if $globalFlag}}Global flag is set{{/if}}',
120155 ],
121156 returns: 'The content if condition is truthy, else branch or empty string otherwise.',
122- handler: ({ unnamedArgs: [condition, content], rawArgs: [rawCondition], flags, env, trimContent }) => {
157+ // Delay argument resolution so nested macros are only evaluated in the chosen branch
123- // Check if the ORIGINAL condition (before macro resolution) starts with !
158+ delayArgResolution: true,
124- // We use raw args to check this, as the resolved value might start with ! from a variable
159+ handler: ({ unnamedArgs: [rawCondition, rawContent], flags, resolve, trimContent }) => {
160+ // With delayArgResolution: true, args contain raw (unresolved) text.
161+ // We resolve the condition first, then only resolve the chosen branch.
162+
163+ // Check if the condition starts with ! for inversion
125164 let inverted = false;
165+ let condition = rawCondition;
126166 if (/^\s*!/.test(rawCondition)) {
127167 inverted = true;
128- // Strip the ! from the resolved condition if it was the prefix
168+ condition = rawCondition.replace(/^\s*!\s*/, '');
129- condition = condition.replace(/^!\s*/, '');
130169 }
131170
171+ // Resolve the condition (may contain nested macros like {{getvar::x}})
172+ condition = resolve(condition);
173+
132174 // Check if condition is a variable shorthand (.varname or $varname)
133175 // If so, resolve it using the appropriate variable macro
134176 const varShorthandRegex = new RegExp(`^([.$])(${MACRO_VARIABLE_SHORTHAND_PATTERN.source})$`);
@@ -136,16 +178,13 @@ export function registerCoreMacros() {
136178 if (varShorthandMatch) {
137179 const [, prefix, varName] = varShorthandMatch;
138180 const varMacro = prefix === '.' ? 'getvar' : 'getglobalvar';
139- // Resolve the variable using MacroEngine.evaluate
181+ condition = resolve(`{{${varMacro}::${varName}}}`);
140- condition = MacroEngine.evaluate(`{{${varMacro}::${varName}}}`, env);
141182 } else {
142183 // Check if condition is a registered macro name (without braces)
143184 // If so, resolve it first (only for macros that accept 0 required args)
144185 const macroDef = MacroRegistry.getPrimaryMacro(condition);
145186 if (macroDef && macroDef.minArgs === 0) {
146- // Use MacroEngine.evaluate to properly resolve the macro with full context
187+ condition = resolve(`{{${condition}}}`);
147- // This ensures all handler args (cst, normalize, list, etc.) are correctly provided
148- condition = MacroEngine.evaluate(`{{${condition}}}`, env);
149188 }
150189 }
151190
@@ -153,17 +192,23 @@ export function registerCoreMacros() {
153192 let isFalsy = condition === '' || isFalseBoolean(condition);
154193 if (inverted) isFalsy = !isFalsy;
155194
156195 // Split raw content on {{else}} markermacro (ifat present)the top nesting level
157- const [thenBranch, elseBranch] = content.split(ELSE_MARKER);
196+ // We need to track nesting depth to find the correct {{else}} for this if
158- const result = !isFalsy ? thenBranch : elseBranch;
197+ const { thenBranch, elseBranch } = splitOnTopLevelElse(rawContent);
198+
199+ // Only resolve the chosen branch
200+ const chosenBranch = !isFalsy ? thenBranch : elseBranch;
201+ if (chosenBranch === undefined) {
202+ return '';
203+ }
159204
160205 // Trim branchesResolve unlessnested #macros flagin isthe setchosen (preserveWhitespace)branch
161- // The engine auto-trims the whole scoped content, but we still need to trim
206+ // Trim result unless # flag is set (preserveWhitespace)
162- // around the {{else}} marker since that's internal to this macro
207+ let result = resolve(chosenBranch);
163208 if (!flags.preserveWhitespace) {
164- return result ?? '';
209+ result = trimContent(result);
165210 }
166211 return trimContent(result ?? '');
167212 },
168213 });
169214
public/scripts/macros/engine/MacroCstWalker.js+83 -7
@@ -45,6 +45,15 @@ import { MacroRegistry } from './MacroRegistry.js';
4545 */
4646
4747/**
48+ * @typedef {Object} MacroNodeInfo
49+ * @property {string} name - The macro identifier name.
50+ * @property {boolean} isClosing - Whether this macro has the closing block flag (/).
51+ * @property {number} startOffset - Start position in the source text.
52+ * @property {number} endOffset - End position in the source text (inclusive).
53+ * @property {number} argCount - Number of arguments provided to the macro.
54+ */
55+
56+/**
4857 * The singleton instance of the MacroCstWalker.
4958 *
5059 * @type {MacroCstWalker}
@@ -127,6 +136,54 @@ class MacroCstWalker {
127136 }
128137
129138 /**
139+ * Extracts basic info from a macro CST node: name, closing flag, position, and argument count.
140+ * Returns null for variable expressions or nodes without valid identifiers.
141+ *
142+ * @param {CstNode} macroNode - A macro CST node from the parser.
143+ * @returns {MacroNodeInfo | null}
144+ */
145+ extractMacroInfo(macroNode) {
146+ const children = macroNode?.children || {};
147+
148+ // Variable expressions don't have standard macro identifiers
149+ if ((children.variableExpr || [])[0]) {
150+ return null;
151+ }
152+
153+ // Get start/end tokens for position
154+ const startToken = /** @type {IToken?} */ ((children['Macro.Start'] || [])[0]);
155+ const endToken = /** @type {IToken?} */ ((children['Macro.End'] || [])[0]);
156+ if (!startToken || !endToken) {
157+ return null;
158+ }
159+
160+ // Get identifier and arguments from macroBody
161+ const macroBodyNode = /** @type {CstNode?} */ ((children.macroBody || [])[0]);
162+ const bodyChildren = macroBodyNode?.children || {};
163+ const identifierTokens = /** @type {IToken[]} */ (bodyChildren['Macro.identifier'] || []);
164+ const name = identifierTokens[0]?.image || '';
165+
166+ if (!name) return null;
167+
168+ // Count arguments (arguments rule contains argument nodes)
169+ const argumentsNode = /** @type {CstNode?} */ ((bodyChildren.arguments || [])[0]);
170+ const argumentNodes = /** @type {CstNode[]} */ (argumentsNode?.children?.argument || []);
171+ const argCount = argumentNodes.length;
172+
173+ // Check for closing block flag
174+ const flagTokens = /** @type {IToken[]} */ (children.flags || []);
175+ const isClosing = flagTokens.some(token => token.image === MacroFlagType.CLOSING_BLOCK);
176+
177+ return {
178+ name,
179+ isClosing,
180+ startOffset: startToken.startOffset,
181+ endOffset: endToken.endOffset,
182+ argCount,
183+ };
184+ }
185+
186+ /**
130187 * Finds unclosed scoped macros in a document CST.
131188 * Used by autocomplete to suggest closing tags.
132189 *
@@ -278,6 +335,10 @@ class MacroCstWalker {
278335 const argumentsNode = /** @type {CstNode?} */ ((bodyChildren.arguments || [])[0]);
279336 const argumentNodes = /** @type {CstNode[]} */ (argumentsNode?.children?.argument || []);
280337
338+ // Check if this macro has delayArgResolution flag - if so, skip nested macro evaluation
339+ const macroDef = MacroRegistry.getMacro(name);
340+ const delayArgResolution = macroDef?.delayArgResolution === true;
341+
281342 /** @type {string[]} */
282343 const args = [];
283344 /** @type {({ value: string } & TokenRange)[]} */
@@ -286,18 +347,20 @@ class MacroCstWalker {
286347 const rawArgs = [];
287348
288349 for (const argNode of argumentNodes) {
289350 const argValuelocation = this.#evaluateArgumentNodegetArgumentLocation(argNode, context);
351+ const rawArgText = location ? text.slice(location.startOffset, location.endOffset + 1) : '';
352+ rawArgs.push(rawArgText);
353+
354+ // If delayArgResolution is true, use raw text; otherwise evaluate nested macros
355+ const argValue = delayArgResolution ? rawArgText : this.#evaluateArgumentNode(argNode, context);
290356 args.push(argValue);
291357
292- const location = this.#getArgumentLocation(argNode);
293358 if (location) {
294359 evaluatedArguments.push({
295360 value: argValue,
296361 ...location,
297362 });
298363 }
299-
300- rawArgs.push(location ? text.slice(location.startOffset, location.endOffset + 1) : '');
301364 }
302365
303366 // If this macro has scoped content, evaluate it and append as the last argument
@@ -305,13 +368,22 @@ class MacroCstWalker {
305368 // Handle empty scoped content (when opening and closing are adjacent)
306369 if (scopedContent.startOffset > scopedContent.endOffset) {
307370 args.push('');
371+ rawArgs.push('');
308372 } else {
309373 letconst scopedValuerawScopedText = thistext.#evaluateScopedContentslice(scopedContent.startOffset, contextscopedContent.endOffset + 1);
374+ rawArgs.push(rawScopedText);
310375
376+ // If delayArgResolution is true, use raw text; otherwise evaluate nested macros
377+ let scopedValue;
378+ if (delayArgResolution) {
379+ scopedValue = rawScopedText;
380+ } else {
381+ scopedValue = this.#evaluateScopedContent(scopedContent, context);
311382 // Auto-trim scoped content unless the '#' (preserveWhitespace) flag is set
312383 if (!flags.preserveWhitespace) {
313384 scopedValue = trimContent(scopedValue);
314385 }
386+ }
315387
316388 args.push(scopedValue);
317389
@@ -1001,7 +1073,8 @@ class MacroCstWalker {
10011073
10021074 /**
10031075 * Finds the matching closing macro for an opening macro at the given index.
10041076 * Handles nested scopes by tracking depth. Only counts opening macros that
1077+ * can accept scoped content (inline macros with all args filled don't count).
10051078 *
10061079 * @param {Array<{ index: number, item: DocumentItemMacro, name: string, isClosing: boolean, matched: boolean }>} macroInfos
10071080 * @param {number} openingIdx - Index in macroInfos array of the opening macro.
@@ -1027,10 +1100,13 @@ class MacroCstWalker {
10271100 return i;
10281101 }
10291102 } else {
10301103 // AnotherOnly openingincrement macrodepth withfor theopening samemacros namethat increasescan depthaccept scoped content
1104+ // Inline macros (e.g., {{if condition::content}}) don't need closing tags
1105+ if (this.#canAcceptScopedContent(info.item.node, info.name)) {
10311106 depth++;
10321107 }
10331108 }
1109+ }
10341110
10351111 return -1; // No matching closing macro found
10361112 }
public/scripts/macros/engine/MacroEngine.js+1 -0
@@ -188,6 +188,7 @@ class MacroEngine {
188188 source: { name: 'dynamic', isExtension: false, isThirdParty: false },
189189 aliasOf: null,
190190 aliasVisible: null,
191+ delayArgResolution: false,
191192 handler: typeof impl === 'function' ? impl : () => impl,
192193 };
193194 }
public/scripts/macros/engine/MacroRegistry.js+14 -2
@@ -71,6 +71,7 @@ export const MacroValueType = Object.freeze({
7171 * @property {MacroValueType|MacroValueType[]} [returnType=MacroValueType.STRING] - The type(s) this macro returns. Defaults to string.
7272 * @property {string} [displayOverride] - Override the auto-generated macro signature for display (must include curly braces, e.g. "{{macro::arg}}").
7373 * @property {string|string[]} [exampleUsage] - Example usage(s) shown in documentation (must include curly braces).
74+ * @property {boolean} [delayArgResolution=false] - If true, nested macros in arguments or scope are NOT resolved before calling the handler. The handler receives raw argument text and must call resolve() manually. Use sparingly - only for control-flow macros like {{if}}.
7475 * @property {MacroHandler} handler - The handler function for the macro.
7576 */
7677
@@ -103,7 +104,7 @@ export const MacroValueType = Object.freeze({
103104/**
104105 * @typedef {Object} MacroExecutionContext
105106 * @property {string} name
106107 * @property {string[]} args - All unnamed arguments passed to the macro. If delayArgResolution is true, these contain raw (unresolved) text.
107108 * @property {string[]} unnamedArgs - Unnamed positional arguments (both required and optional, up to the defined count).
108109 * @property {string[]|null} list - List arguments (after unnamed args), or null if list is not enabled.
109110 * @property {{ [key: string]: string }|null} namedArgs - Reserved for future named argument support.
@@ -111,12 +112,13 @@ export const MacroValueType = Object.freeze({
111112 * @property {boolean} isScoped - Whether this macro was invoked using scoped syntax (opening + closing tags).
112113 * @property {string} raw - The inner macro content with nested macros resolved.
113114 * @property {string} rawOriginal - The original full macro text including braces, before any resolution.
114115 * @property {string[]} rawArgs - The original arguments passed to the macro (always unresolved).
115116 * @property {MacroEnv} env
116117 * @property {CstNode|null} cstNode
117118 * @property {{ startOffset: number, endOffset: number }|null} range
118119 * @property {(value: any) => string} normalize - Normalize function to use on unsure macro results to make sure they return strings as expected.
119120 * @property {(content: string, options?: { trimIndent?: boolean }) => string} trimContent - Trims scoped content with optional indentation dedent. Defaults to trimming indentation.
121+ * @property {(text: string) => string} resolve - Evaluates macros in the given text using the same environment. Use when delayArgResolution is true.
120122 */
121123
122124/**
@@ -134,6 +136,7 @@ export const MacroValueType = Object.freeze({
134136 * @property {MacroValueType|MacroValueType[]} returnType - The type(s) this macro returns.
135137 * @property {string|null} displayOverride - Override for the auto-generated macro signature display.
136138 * @property {string[]} exampleUsage - Example usage strings for documentation.
139+ * @property {boolean} delayArgResolution - If true, nested macros in arguments are NOT resolved before calling the handler. The handler receives raw argument text and must call resolve() manually. Use sparingly - only for control-flow macros like {{if}}.
137140 * @property {MacroHandler} handler
138141 * @property {MacroSource} source
139142 * @property {string|null} aliasOf - If this is an alias, the primary macro name this is an alias of. Can also be used to check if this is an alias macro.
@@ -203,6 +206,7 @@ class MacroRegistry {
203206 returnType: rawReturnType,
204207 displayOverride: rawDisplayOverride,
205208 exampleUsage: rawExampleUsage,
209+ delayArgResolution: rawDelayArgResolution,
206210 handler,
207211 } = options;
208212
@@ -358,6 +362,12 @@ class MacroRegistry {
358362 }
359363 }
360364
365+ let delayArgResolution = false;
366+ if (rawDelayArgResolution !== undefined) {
367+ if (typeof rawDelayArgResolution !== 'boolean') throw new Error(`Macro "${name}" options.delayArgResolution must be a boolean when provided.`);
368+ delayArgResolution = rawDelayArgResolution;
369+ }
370+
361371 const nameKey = name.toLowerCase();
362372 if (this.#macros.has(nameKey)) {
363373 logMacroRegisterWarning({ macroName: name, message: `Macro "${name}" is already registered and will be overwritten.` });
@@ -381,6 +391,7 @@ class MacroRegistry {
381391 returnType,
382392 displayOverride,
383393 exampleUsage,
394+ delayArgResolution,
384395 handler,
385396 source: {
386397 name: source,
@@ -551,6 +562,7 @@ class MacroRegistry {
551562 range: call.range,
552563 normalize: MacroEngine.normalizeMacroResult.bind(MacroEngine),
553564 trimContent: MacroEngine.trimScopedContent.bind(MacroEngine),
565+ resolve: (text) => MacroEngine.evaluate(text, call.env),
554566 };
555567
556568 const result = def.handler(executionContext);
tests/frontend/MacroEngine.e2e.js+180 -0
@@ -1924,6 +1924,186 @@ test.describe('MacroEngine', () => {
19241924 expect(output).toBe('Count: 42');
19251925 });
19261926 });
1927+
1928+ const getUniqueVariableId = () => `dt_${Date.now()}_${Math.random().toString(36).slice(2)}`;
1929+
1930+ test.describe('Delayed Argument Resolution ({{if}} branch isolation)', () => {
1931+ // Core feature: setvar in non-chosen branch should NOT execute
1932+ test('should NOT execute setvar in false branch', async ({ page }) => {
1933+ const id = getUniqueVariableId();
1934+ const output = await page.evaluate(async (id) => {
1935+ const { MacroEngine } = await import('./scripts/macros/engine/MacroEngine.js');
1936+ const { MacroEnvBuilder } = await import('./scripts/macros/engine/MacroEnvBuilder.js');
1937+ const ctx = SillyTavern.getContext();
1938+
1939+ ctx.variables.local.del(id);
1940+
1941+ const input = `{{if 0}}{{setvar::${id}::should-not-set}}{{/if}}`;
1942+ const env = MacroEnvBuilder.buildFromRawEnv({ content: input });
1943+ MacroEngine.evaluate(input, env);
1944+
1945+ // Variable should NOT be set because the branch was not taken
1946+ const result = ctx.variables.local.get(id);
1947+ ctx.variables.local.del(id);
1948+ return result;
1949+ }, id);
1950+
1951+ expect(output).toBe('');
1952+ });
1953+
1954+ // setvar in true branch SHOULD execute
1955+ test('should execute setvar in true branch', async ({ page }) => {
1956+ const id = getUniqueVariableId();
1957+ const output = await page.evaluate(async (id) => {
1958+ const { MacroEngine } = await import('./scripts/macros/engine/MacroEngine.js');
1959+ const { MacroEnvBuilder } = await import('./scripts/macros/engine/MacroEnvBuilder.js');
1960+ const ctx = SillyTavern.getContext();
1961+
1962+ ctx.variables.local.del(id);
1963+
1964+ const input = `{{if 1}}{{setvar::${id}::was-set}}{{/if}}`;
1965+ const env = MacroEnvBuilder.buildFromRawEnv({ content: input });
1966+ MacroEngine.evaluate(input, env);
1967+
1968+ const result = ctx.variables.local.get(id);
1969+ ctx.variables.local.del(id);
1970+ return result;
1971+ }, id);
1972+
1973+ expect(output).toBe('was-set');
1974+ });
1975+
1976+ // With else branch: only the chosen branch's setvar should execute
1977+ test('should only execute setvar in chosen else branch', async ({ page }) => {
1978+ const id = getUniqueVariableId();
1979+ const output = await page.evaluate(async (id) => {
1980+ const { MacroEngine } = await import('./scripts/macros/engine/MacroEngine.js');
1981+ const { MacroEnvBuilder } = await import('./scripts/macros/engine/MacroEnvBuilder.js');
1982+ const ctx = SillyTavern.getContext();
1983+
1984+ ctx.variables.local.del(id);
1985+
1986+ const input = `{{if 0}}{{setvar::${id}::then-branch}}{{else}}{{setvar::${id}::else-branch}}{{/if}}`;
1987+ const env = MacroEnvBuilder.buildFromRawEnv({ content: input });
1988+ MacroEngine.evaluate(input, env);
1989+
1990+ const result = ctx.variables.local.get(id);
1991+ ctx.variables.local.del(id);
1992+ return result;
1993+ }, id);
1994+
1995+ expect(output).toBe('else-branch');
1996+ });
1997+
1998+ // Verify then branch setvar executes, not else branch
1999+ test('should only execute setvar in chosen then branch', async ({ page }) => {
2000+ const id = getUniqueVariableId();
2001+ const output = await page.evaluate(async (id) => {
2002+ const { MacroEngine } = await import('./scripts/macros/engine/MacroEngine.js');
2003+ const { MacroEnvBuilder } = await import('./scripts/macros/engine/MacroEnvBuilder.js');
2004+ const ctx = SillyTavern.getContext();
2005+
2006+ ctx.variables.local.del(id);
2007+
2008+ const input = `{{if 1}}{{setvar::${id}::then-branch}}{{else}}{{setvar::${id}::else-branch}}{{/if}}`;
2009+ const env = MacroEnvBuilder.buildFromRawEnv({ content: input });
2010+ MacroEngine.evaluate(input, env);
2011+
2012+ const result = ctx.variables.local.get(id);
2013+ ctx.variables.local.del(id);
2014+ return result;
2015+ }, id);
2016+
2017+ expect(output).toBe('then-branch');
2018+ });
2019+
2020+ // Multiple setvars in branches - only chosen branch's setvars execute
2021+ test('should execute multiple setvars only in chosen branch', async ({ page }) => {
2022+ const id = getUniqueVariableId();
2023+ const output = await page.evaluate(async (id) => {
2024+ const { MacroEngine } = await import('./scripts/macros/engine/MacroEngine.js');
2025+ const { MacroEnvBuilder } = await import('./scripts/macros/engine/MacroEnvBuilder.js');
2026+ const ctx = SillyTavern.getContext();
2027+
2028+ ctx.variables.local.del(`${id}_a`);
2029+ ctx.variables.local.del(`${id}_b`);
2030+
2031+ const input = `{{if 0}}{{setvar::${id}_a::wrong}}{{setvar::${id}_b::wrong}}{{else}}{{setvar::${id}_a::right}}{{setvar::${id}_b::right}}{{/if}}`;
2032+ const env = MacroEnvBuilder.buildFromRawEnv({ content: input });
2033+ MacroEngine.evaluate(input, env);
2034+
2035+ const a = ctx.variables.local.get(`${id}_a`);
2036+ const b = ctx.variables.local.get(`${id}_b`);
2037+ ctx.variables.local.del(`${id}_a`);
2038+ ctx.variables.local.del(`${id}_b`);
2039+ return `a=${a},b=${b}`;
2040+ }, id);
2041+
2042+ expect(output).toBe('a=right,b=right');
2043+ });
2044+
2045+ // Nested if with delayed resolution - inner if should also work correctly
2046+ test('should handle nested if with delayed resolution', async ({ page }) => {
2047+ const id = `dt_nested_${Date.now()}_${Math.random().toString(36).slice(2)}`;
2048+ const output = await page.evaluate(async (id) => {
2049+ const { MacroEngine } = await import('./scripts/macros/engine/MacroEngine.js');
2050+ const { MacroEnvBuilder } = await import('./scripts/macros/engine/MacroEnvBuilder.js');
2051+ const ctx = SillyTavern.getContext();
2052+
2053+ ctx.variables.local.del(`${id}_outer`);
2054+ ctx.variables.local.del(`${id}_inner`);
2055+
2056+ // Outer if is true, inner if is false
2057+ const input = `{{if 1}}{{setvar::${id}_outer::yes}}{{if 0}}{{setvar::${id}_inner::wrong}}{{else}}{{setvar::${id}_inner::correct}}{{/if}}{{/if}}`;
2058+ const env = MacroEnvBuilder.buildFromRawEnv({ content: input });
2059+ MacroEngine.evaluate(input, env);
2060+
2061+ const outer = ctx.variables.local.get(`${id}_outer`);
2062+ const inner = ctx.variables.local.get(`${id}_inner`);
2063+ ctx.variables.local.del(`${id}_outer`);
2064+ ctx.variables.local.del(`${id}_inner`);
2065+ return `outer=${outer},inner=${inner}`;
2066+ }, id);
2067+
2068+ expect(output).toBe('outer=yes,inner=correct');
2069+ });
2070+
2071+ // Variable-based condition with delayed resolution
2072+ test('should work with variable shorthand condition and delayed resolution', async ({ page }) => {
2073+ const id = `dt_varsh_${Date.now()}_${Math.random().toString(36).slice(2)}`;
2074+ const output = await page.evaluate(async (id) => {
2075+ const { MacroEngine } = await import('./scripts/macros/engine/MacroEngine.js');
2076+ const { MacroEnvBuilder } = await import('./scripts/macros/engine/MacroEnvBuilder.js');
2077+ const ctx = SillyTavern.getContext();
2078+
2079+ ctx.variables.local.set(`${id}_flag`, '');
2080+ ctx.variables.local.del(`${id}_result`);
2081+
2082+ const input = `{{if .${id}_flag}}{{setvar::${id}_result::truthy}}{{else}}{{setvar::${id}_result::falsy}}{{/if}}`;
2083+ const env = MacroEnvBuilder.buildFromRawEnv({ content: input });
2084+ MacroEngine.evaluate(input, env);
2085+
2086+ const result = ctx.variables.local.get(`${id}_result`);
2087+ ctx.variables.local.del(`${id}_flag`);
2088+ ctx.variables.local.del(`${id}_result`);
2089+ return result;
2090+ }, id);
2091+
2092+ expect(output).toBe('falsy');
2093+ });
2094+
2095+ // Inline {{if}} should not break outer {{else}} detection
2096+ test('should handle inline if inside scoped if with else', async ({ page }) => {
2097+ const output = await evaluateWithEngine(page, '{{if 0}}{{if::1::inner}}{{else}}outer-else{{/if}}');
2098+ expect(output).toBe('outer-else');
2099+ });
2100+
2101+ // Another inline if scenario - inner inline if should not affect outer else
2102+ test('should correctly find outer else with multiple inline ifs', async ({ page }) => {
2103+ const output = await evaluateWithEngine(page, '{{if 0}}{{if::1::a}}{{if::1::b}}{{else}}found{{/if}}');
2104+ expect(output).toBe('found');
2105+ });
2106+ });
19272107});
19282108
19292109/**
tests/package-lock.json+1 -778
@@ -1041,6 +1041,7 @@
10411041 "version": "7.7.1",
10421042 "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
10431043 "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
1044+ "extraneous": true,
10441045 "license": "ISC",
10451046 "bin": {
10461047 "semver": "bin/semver.js"
@@ -1049,27 +1050,6 @@
10491050 "node": ">=10"
10501051 }
10511052 },
1052- "node_modules/@sideway/address": {
1053- "version": "4.1.5",
1054- "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
1055- "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==",
1056- "license": "BSD-3-Clause",
1057- "dependencies": {
1058- "@hapi/hoek": "^9.0.0"
1059- }
1060- },
1061- "node_modules/@sideway/formula": {
1062- "version": "3.0.1",
1063- "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
1064- "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==",
1065- "license": "BSD-3-Clause"
1066- },
1067- "node_modules/@sideway/pinpoint": {
1068- "version": "2.0.0",
1069- "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
1070- "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
1071- "license": "BSD-3-Clause"
1072- },
10731053 "node_modules/@sinclair/typebox": {
10741054 "version": "0.27.8",
10751055 "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@@ -1094,12 +1074,6 @@
10941074 "@sinonjs/commons": "^3.0.0"
10951075 }
10961076 },
1097- "node_modules/@tootallnate/quickjs-emscripten": {
1098- "version": "0.23.0",
1099- "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
1100- "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
1101- "license": "MIT"
1102- },
11031077 "node_modules/@types/babel__core": {
11041078 "version": "7.20.5",
11051079 "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1214,16 +1188,6 @@
12141188 "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
12151189 "license": "MIT"
12161190 },
1217- "node_modules/@types/yauzl": {
1218- "version": "2.10.3",
1219- "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
1220- "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
1221- "license": "MIT",
1222- "optional": true,
1223- "dependencies": {
1224- "@types/node": "*"
1225- }
1226- },
12271191 "node_modules/@ungap/structured-clone": {
12281192 "version": "1.2.0",
12291193 "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
@@ -1252,15 +1216,6 @@
12521216 "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
12531217 }
12541218 },
1255- "node_modules/agent-base": {
1256- "version": "7.1.3",
1257- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
1258- "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
1259- "license": "MIT",
1260- "engines": {
1261- "node": ">= 14"
1262- }
1263- },
12641219 "node_modules/ajv": {
12651220 "version": "6.12.6",
12661221 "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -1338,41 +1293,6 @@
13381293 "sprintf-js": "~1.0.2"
13391294 }
13401295 },
1341- "node_modules/ast-types": {
1342- "version": "0.13.4",
1343- "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
1344- "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
1345- "license": "MIT",
1346- "dependencies": {
1347- "tslib": "^2.0.1"
1348- },
1349- "engines": {
1350- "node": ">=4"
1351- }
1352- },
1353- "node_modules/asynckit": {
1354- "version": "0.4.0",
1355- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
1356- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
1357- "license": "MIT"
1358- },
1359- "node_modules/axios": {
1360- "version": "1.12.0",
1361- "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.0.tgz",
1362- "integrity": "sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==",
1363- "license": "MIT",
1364- "dependencies": {
1365- "follow-redirects": "^1.15.6",
1366- "form-data": "^4.0.4",
1367- "proxy-from-env": "^1.1.0"
1368- }
1369- },
1370- "node_modules/b4a": {
1371- "version": "1.6.7",
1372- "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
1373- "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==",
1374- "license": "Apache-2.0"
1375- },
13761296 "node_modules/babel-jest": {
13771297 "version": "29.7.0",
13781298 "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
@@ -1486,87 +1406,6 @@
14861406 "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
14871407 "license": "MIT"
14881408 },
1489- "node_modules/bare-events": {
1490- "version": "2.5.4",
1491- "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz",
1492- "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==",
1493- "license": "Apache-2.0",
1494- "optional": true
1495- },
1496- "node_modules/bare-fs": {
1497- "version": "4.1.3",
1498- "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.3.tgz",
1499- "integrity": "sha512-OeEZYIg+2qepaWLyphaOXHAHKo3xkM8y3BeGAvHdMN8GNWvEAU1Yw6rYpGzu/wDDbKxgEjVeVDpgGhDzaeMpjg==",
1500- "license": "Apache-2.0",
1501- "optional": true,
1502- "dependencies": {
1503- "bare-events": "^2.5.4",
1504- "bare-path": "^3.0.0",
1505- "bare-stream": "^2.6.4"
1506- },
1507- "engines": {
1508- "bare": ">=1.16.0"
1509- },
1510- "peerDependencies": {
1511- "bare-buffer": "*"
1512- },
1513- "peerDependenciesMeta": {
1514- "bare-buffer": {
1515- "optional": true
1516- }
1517- }
1518- },
1519- "node_modules/bare-os": {
1520- "version": "3.6.1",
1521- "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz",
1522- "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==",
1523- "license": "Apache-2.0",
1524- "optional": true,
1525- "engines": {
1526- "bare": ">=1.14.0"
1527- }
1528- },
1529- "node_modules/bare-path": {
1530- "version": "3.0.0",
1531- "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
1532- "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
1533- "license": "Apache-2.0",
1534- "optional": true,
1535- "dependencies": {
1536- "bare-os": "^3.0.1"
1537- }
1538- },
1539- "node_modules/bare-stream": {
1540- "version": "2.6.5",
1541- "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz",
1542- "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==",
1543- "license": "Apache-2.0",
1544- "optional": true,
1545- "dependencies": {
1546- "streamx": "^2.21.0"
1547- },
1548- "peerDependencies": {
1549- "bare-buffer": "*",
1550- "bare-events": "*"
1551- },
1552- "peerDependenciesMeta": {
1553- "bare-buffer": {
1554- "optional": true
1555- },
1556- "bare-events": {
1557- "optional": true
1558- }
1559- }
1560- },
1561- "node_modules/basic-ftp": {
1562- "version": "5.0.5",
1563- "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
1564- "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==",
1565- "license": "MIT",
1566- "engines": {
1567- "node": ">=10.0.0"
1568- }
1569- },
15701409 "node_modules/brace-expansion": {
15711410 "version": "1.1.12",
15721411 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
@@ -1631,15 +1470,6 @@
16311470 "node-int64": "^0.4.0"
16321471 }
16331472 },
1634- "node_modules/buffer-crc32": {
1635- "version": "0.2.13",
1636- "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
1637- "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
1638- "license": "MIT",
1639- "engines": {
1640- "node": "*"
1641- }
1642- },
16431473 "node_modules/buffer-from": {
16441474 "version": "1.1.2",
16451475 "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -1709,19 +1539,6 @@
17091539 "node": ">=10"
17101540 }
17111541 },
1712- "node_modules/chromium-bidi": {
1713- "version": "4.1.1",
1714- "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-4.1.1.tgz",
1715- "integrity": "sha512-biR7t4vF3YluE6RlMSk9IWk+b9U+WWyzHp+N2pL9vRTk+UXHYRTVp7jTK58ZNzMLBgoLMHY4QyJMbeuw3eKxqg==",
1716- "license": "Apache-2.0",
1717- "dependencies": {
1718- "mitt": "^3.0.1",
1719- "zod": "^3.24.1"
1720- },
1721- "peerDependencies": {
1722- "devtools-protocol": "*"
1723- }
1724- },
17251542 "node_modules/ci-info": {
17261543 "version": "3.9.0",
17271544 "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
@@ -1803,50 +1620,6 @@
18031620 "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
18041621 "license": "MIT"
18051622 },
1806- "node_modules/cosmiconfig": {
1807- "version": "8.3.6",
1808- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
1809- "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==",
1810- "license": "MIT",
1811- "dependencies": {
1812- "import-fresh": "^3.3.0",
1813- "js-yaml": "^4.1.0",
1814- "parse-json": "^5.2.0",
1815- "path-type": "^4.0.0"
1816- },
1817- "engines": {
1818- "node": ">=14"
1819- },
1820- "funding": {
1821- "url": "https://github.com/sponsors/d-fischer"
1822- },
1823- "peerDependencies": {
1824- "typescript": ">=4.9.5"
1825- },
1826- "peerDependenciesMeta": {
1827- "typescript": {
1828- "optional": true
1829- }
1830- }
1831- },
1832- "node_modules/cosmiconfig/node_modules/argparse": {
1833- "version": "2.0.1",
1834- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
1835- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
1836- "license": "Python-2.0"
1837- },
1838- "node_modules/cosmiconfig/node_modules/js-yaml": {
1839- "version": "4.1.1",
1840- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
1841- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
1842- "license": "MIT",
1843- "dependencies": {
1844- "argparse": "^2.0.1"
1845- },
1846- "bin": {
1847- "js-yaml": "bin/js-yaml.js"
1848- }
1849- },
18501623 "node_modules/create-jest": {
18511624 "version": "29.7.0",
18521625 "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
@@ -1882,28 +1655,6 @@
18821655 "node": ">= 8"
18831656 }
18841657 },
1885- "node_modules/cwd": {
1886- "version": "0.10.0",
1887- "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz",
1888- "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==",
1889- "license": "MIT",
1890- "dependencies": {
1891- "find-pkg": "^0.1.2",
1892- "fs-exists-sync": "^0.1.0"
1893- },
1894- "engines": {
1895- "node": ">=0.8"
1896- }
1897- },
1898- "node_modules/data-uri-to-buffer": {
1899- "version": "6.0.2",
1900- "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
1901- "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
1902- "license": "MIT",
1903- "engines": {
1904- "node": ">= 14"
1905- }
1906- },
19071658 "node_modules/debug": {
19081659 "version": "4.4.0",
19091660 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
@@ -1950,29 +1701,6 @@
19501701 "node": ">=0.10.0"
19511702 }
19521703 },
1953- "node_modules/degenerator": {
1954- "version": "5.0.1",
1955- "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
1956- "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
1957- "license": "MIT",
1958- "dependencies": {
1959- "ast-types": "^0.13.4",
1960- "escodegen": "^2.1.0",
1961- "esprima": "^4.0.1"
1962- },
1963- "engines": {
1964- "node": ">= 14"
1965- }
1966- },
1967- "node_modules/delayed-stream": {
1968- "version": "1.0.0",
1969- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
1970- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
1971- "license": "MIT",
1972- "engines": {
1973- "node": ">=0.4.0"
1974- }
1975- },
19761704 "node_modules/detect-newline": {
19771705 "version": "3.1.0",
19781706 "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -2027,24 +1755,6 @@
20271755 "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
20281756 "license": "MIT"
20291757 },
2030- "node_modules/end-of-stream": {
2031- "version": "1.4.4",
2032- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
2033- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
2034- "license": "MIT",
2035- "dependencies": {
2036- "once": "^1.4.0"
2037- }
2038- },
2039- "node_modules/env-paths": {
2040- "version": "2.2.1",
2041- "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
2042- "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
2043- "license": "MIT",
2044- "engines": {
2045- "node": ">=6"
2046- }
2047- },
20481758 "node_modules/error-ex": {
20491759 "version": "1.3.2",
20501760 "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -2072,27 +1782,6 @@
20721782 "node": ">=8"
20731783 }
20741784 },
2075- "node_modules/escodegen": {
2076- "version": "2.1.0",
2077- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
2078- "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
2079- "license": "BSD-2-Clause",
2080- "dependencies": {
2081- "esprima": "^4.0.1",
2082- "estraverse": "^5.2.0",
2083- "esutils": "^2.0.2"
2084- },
2085- "bin": {
2086- "escodegen": "bin/escodegen.js",
2087- "esgenerate": "bin/esgenerate.js"
2088- },
2089- "engines": {
2090- "node": ">=6.0"
2091- },
2092- "optionalDependencies": {
2093- "source-map": "~0.6.1"
2094- }
2095- },
20961785 "node_modules/eslint": {
20971786 "version": "8.57.0",
20981787 "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
@@ -2399,61 +2088,12 @@
23992088 "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
24002089 }
24012090 },
2402- "node_modules/expect-puppeteer": {
2403- "version": "10.0.0",
2404- "resolved": "https://registry.npmjs.org/expect-puppeteer/-/expect-puppeteer-10.0.0.tgz",
2405- "integrity": "sha512-E7sE6nVdEbrnpDOBMmcLgyqLJKt876AlBg1A+gsu5R8cWx+SLafreOgJAgzXg5Qko7Tk0cW5oZdRbHQLU738dg==",
2406- "engines": {
2407- "node": ">=16"
2408- }
2409- },
2410- "node_modules/extract-zip": {
2411- "version": "2.0.1",
2412- "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
2413- "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
2414- "license": "BSD-2-Clause",
2415- "dependencies": {
2416- "debug": "^4.1.1",
2417- "get-stream": "^5.1.0",
2418- "yauzl": "^2.10.0"
2419- },
2420- "bin": {
2421- "extract-zip": "cli.js"
2422- },
2423- "engines": {
2424- "node": ">= 10.17.0"
2425- },
2426- "optionalDependencies": {
2427- "@types/yauzl": "^2.9.1"
2428- }
2429- },
2430- "node_modules/extract-zip/node_modules/get-stream": {
2431- "version": "5.2.0",
2432- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
2433- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
2434- "license": "MIT",
2435- "dependencies": {
2436- "pump": "^3.0.0"
2437- },
2438- "engines": {
2439- "node": ">=8"
2440- },
2441- "funding": {
2442- "url": "https://github.com/sponsors/sindresorhus"
2443- }
2444- },
24452091 "node_modules/fast-deep-equal": {
24462092 "version": "3.1.3",
24472093 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
24482094 "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
24492095 "license": "MIT"
24502096 },
2451- "node_modules/fast-fifo": {
2452- "version": "1.3.2",
2453- "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
2454- "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
2455- "license": "MIT"
2456- },
24572097 "node_modules/fast-json-stable-stringify": {
24582098 "version": "2.1.0",
24592099 "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -2484,15 +2124,6 @@
24842124 "bser": "2.1.1"
24852125 }
24862126 },
2487- "node_modules/fd-slicer": {
2488- "version": "1.1.0",
2489- "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
2490- "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
2491- "license": "MIT",
2492- "dependencies": {
2493- "pend": "~1.2.0"
2494- }
2495- },
24962127 "node_modules/file-entry-cache": {
24972128 "version": "6.0.1",
24982129 "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -2618,20 +2249,6 @@
26182249 "url": "https://github.com/sponsors/sindresorhus"
26192250 }
26202251 },
2621- "node_modules/get-uri": {
2622- "version": "6.0.4",
2623- "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz",
2624- "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==",
2625- "license": "MIT",
2626- "dependencies": {
2627- "basic-ftp": "^5.0.2",
2628- "data-uri-to-buffer": "^6.0.2",
2629- "debug": "^4.3.4"
2630- },
2631- "engines": {
2632- "node": ">= 14"
2633- }
2634- },
26352252 "node_modules/glob": {
26362253 "version": "7.2.3",
26372254 "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -2713,32 +2330,6 @@
27132330 "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
27142331 "license": "MIT"
27152332 },
2716- "node_modules/http-proxy-agent": {
2717- "version": "7.0.2",
2718- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
2719- "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
2720- "license": "MIT",
2721- "dependencies": {
2722- "agent-base": "^7.1.0",
2723- "debug": "^4.3.4"
2724- },
2725- "engines": {
2726- "node": ">= 14"
2727- }
2728- },
2729- "node_modules/https-proxy-agent": {
2730- "version": "7.0.6",
2731- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
2732- "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
2733- "license": "MIT",
2734- "dependencies": {
2735- "agent-base": "^7.1.2",
2736- "debug": "4"
2737- },
2738- "engines": {
2739- "node": ">= 14"
2740- }
2741- },
27422333 "node_modules/human-signals": {
27432334 "version": "2.1.0",
27442335 "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -2827,31 +2418,6 @@
28272418 "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
28282419 "license": "ISC"
28292420 },
2830- "node_modules/ini": {
2831- "version": "1.3.8",
2832- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
2833- "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
2834- "license": "ISC"
2835- },
2836- "node_modules/ip-address": {
2837- "version": "9.0.5",
2838- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
2839- "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
2840- "license": "MIT",
2841- "dependencies": {
2842- "jsbn": "1.1.0",
2843- "sprintf-js": "^1.1.3"
2844- },
2845- "engines": {
2846- "node": ">= 12"
2847- }
2848- },
2849- "node_modules/ip-address/node_modules/sprintf-js": {
2850- "version": "1.1.3",
2851- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
2852- "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
2853- "license": "BSD-3-Clause"
2854- },
28552421 "node_modules/is-arrayish": {
28562422 "version": "0.2.1",
28572423 "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -3612,12 +3178,6 @@
36123178 "js-yaml": "bin/js-yaml.js"
36133179 }
36143180 },
3615- "node_modules/jsbn": {
3616- "version": "1.1.0",
3617- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
3618- "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
3619- "license": "MIT"
3620- },
36213181 "node_modules/jsesc": {
36223182 "version": "2.5.2",
36233183 "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -3814,21 +3374,6 @@
38143374 "node": "*"
38153375 }
38163376 },
3817- "node_modules/minimist": {
3818- "version": "1.2.8",
3819- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
3820- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
3821- "license": "MIT",
3822- "funding": {
3823- "url": "https://github.com/sponsors/ljharb"
3824- }
3825- },
3826- "node_modules/mitt": {
3827- "version": "3.0.1",
3828- "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
3829- "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
3830- "license": "MIT"
3831- },
38323377 "node_modules/ms": {
38333378 "version": "2.1.3",
38343379 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -3841,15 +3386,6 @@
38413386 "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
38423387 "license": "MIT"
38433388 },
3844- "node_modules/netmask": {
3845- "version": "2.0.2",
3846- "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
3847- "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
3848- "license": "MIT",
3849- "engines": {
3850- "node": ">= 0.4.0"
3851- }
3852- },
38533389 "node_modules/node-int64": {
38543390 "version": "0.4.0",
38553391 "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -3975,38 +3511,6 @@
39753511 "node": ">=6"
39763512 }
39773513 },
3978- "node_modules/pac-proxy-agent": {
3979- "version": "7.2.0",
3980- "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
3981- "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
3982- "license": "MIT",
3983- "dependencies": {
3984- "@tootallnate/quickjs-emscripten": "^0.23.0",
3985- "agent-base": "^7.1.2",
3986- "debug": "^4.3.4",
3987- "get-uri": "^6.0.1",
3988- "http-proxy-agent": "^7.0.0",
3989- "https-proxy-agent": "^7.0.6",
3990- "pac-resolver": "^7.0.1",
3991- "socks-proxy-agent": "^8.0.5"
3992- },
3993- "engines": {
3994- "node": ">= 14"
3995- }
3996- },
3997- "node_modules/pac-resolver": {
3998- "version": "7.0.1",
3999- "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
4000- "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
4001- "license": "MIT",
4002- "dependencies": {
4003- "degenerator": "^5.0.0",
4004- "netmask": "^2.0.2"
4005- },
4006- "engines": {
4007- "node": ">= 14"
4008- }
4009- },
40103514 "node_modules/parent-module": {
40113515 "version": "1.0.1",
40123516 "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -4070,21 +3574,6 @@
40703574 "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
40713575 "license": "MIT"
40723576 },
4073- "node_modules/path-type": {
4074- "version": "4.0.0",
4075- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
4076- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
4077- "license": "MIT",
4078- "engines": {
4079- "node": ">=8"
4080- }
4081- },
4082- "node_modules/pend": {
4083- "version": "1.2.0",
4084- "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
4085- "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
4086- "license": "MIT"
4087- },
40883577 "node_modules/picocolors": {
40893578 "version": "1.0.1",
40903579 "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
@@ -4203,15 +3692,6 @@
42033692 "url": "https://github.com/chalk/ansi-styles?sponsor=1"
42043693 }
42053694 },
4206- "node_modules/progress": {
4207- "version": "2.0.3",
4208- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
4209- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
4210- "license": "MIT",
4211- "engines": {
4212- "node": ">=0.4.0"
4213- }
4214- },
42153695 "node_modules/prompts": {
42163696 "version": "2.4.2",
42173697 "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -4225,50 +3705,6 @@
42253705 "node": ">= 6"
42263706 }
42273707 },
4228- "node_modules/proxy-agent": {
4229- "version": "6.5.0",
4230- "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
4231- "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
4232- "license": "MIT",
4233- "dependencies": {
4234- "agent-base": "^7.1.2",
4235- "debug": "^4.3.4",
4236- "http-proxy-agent": "^7.0.1",
4237- "https-proxy-agent": "^7.0.6",
4238- "lru-cache": "^7.14.1",
4239- "pac-proxy-agent": "^7.1.0",
4240- "proxy-from-env": "^1.1.0",
4241- "socks-proxy-agent": "^8.0.5"
4242- },
4243- "engines": {
4244- "node": ">= 14"
4245- }
4246- },
4247- "node_modules/proxy-agent/node_modules/lru-cache": {
4248- "version": "7.18.3",
4249- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
4250- "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
4251- "license": "ISC",
4252- "engines": {
4253- "node": ">=12"
4254- }
4255- },
4256- "node_modules/proxy-from-env": {
4257- "version": "1.1.0",
4258- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
4259- "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
4260- "license": "MIT"
4261- },
4262- "node_modules/pump": {
4263- "version": "3.0.2",
4264- "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
4265- "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
4266- "license": "MIT",
4267- "dependencies": {
4268- "end-of-stream": "^1.1.0",
4269- "once": "^1.3.1"
4270- }
4271- },
42723708 "node_modules/punycode": {
42733709 "version": "2.3.1",
42743710 "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -4278,88 +3714,6 @@
42783714 "node": ">=6"
42793715 }
42803716 },
4281- "node_modules/puppeteer": {
4282- "version": "24.7.2",
4283- "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.7.2.tgz",
4284- "integrity": "sha512-ifYqoY6wGs0yZeFuFPn8BE9FhuveXkarF+eO18I2e/axdoCh4Qh1AE+qXdJBhdaeoPt6eRNTY4Dih29Jbq8wow==",
4285- "hasInstallScript": true,
4286- "license": "Apache-2.0",
4287- "dependencies": {
4288- "@puppeteer/browsers": "2.10.2",
4289- "chromium-bidi": "4.1.1",
4290- "cosmiconfig": "^9.0.0",
4291- "devtools-protocol": "0.0.1425554",
4292- "puppeteer-core": "24.7.2",
4293- "typed-query-selector": "^2.12.0"
4294- },
4295- "bin": {
4296- "puppeteer": "lib/cjs/puppeteer/node/cli.js"
4297- },
4298- "engines": {
4299- "node": ">=18"
4300- }
4301- },
4302- "node_modules/puppeteer-core": {
4303- "version": "24.7.2",
4304- "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.7.2.tgz",
4305- "integrity": "sha512-P9pZyTmJqKODFCnkZgemCpoFA4LbAa8+NumHVQKyP5X9IgdNS1ZnAnIh1sMAwhF8/xEUGf7jt+qmNLlKieFw1Q==",
4306- "license": "Apache-2.0",
4307- "dependencies": {
4308- "@puppeteer/browsers": "2.10.2",
4309- "chromium-bidi": "4.1.1",
4310- "debug": "^4.4.0",
4311- "devtools-protocol": "0.0.1425554",
4312- "typed-query-selector": "^2.12.0",
4313- "ws": "^8.18.1"
4314- },
4315- "engines": {
4316- "node": ">=18"
4317- }
4318- },
4319- "node_modules/puppeteer/node_modules/argparse": {
4320- "version": "2.0.1",
4321- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
4322- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
4323- "license": "Python-2.0"
4324- },
4325- "node_modules/puppeteer/node_modules/cosmiconfig": {
4326- "version": "9.0.0",
4327- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
4328- "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
4329- "license": "MIT",
4330- "dependencies": {
4331- "env-paths": "^2.2.1",
4332- "import-fresh": "^3.3.0",
4333- "js-yaml": "^4.1.0",
4334- "parse-json": "^5.2.0"
4335- },
4336- "engines": {
4337- "node": ">=14"
4338- },
4339- "funding": {
4340- "url": "https://github.com/sponsors/d-fischer"
4341- },
4342- "peerDependencies": {
4343- "typescript": ">=4.9.5"
4344- },
4345- "peerDependenciesMeta": {
4346- "typescript": {
4347- "optional": true
4348- }
4349- }
4350- },
4351- "node_modules/puppeteer/node_modules/js-yaml": {
4352- "version": "4.1.1",
4353- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
4354- "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
4355- "license": "MIT",
4356- "dependencies": {
4357- "argparse": "^2.0.1"
4358- },
4359- "bin": {
4360- "js-yaml": "bin/js-yaml.js"
4361- }
4362- },
43633717 "node_modules/pure-rand": {
43643718 "version": "6.1.0",
43653719 "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
@@ -4558,44 +3912,6 @@
45583912 "node": ">=8"
45593913 }
45603914 },
4561- "node_modules/smart-buffer": {
4562- "version": "4.2.0",
4563- "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
4564- "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
4565- "license": "MIT",
4566- "engines": {
4567- "node": ">= 6.0.0",
4568- "npm": ">= 3.0.0"
4569- }
4570- },
4571- "node_modules/socks": {
4572- "version": "2.8.4",
4573- "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
4574- "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
4575- "license": "MIT",
4576- "dependencies": {
4577- "ip-address": "^9.0.5",
4578- "smart-buffer": "^4.2.0"
4579- },
4580- "engines": {
4581- "node": ">= 10.0.0",
4582- "npm": ">= 3.0.0"
4583- }
4584- },
4585- "node_modules/socks-proxy-agent": {
4586- "version": "8.0.5",
4587- "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
4588- "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
4589- "license": "MIT",
4590- "dependencies": {
4591- "agent-base": "^7.1.2",
4592- "debug": "^4.3.4",
4593- "socks": "^2.8.3"
4594- },
4595- "engines": {
4596- "node": ">= 14"
4597- }
4598- },
45993915 "node_modules/source-map": {
46003916 "version": "0.6.1",
46013917 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -4633,19 +3949,6 @@
46333949 "node": ">=10"
46343950 }
46353951 },
4636- "node_modules/streamx": {
4637- "version": "2.22.0",
4638- "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz",
4639- "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==",
4640- "license": "MIT",
4641- "dependencies": {
4642- "fast-fifo": "^1.3.2",
4643- "text-decoder": "^1.1.0"
4644- },
4645- "optionalDependencies": {
4646- "bare-events": "^2.2.0"
4647- }
4648- },
46493952 "node_modules/string-length": {
46503953 "version": "4.0.2",
46513954 "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@@ -4739,31 +4042,6 @@
47394042 "url": "https://github.com/sponsors/ljharb"
47404043 }
47414044 },
4742- "node_modules/tar-fs": {
4743- "version": "3.1.1",
4744- "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz",
4745- "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==",
4746- "license": "MIT",
4747- "dependencies": {
4748- "pump": "^3.0.0",
4749- "tar-stream": "^3.1.5"
4750- },
4751- "optionalDependencies": {
4752- "bare-fs": "^4.0.1",
4753- "bare-path": "^3.0.0"
4754- }
4755- },
4756- "node_modules/tar-stream": {
4757- "version": "3.1.7",
4758- "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
4759- "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
4760- "license": "MIT",
4761- "dependencies": {
4762- "b4a": "^1.6.4",
4763- "fast-fifo": "^1.2.0",
4764- "streamx": "^2.15.0"
4765- }
4766- },
47674045 "node_modules/test-exclude": {
47684046 "version": "6.0.0",
47694047 "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
@@ -4778,15 +4056,6 @@
47784056 "node": ">=8"
47794057 }
47804058 },
4781- "node_modules/text-decoder": {
4782- "version": "1.2.3",
4783- "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz",
4784- "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==",
4785- "license": "Apache-2.0",
4786- "dependencies": {
4787- "b4a": "^1.6.4"
4788- }
4789- },
47904059 "node_modules/text-table": {
47914060 "version": "0.2.0",
47924061 "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -4844,12 +4113,6 @@
48444113 "url": "https://github.com/sponsors/sindresorhus"
48454114 }
48464115 },
4847- "node_modules/typed-query-selector": {
4848- "version": "2.12.0",
4849- "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz",
4850- "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==",
4851- "license": "MIT"
4852- },
48534116 "node_modules/undici-types": {
48544117 "version": "5.26.5",
48554118 "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
@@ -4978,27 +4241,6 @@
49784241 "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
49794242 }
49804243 },
4981- "node_modules/ws": {
4982- "version": "8.18.1",
4983- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
4984- "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
4985- "license": "MIT",
4986- "engines": {
4987- "node": ">=10.0.0"
4988- },
4989- "peerDependencies": {
4990- "bufferutil": "^4.0.1",
4991- "utf-8-validate": ">=5.0.2"
4992- },
4993- "peerDependenciesMeta": {
4994- "bufferutil": {
4995- "optional": true
4996- },
4997- "utf-8-validate": {
4998- "optional": true
4999- }
5000- }
5001- },
50024244 "node_modules/y18n": {
50034245 "version": "5.0.8",
50044246 "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -5041,16 +4283,6 @@
50414283 "node": ">=12"
50424284 }
50434285 },
5044- "node_modules/yauzl": {
5045- "version": "2.10.0",
5046- "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
5047- "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
5048- "license": "MIT",
5049- "dependencies": {
5050- "buffer-crc32": "~0.2.3",
5051- "fd-slicer": "~1.1.0"
5052- }
5053- },
50544286 "node_modules/yocto-queue": {
50554287 "version": "0.1.0",
50564288 "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -5062,15 +4294,6 @@
50624294 "funding": {
50634295 "url": "https://github.com/sponsors/sindresorhus"
50644296 }
5065- },
5066- "node_modules/zod": {
5067- "version": "3.24.3",
5068- "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz",
5069- "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==",
5070- "license": "MIT",
5071- "funding": {
5072- "url": "https://github.com/sponsors/colinhacks"
5073- }
50744297 }
50754298 }
50764299}