diff --git a/packages/desktop-client/src/components/Notifications.js b/packages/desktop-client/src/components/Notifications.js
index a795454c4312b8246b28483a3ba8ee5ccc033c7b..9ded51a92834656c07ce0e393b9d2e11eebfd3a8 100644
--- a/packages/desktop-client/src/components/Notifications.js
+++ b/packages/desktop-client/src/components/Notifications.js
@@ -65,7 +65,7 @@ function compileMessage(message, actions, setLoading, onRemove) {
 }
 
 function Notification({ notification, onRemove }) {
-  let { type, title, message, messageActions, sticky, internal, button } =
+  let { type, title, message, pre, messageActions, sticky, internal, button } =
     notification;
 
   let [loading, setLoading] = useState(false);
@@ -121,6 +121,23 @@ function Notification({ notification, onRemove }) {
             <View style={{ fontWeight: 700, marginBottom: 10 }}>{title}</View>
           )}
           <View>{processedMessage}</View>
+          {pre
+            ? pre.split('\n\n').map((text, idx) => (
+                <View
+                  key={idx}
+                  style={{
+                    whiteSpace: 'pre-wrap',
+                    fontFamily: 'monospace',
+                    fontSize: 12,
+                    backgroundColor: 'rgba(0, 0, 0, .05)',
+                    padding: 10,
+                    borderRadius: 4,
+                  }}
+                >
+                  {text}
+                </View>
+              ))
+            : null}
           {button && (
             <ButtonWithLoading
               bare
diff --git a/packages/loot-core/jest.config.js b/packages/loot-core/jest.config.js
index a00e1a2a6f9bf59563048ba12f4a2e2f81c0d137..e9e723ddf5cd49be2f5fa9d86fc9f2e2af1d3391 100644
--- a/packages/loot-core/jest.config.js
+++ b/packages/loot-core/jest.config.js
@@ -4,13 +4,16 @@ module.exports = {
     'mjs',
     'js',
     'ts',
-    'json'
+    'json',
   ]),
   setupFilesAfterEnv: ['<rootDir>/src/mocks/setup.js'],
   testEnvironment: 'node',
   testPathIgnorePatterns: ['/node_modules/', '/lib/', '.+/index.web.test.js'],
   transformIgnorePatterns: ['/node_modules/', '__mocks__'],
   globals: {
-    __TESTING__: true
-  }
+    __TESTING__: true,
+  },
+  transform: {
+    '\\.pegjs$': 'pegjs-jest-transformer',
+  },
 };
diff --git a/packages/loot-core/jest.web.config.js b/packages/loot-core/jest.web.config.js
index 84b38b628b17570b7cd3731040507b35cb2471d6..d994d5f91ba01ee6a4a4233078f504e928e202b2 100644
--- a/packages/loot-core/jest.web.config.js
+++ b/packages/loot-core/jest.web.config.js
@@ -6,9 +6,12 @@ module.exports = {
   testMatch: ['**/*.web.test.js'],
   transformIgnorePatterns: [
     '__mocks__',
-    '/node_modules/(?!perf-deets|absurd-sql)'
+    '/node_modules/(?!perf-deets|absurd-sql)',
   ],
   globals: {
-    __TESTING__: true
-  }
+    __TESTING__: true,
+  },
+  transform: {
+    '\\.pegjs$': 'pegjs-jest-transformer',
+  },
 };
diff --git a/packages/loot-core/package.json b/packages/loot-core/package.json
index 3db5160b57508c6863f066c6047a00f1b565bab6..68c1f2df66eb85afa8fb138186236adf57f8f2dd 100644
--- a/packages/loot-core/package.json
+++ b/packages/loot-core/package.json
@@ -41,6 +41,7 @@
     "@actual-app/import-ynab4": "*",
     "@babel/core": "~7.14.3",
     "@types/jest": "^27.5.0",
+    "@types/webpack": "^5.28.0",
     "adm-zip": "^0.5.9",
     "babel-loader": "^8.0.6",
     "buffer": "^5.5.0",
@@ -62,6 +63,9 @@
     "mockdate": "^3.0.5",
     "murmurhash": "^0.0.2",
     "npm-run-all": "^4.1.3",
+    "pegjs": "^0.10.0",
+    "pegjs-jest-transformer": "^1.2.3",
+    "pegjs-loader": "^0.5.6",
     "perf-deets": "^1.0.15",
     "sanitize-filename": "^1.6.1",
     "search-query-parser": "^1.3.0",
diff --git a/packages/loot-core/src/client/actions/queries.js b/packages/loot-core/src/client/actions/queries.js
index e1c4e9f3388e29c1e9f009d8027e3321e22be2e9..e52c06c1c69aa0c0a108e233b9dc8de08e79450d 100644
--- a/packages/loot-core/src/client/actions/queries.js
+++ b/packages/loot-core/src/client/actions/queries.js
@@ -7,7 +7,7 @@ import { pushModal } from './modals';
 import { addNotification, addGenericErrorNotification } from './notifications';
 
 export function applyBudgetAction(month, type, args) {
-  return async function () {
+  return async function (dispatch) {
     switch (type) {
       case 'budget-amount':
         await send('budget/budget-amount', {
@@ -26,10 +26,16 @@ export function applyBudgetAction(month, type, args) {
         await send('budget/set-3month-avg', { month });
         break;
       case 'apply-goal-template':
-        await send('budget/apply-goal-template', { month });
+        dispatch(
+          addNotification(await send('budget/apply-goal-template', { month })),
+        );
         break;
       case 'overwrite-goal-template':
-        await send('budget/overwrite-goal-template', { month });
+        dispatch(
+          addNotification(
+            await send('budget/overwrite-goal-template', { month }),
+          ),
+        );
         break;
       case 'hold':
         await send('budget/hold-for-next-month', {
diff --git a/packages/loot-core/src/server/budget/goal-template.pegjs b/packages/loot-core/src/server/budget/goal-template.pegjs
new file mode 100644
index 0000000000000000000000000000000000000000..78127a04ec34e936160430173446ba836912be82
--- /dev/null
+++ b/packages/loot-core/src/server/budget/goal-template.pegjs
@@ -0,0 +1,52 @@
+// https://pegjs.org
+
+expr
+  = percent: percent _ of _ category: $([^\n] *)
+    { return { type: 'percentage', percent: +percent, category } }
+  / amount: amount _ repeatEvery _ weeks: weekCount _ starting _ starting: date limit: limit?
+    { return { type: 'week', amount, weeks, starting, limit } }
+  / amount: amount _ by _ month: month from: spendFrom? repeat: (_ repeatEvery _ repeat)?
+    { return {
+      type: from ? 'spend' : 'by',
+      amount,
+      month,
+      ...(repeat ? repeat[3] : {}),
+      from
+    } }
+  / monthly: amount limit: limit?
+    { return { type: 'simple', monthly, limit } }
+  / upTo _ limit: amount
+    { return { type: 'simple', limit } }
+
+repeat 'repeat interval'
+  = 'month' { return { annual: false } }
+  / months: d _ 'months' { return { annual: false, repeat: +months } }
+  / 'year' { return { annual: true } }
+  / years: d _ 'years' { return { annual: true, repeat: +years } }
+
+limit = _ upTo? _ amount: amount { return amount }
+
+weekCount
+  = week { return null }
+  / n: number _ weeks { return +n }
+
+spendFrom = _ 'spend' _ 'from' _ month: month { return month }
+
+week = 'week'
+weeks = 'weeks'
+by = 'by'
+of = 'of'
+repeatEvery = 'repeat' _ 'every'
+starting = 'starting'
+upTo = 'up' _ 'to'
+
+_ 'space' = ' '+
+d 'digit' = [0-9]
+number 'number' = $(d+)
+amount 'amount' = currencySymbol? _? amount: $(d+ ('.' d d)?) { return +amount }
+percent 'percentage' = percent: $(d+) _? '%' { return +percent }
+year 'year' = $(d d d d)
+month 'month' = $(year '-' d d)
+day 'day' = $(d d)
+date = $(month '-' day)
+currencySymbol 'currency symbol' = symbol: . & { return /\p{Sc}/u.test(symbol) }
diff --git a/packages/loot-core/src/server/budget/goaltemplates.js b/packages/loot-core/src/server/budget/goaltemplates.js
index f78751fad78161fed9cd5ff6a7144ba49b6af8bc..b699a97d79d36727c5ccb526496855a166279dc6 100644
--- a/packages/loot-core/src/server/budget/goaltemplates.js
+++ b/packages/loot-core/src/server/budget/goaltemplates.js
@@ -10,17 +10,19 @@ import { amountToInteger, integerToAmount } from '../../shared/util';
 import * as db from '../db';
 
 import { setBudget, getSheetValue } from './actions';
+import { parse } from './goal-template.pegjs';
 
-export async function applyTemplate({ month }) {
-  await processTemplate(month, false);
+export function applyTemplate({ month }) {
+  return processTemplate(month, false);
 }
 
-export async function overwriteTemplate({ month }) {
-  await processTemplate(month, true);
+export function overwriteTemplate({ month }) {
+  return processTemplate(month, true);
 }
 
 async function processTemplate(month, force) {
   let category_templates = await getCategoryTemplates();
+  let errors = [];
 
   let categories = await db.all(
     'SELECT * FROM v_categories WHERE tombstone = 0',
@@ -39,6 +41,19 @@ async function processTemplate(month, force) {
       let template = category_templates[category.id];
 
       if (template) {
+        errors = errors.concat(
+          template
+            .filter(t => t.type === 'error')
+            .map(({ line, error }) =>
+              [
+                category.name + ': ' + error.message,
+                line,
+                ' '.repeat(
+                  TEMPLATE_PREFIX.length + error.location.start.offset,
+                ) + '^',
+              ].join('\n'),
+            ),
+        );
         let to_budget = await applyCategoryTemplate(
           category,
           template,
@@ -53,120 +68,56 @@ async function processTemplate(month, force) {
     }
   }
   if (num_applied === 0) {
-    console.log('All categories were up to date.');
+    if (errors.length) {
+      return {
+        type: 'error',
+        sticky: true,
+        message: `There were errors interpreting some templates:`,
+        pre: errors.join('\n\n'),
+      };
+    } else {
+      return { type: 'message', message: 'All categories were up to date.' };
+    }
   } else {
-    console.log(`${num_applied} categories updated.`);
+    let applied = `Successfully applied templates to ${num_applied} ${
+      num_applied === 1 ? 'category' : 'categories'
+    }.`;
+    if (errors.length) {
+      return {
+        sticky: true,
+        message: `${applied} There were errors interpreting some templates:`,
+        pre: errors.join('\n\n'),
+      };
+    } else {
+      return {
+        type: 'message',
+        message: applied,
+      };
+    }
   }
 }
 
-async function getCategoryTemplates() {
-  const matches = [
-    {
-      type: 'simple',
-        re: /^#template \$?(\-?\d+(\.\d{2})?)$/im,//eslint-disable-line
-      params: ['monthly'],
-    },
-    {
-      type: 'simple',
-      re: /^#template up to \$?(\d+(\.\d{2})?)$/im,
-      params: ['limit'],
-    },
-    {
-      type: 'simple',
-      re: /^#template \$?(\d+(\.\d{2})?) up to \$?(\d+(\.\d{2})?)$/im,
-      params: ['monthly', null, 'limit'],
-    },
-    {
-      type: 'by',
-        re: /^#template \$?(\d+(\.\d{2})?) by (\d{4}\-\d{2})$/im,//eslint-disable-line
-      params: ['amount', null, 'month'],
-    },
-    {
-      type: 'by',
-        re: /^#template \$?(\d+(\.\d{2})?) by (\d{4}\-\d{2}) repeat every (\d+) months$/im,//eslint-disable-line
-      params: ['amount', null, 'month', 'repeat'],
-    },
-    {
-      type: 'week',
-        re: /^#template \$?(\d+(\.\d{2})?) repeat every week starting (\d{4}\-\d{2}\-\d{2})$/im,//eslint-disable-line
-      params: ['amount', null, 'starting'],
-    },
-    {
-      type: 'week',
-        re: /^#template \$?(\d+(\.\d{2})?) repeat every week starting (\d{4}\-\d{2}\-\d{2}) up to \$?(\d+(\.\d{2})?)$/im,//eslint-disable-line
-      params: ['amount', null, 'starting', 'limit'],
-    },
-    {
-      type: 'weeks',
-        re: /^#template \$?(\d+(\.\d{2})?) repeat every (\d+) weeks starting (\d{4}\-\d{2}\-\d{2})$/im,//eslint-disable-line
-      params: ['amount', null, 'weeks', 'starting'],
-    },
-    {
-      type: 'weeks',
-        re: /^#template \$?(\d+(\.\d{2})?) repeat every (\d+) weeks starting (\d{4}\-\d{2}\-\d{2}) up to \$?(\d+(\.\d{2})?)$/im,//eslint-disable-line
-      params: ['amount', null, 'weeks', 'starting', 'limit'],
-    },
-    {
-      type: 'by_annual',
-        re: /^#template \$?(\d+(\.\d{2})?) by (\d{4}\-\d{2}) repeat every year$/im,//eslint-disable-line
-      params: ['amount', null, 'month'],
-    },
-    {
-      type: 'by_annual',
-        re: /^#template \$?(\d+(\.\d{2})?) by (\d{4}\-\d{2}) repeat every (\d+) years$/im,//eslint-disable-line
-      params: ['amount', null, 'month', 'repeat'],
-    },
-    {
-      type: 'spend',
-        re: /^#template \$?(\d+(\.\d{2})?) by (\d{4}\-\d{2}) spend from (\d{4}\-\d{2})$/im,//eslint-disable-line
-      params: ['amount', null, 'month', 'from'],
-    },
-    {
-      type: 'spend',
-        re: /^#template \$?(\d+(\.\d{2})?) by (\d{4}\-\d{2}) spend from (\d{4}\-\d{2}) repeat every (\d+) months$/im,//eslint-disable-line
-      params: ['amount', null, 'month', 'from', 'repeat'],
-    },
-    {
-      type: 'spend_annual',
-        re: /^#template \$?(\d+(\.\d{2})?) by (\d{4}\-\d{2}) spend from (\d{4}\-\d{2}) repeat every year$/im,//eslint-disable-line
-      params: ['amount', null, 'month', 'from'],
-    },
-    {
-      type: 'spend_annual',
-        re: /^#template \$?(\d+(\.\d{2})?) by (\d{4}\-\d{2}) spend from (\d{4}\-\d{2}) repeat every (\d+) years$/im,//eslint-disable-line
-      params: ['amount', null, 'month', 'from', 'repeat'],
-    },
-    {
-      type: 'percentage',
-      re: /^#template (\d+(\.\d+)?)% of (.*)$/im,
-      params: ['percent', null, 'category'],
-    },
-    { type: 'error', re: /^#template .*$/im, params: [] },
-  ];
+const TEMPLATE_PREFIX = '#template ';
 
+async function getCategoryTemplates() {
   let templates = {};
 
-  let notes = await db.all(`SELECT * FROM notes WHERE note like '%#template%'`);
+  let notes = await db.all(
+    `SELECT * FROM notes WHERE lower(note) like '%${TEMPLATE_PREFIX}%'`,
+  );
 
   for (let n = 0; n < notes.length; n++) {
     let lines = notes[n].note.split('\n');
     let template_lines = [];
     for (let l = 0; l < lines.length; l++) {
-      for (let m = 0; m < matches.length; m++) {
-        let arr = matches[m].re.exec(lines[l]);
-        if (arr) {
-          let matched = {};
-          matched.line = arr[0];
-          matched.type = matches[m].type;
-          for (let p = 0; p < matches[m].params.length; p++) {
-            let param_name = matches[m].params[p];
-            if (param_name) {
-              matched[param_name] = arr[p + 1];
-            }
-          }
-          template_lines.push(matched);
-          break;
-        }
+      let line = lines[l].trim();
+      if (!line.toLowerCase().startsWith(TEMPLATE_PREFIX)) continue;
+      let expression = line.slice(TEMPLATE_PREFIX.length);
+      try {
+        let parsed = parse(expression);
+        template_lines.push(parsed);
+      } catch (e) {
+        template_lines.push({ type: 'error', line, error: e });
       }
     }
     if (template_lines.length) {
@@ -186,20 +137,18 @@ async function applyCategoryTemplate(category, template_lines, month, force) {
 
     switch (template.type) {
       case 'by':
-      case 'by_annual':
       case 'spend':
-      case 'spend_annual':
         let target_month = new Date(`${template.month}-01`);
         let num_months = differenceInCalendarMonths(
           target_month,
           current_month,
         );
-        let repeat = template.type.includes('annual')
+        let repeat = template.annual
           ? (template.repeat || 1) * 12
           : template.repeat;
 
         let spend_from;
-        if (template.type.includes('spend')) {
+        if (template.type === 'spend') {
           spend_from = new Date(`${template.from}-01`);
         }
         while (num_months < 0 && repeat) {
@@ -230,10 +179,7 @@ async function applyCategoryTemplate(category, template_lines, month, force) {
   if (template_lines.length > 1) {
     template_lines = template_lines
       .sort((a, b) => {
-        if (
-          a.type.slice(0, 2) === b.type.slice(0, 2) &&
-          a.type.slice(0, 2) === 'by'
-        ) {
+        if (a.type === 'by' && !a.annual) {
           return differenceInCalendarMonths(
             new Date(`${a.month}-01`),
             new Date(`${b.month}-01`),
@@ -243,7 +189,7 @@ async function applyCategoryTemplate(category, template_lines, month, force) {
         }
       })
       .filter(el => {
-        if (el.type.slice(0, 2) === 'by') {
+        if (el.type === 'by') {
           if (!got_by) {
             got_by = true;
             return el;
@@ -288,8 +234,7 @@ async function applyCategoryTemplate(category, template_lines, month, force) {
         }
         break;
       }
-      case 'by':
-      case 'by_annual': {
+      case 'by': {
         // by has 'amount' and 'month' params
         let target_month = new Date(`${template.month}-01`);
         let target = amountToInteger(template.amount);
@@ -311,10 +256,8 @@ async function applyCategoryTemplate(category, template_lines, month, force) {
         }
         break;
       }
-      case 'week':
-      case 'weeks': {
-        // weeks has 'amount', 'starting' and optional 'limit' params
-        // weeks has 'amount', 'starting', 'weeks' and optional 'limit' params
+      case 'week': {
+        // week has 'amount', 'starting', 'weeks' and optional 'limit' params
         let amount = amountToInteger(template.amount);
         let weeks = template.weeks != null ? Math.round(template.weeks) : 1;
         if (template.limit != null) {
@@ -341,8 +284,7 @@ async function applyCategoryTemplate(category, template_lines, month, force) {
         }
         break;
       }
-      case 'spend':
-      case 'spend_annual': {
+      case 'spend': {
         // spend has 'amount' and 'from' and 'month' params
         let from_month = new Date(`${template.from}-01`);
         let to_month = new Date(`${template.month}-01`);
@@ -409,7 +351,6 @@ async function applyCategoryTemplate(category, template_lines, month, force) {
         break;
       }
       case 'error':
-        console.log(`${category.name}: ${`Failed to match:`} ${template.line}`);
         return null;
       default:
     }
diff --git a/packages/loot-core/webpack/webpack.browser.config.js b/packages/loot-core/webpack/webpack.browser.config.js
index cf21287e67bf2e76bd374be89e63986327faf3a8..33340b9f9577669b2494f2bcf87dd85850a078d8 100644
--- a/packages/loot-core/webpack/webpack.browser.config.js
+++ b/packages/loot-core/webpack/webpack.browser.config.js
@@ -1,6 +1,8 @@
 let path = require('path');
+
 let webpack = require('webpack');
 
+/** @type {webpack.Configuration} */
 module.exports = {
   mode: process.env.NODE_ENV === 'development' ? 'development' : 'production',
   entry: path.join(__dirname, '../src/server/main.js'),
@@ -9,7 +11,7 @@ module.exports = {
   output: {
     path: path.resolve(path.join(__dirname, '/../lib-dist/browser')),
     library: 'backend',
-    publicPath: '/kcab/'
+    publicPath: '/kcab/',
   },
   resolve: {
     extensions: ['.web.js', '.js', '.json'],
@@ -20,8 +22,13 @@ module.exports = {
       'perf-deets':
         process.env.NODE_ENV === 'development' || process.env.PERF_BUILD
           ? 'perf-deets'
-          : require.resolve('perf-deets/noop')
-    }
+          : require.resolve('perf-deets/noop'),
+    },
+  },
+  resolveLoader: {
+    alias: {
+      'pegjs-loader': require.resolve('pegjs-loader'),
+    },
   },
   module: {
     rules: [
@@ -30,37 +37,41 @@ module.exports = {
         use: {
           loader: 'babel-loader',
           options: {
-            presets: ['babel-preset-jwl-app']
-          }
-        }
-      }
-    ]
+            presets: ['babel-preset-jwl-app'],
+          },
+        },
+      },
+      {
+        test: /\.pegjs$/,
+        use: { loader: 'pegjs-loader' },
+      },
+    ],
   },
   optimization: {
-    namedChunks: true
+    namedChunks: true,
   },
   plugins: [
     new webpack.DefinePlugin({
       'process.env.IS_DEV': JSON.stringify(
-        process.env.NODE_ENV === 'development'
+        process.env.NODE_ENV === 'development',
       ),
       'process.env.IS_BETA': JSON.stringify(
-        process.env.ACTUAL_RELEASE_TYPE === 'beta'
+        process.env.ACTUAL_RELEASE_TYPE === 'beta',
       ),
       'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL || '/'),
       'process.env.ACTUAL_DATA_DIR': JSON.stringify('/'),
-      'process.env.ACTUAL_DOCUMENT_DIR': JSON.stringify('/documents')
+      'process.env.ACTUAL_DOCUMENT_DIR': JSON.stringify('/documents'),
     }),
     new webpack.SourceMapDevToolPlugin({
       filename: '[file].map',
-      exclude: /xfo.kcab/
+      exclude: /xfo.kcab/,
     }),
     new webpack.IgnorePlugin({
-      resourceRegExp: /worker_threads|original-fs/
-    })
+      resourceRegExp: /worker_threads|original-fs/,
+    }),
   ],
   node: {
-    dgram: "empty",
+    dgram: 'empty',
     net: 'empty',
     tls: 'empty',
   },
diff --git a/packages/loot-core/webpack/webpack.desktop.config.js b/packages/loot-core/webpack/webpack.desktop.config.js
index 56ae2f2e7f122d90782606477dbf97e756de4eeb..433df753c71886823e4d07694cc55684216fe91b 100644
--- a/packages/loot-core/webpack/webpack.desktop.config.js
+++ b/packages/loot-core/webpack/webpack.desktop.config.js
@@ -1,51 +1,40 @@
 let path = require('path');
+
 let webpack = require('webpack');
 
+let browser = require('./webpack.browser.config');
+
+/** @type {webpack.Configuration} */
 module.exports = {
-  mode: process.env.NODE_ENV === 'development' ? 'development' : 'production',
+  ...browser,
   target: 'node',
-  entry: path.join(__dirname, '../src/server/main.js'),
-  context: path.resolve(__dirname, '../../..'),
   devtool: 'source-map',
   output: {
     path: path.resolve(path.join(__dirname, '/../lib-dist')),
     filename: 'bundle.desktop.js',
     sourceMapFilename: 'bundle.desktop.js.map',
-    libraryTarget: 'commonjs2'
+    libraryTarget: 'commonjs2',
   },
   resolve: {
     extensions: ['.electron.js', '.js', '.json'],
     alias: {
-      'perf-deets': require.resolve('perf-deets/noop')
-    }
+      'perf-deets': require.resolve('perf-deets/noop'),
+    },
   },
   externals: [
     'better-sqlite3',
     'node-ipc',
     'electron-log',
     'node-fetch',
-    'node-libofx'
+    'node-libofx',
   ],
-  module: {
-    rules: [
-      {
-        test: /\.m?js$/,
-        use: {
-          loader: 'babel-loader',
-          options: {
-            presets: ['babel-preset-jwl-app']
-          }
-        }
-      }
-    ]
-  },
   plugins: [
     new webpack.IgnorePlugin({
-      resourceRegExp: /original-fs/
-    })
+      resourceRegExp: /original-fs/,
+    }),
   ],
   node: {
     __dirname: false,
-    __filename: false
-  }
+    __filename: false,
+  },
 };
diff --git a/yarn.lock b/yarn.lock
index a85e1901bf017c6f68be8e166b1a0bbb6cc0e937..f198b549824912c1cb988bc26ccdd18939149752 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3024,7 +3024,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@jridgewell/gen-mapping@npm:^0.3.2":
+"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2":
   version: 0.3.2
   resolution: "@jridgewell/gen-mapping@npm:0.3.2"
   dependencies:
@@ -3056,6 +3056,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@jridgewell/source-map@npm:^0.3.2":
+  version: 0.3.2
+  resolution: "@jridgewell/source-map@npm:0.3.2"
+  dependencies:
+    "@jridgewell/gen-mapping": ^0.3.0
+    "@jridgewell/trace-mapping": ^0.3.9
+  checksum: 1b83f0eb944e77b70559a394d5d3b3f98a81fcc186946aceb3ef42d036762b52ef71493c6c0a3b7c1d2f08785f53ba2df1277fe629a06e6109588ff4cdcf7482
+  languageName: node
+  linkType: hard
+
 "@jridgewell/sourcemap-codec@npm:1.4.14":
   version: 1.4.14
   resolution: "@jridgewell/sourcemap-codec@npm:1.4.14"
@@ -3100,7 +3110,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.9":
+"@jridgewell/trace-mapping@npm:^0.3.14, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.9":
   version: 0.3.17
   resolution: "@jridgewell/trace-mapping@npm:0.3.17"
   dependencies:
@@ -4341,6 +4351,40 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/eslint-scope@npm:^3.7.3":
+  version: 3.7.4
+  resolution: "@types/eslint-scope@npm:3.7.4"
+  dependencies:
+    "@types/eslint": "*"
+    "@types/estree": "*"
+  checksum: ea6a9363e92f301cd3888194469f9ec9d0021fe0a397a97a6dd689e7545c75de0bd2153dfb13d3ab532853a278b6572c6f678ce846980669e41029d205653460
+  languageName: node
+  linkType: hard
+
+"@types/eslint@npm:*":
+  version: 8.4.10
+  resolution: "@types/eslint@npm:8.4.10"
+  dependencies:
+    "@types/estree": "*"
+    "@types/json-schema": "*"
+  checksum: 21e009ed9ed9bc8920fdafc6e11ff321c4538b4cc18a56fdd59dc5184ea7bbf363c71638c9bdb59fc1254dddcdd567485136ed68b0ee4750948d4e32cb79c689
+  languageName: node
+  linkType: hard
+
+"@types/estree@npm:*":
+  version: 1.0.0
+  resolution: "@types/estree@npm:1.0.0"
+  checksum: 910d97fb7092c6738d30a7430ae4786a38542023c6302b95d46f49420b797f21619cdde11fa92b338366268795884111c2eb10356e4bd2c8ad5b92941e9e6443
+  languageName: node
+  linkType: hard
+
+"@types/estree@npm:^0.0.51":
+  version: 0.0.51
+  resolution: "@types/estree@npm:0.0.51"
+  checksum: e56a3bcf759fd9185e992e7fdb3c6a5f81e8ff120e871641607581fb3728d16c811702a7d40fa5f869b7f7b4437ab6a87eb8d98ffafeee51e85bbe955932a189
+  languageName: node
+  linkType: hard
+
 "@types/fs-extra@npm:^9.0.7":
   version: 9.0.13
   resolution: "@types/fs-extra@npm:9.0.13"
@@ -4458,7 +4502,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8":
+"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8":
   version: 7.0.11
   resolution: "@types/json-schema@npm:7.0.11"
   checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d
@@ -4668,6 +4712,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/webpack@npm:^5.28.0":
+  version: 5.28.0
+  resolution: "@types/webpack@npm:5.28.0"
+  dependencies:
+    "@types/node": "*"
+    tapable: ^2.2.0
+    webpack: ^5
+  checksum: a038d7e12dd109c6a8d2eb744fd32070ef94f1655e730fb1443b370db98864c3a0e408638b02d12ba08269b9c012b3be8b801117ced2d1102e7676203fd663ed
+  languageName: node
+  linkType: hard
+
 "@types/yargs-parser@npm:*":
   version: 21.0.0
   resolution: "@types/yargs-parser@npm:21.0.0"
@@ -4711,6 +4766,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/ast@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/ast@npm:1.11.1"
+  dependencies:
+    "@webassemblyjs/helper-numbers": 1.11.1
+    "@webassemblyjs/helper-wasm-bytecode": 1.11.1
+  checksum: 1eee1534adebeece635362f8e834ae03e389281972611408d64be7895fc49f48f98fddbbb5339bf8a72cb101bcb066e8bca3ca1bf1ef47dadf89def0395a8d87
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/ast@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/ast@npm:1.7.6"
@@ -4734,6 +4799,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/floating-point-hex-parser@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.11.1"
+  checksum: b8efc6fa08e4787b7f8e682182d84dfdf8da9d9c77cae5d293818bc4a55c1f419a87fa265ab85252b3e6c1fd323d799efea68d825d341a7c365c64bc14750e97
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/floating-point-hex-parser@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.7.6"
@@ -4748,6 +4820,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/helper-api-error@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/helper-api-error@npm:1.11.1"
+  checksum: 0792813f0ed4a0e5ee0750e8b5d0c631f08e927f4bdfdd9fe9105dc410c786850b8c61bff7f9f515fdfb149903bec3c976a1310573a4c6866a94d49bc7271959
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/helper-api-error@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/helper-api-error@npm:1.7.6"
@@ -4762,6 +4841,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/helper-buffer@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/helper-buffer@npm:1.11.1"
+  checksum: a337ee44b45590c3a30db5a8b7b68a717526cf967ada9f10253995294dbd70a58b2da2165222e0b9830cd4fc6e4c833bf441a721128d1fe2e9a7ab26b36003ce
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/helper-buffer@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/helper-buffer@npm:1.7.6"
@@ -4826,6 +4912,24 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/helper-numbers@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/helper-numbers@npm:1.11.1"
+  dependencies:
+    "@webassemblyjs/floating-point-hex-parser": 1.11.1
+    "@webassemblyjs/helper-api-error": 1.11.1
+    "@xtuc/long": 4.2.2
+  checksum: 44d2905dac2f14d1e9b5765cf1063a0fa3d57295c6d8930f6c59a36462afecc6e763e8a110b97b342a0f13376166c5d41aa928e6ced92e2f06b071fd0db59d3a
+  languageName: node
+  linkType: hard
+
+"@webassemblyjs/helper-wasm-bytecode@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.11.1"
+  checksum: eac400113127832c88f5826bcc3ad1c0db9b3dbd4c51a723cfdb16af6bfcbceb608170fdaac0ab7731a7e18b291be7af68a47fcdb41cfe0260c10857e7413d97
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/helper-wasm-bytecode@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.7.6"
@@ -4840,6 +4944,18 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/helper-wasm-section@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/helper-wasm-section@npm:1.11.1"
+  dependencies:
+    "@webassemblyjs/ast": 1.11.1
+    "@webassemblyjs/helper-buffer": 1.11.1
+    "@webassemblyjs/helper-wasm-bytecode": 1.11.1
+    "@webassemblyjs/wasm-gen": 1.11.1
+  checksum: 617696cfe8ecaf0532763162aaf748eb69096fb27950219bb87686c6b2e66e11cd0614d95d319d0ab1904bc14ebe4e29068b12c3e7c5e020281379741fe4bedf
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/helper-wasm-section@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/helper-wasm-section@npm:1.7.6"
@@ -4864,6 +4980,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/ieee754@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/ieee754@npm:1.11.1"
+  dependencies:
+    "@xtuc/ieee754": ^1.2.0
+  checksum: 23a0ac02a50f244471631802798a816524df17e56b1ef929f0c73e3cde70eaf105a24130105c60aff9d64a24ce3b640dad443d6f86e5967f922943a7115022ec
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/ieee754@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/ieee754@npm:1.7.6"
@@ -4882,6 +5007,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/leb128@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/leb128@npm:1.11.1"
+  dependencies:
+    "@xtuc/long": 4.2.2
+  checksum: 33ccc4ade2f24de07bf31690844d0b1ad224304ee2062b0e464a610b0209c79e0b3009ac190efe0e6bd568b0d1578d7c3047fc1f9d0197c92fc061f56224ff4a
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/leb128@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/leb128@npm:1.7.6"
@@ -4900,6 +5034,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/utf8@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/utf8@npm:1.11.1"
+  checksum: 972c5cfc769d7af79313a6bfb96517253a270a4bf0c33ba486aa43cac43917184fb35e51dfc9e6b5601548cd5931479a42e42c89a13bb591ffabebf30c8a6a0b
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/utf8@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/utf8@npm:1.7.6"
@@ -4914,6 +5055,22 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/wasm-edit@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/wasm-edit@npm:1.11.1"
+  dependencies:
+    "@webassemblyjs/ast": 1.11.1
+    "@webassemblyjs/helper-buffer": 1.11.1
+    "@webassemblyjs/helper-wasm-bytecode": 1.11.1
+    "@webassemblyjs/helper-wasm-section": 1.11.1
+    "@webassemblyjs/wasm-gen": 1.11.1
+    "@webassemblyjs/wasm-opt": 1.11.1
+    "@webassemblyjs/wasm-parser": 1.11.1
+    "@webassemblyjs/wast-printer": 1.11.1
+  checksum: 6d7d9efaec1227e7ef7585a5d7ff0be5f329f7c1c6b6c0e906b18ed2e9a28792a5635e450aca2d136770d0207225f204eff70a4b8fd879d3ac79e1dcc26dbeb9
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/wasm-edit@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/wasm-edit@npm:1.7.6"
@@ -4946,6 +5103,19 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/wasm-gen@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/wasm-gen@npm:1.11.1"
+  dependencies:
+    "@webassemblyjs/ast": 1.11.1
+    "@webassemblyjs/helper-wasm-bytecode": 1.11.1
+    "@webassemblyjs/ieee754": 1.11.1
+    "@webassemblyjs/leb128": 1.11.1
+    "@webassemblyjs/utf8": 1.11.1
+  checksum: 1f6921e640293bf99fb16b21e09acb59b340a79f986c8f979853a0ae9f0b58557534b81e02ea2b4ef11e929d946708533fd0693c7f3712924128fdafd6465f5b
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/wasm-gen@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/wasm-gen@npm:1.7.6"
@@ -4972,6 +5142,18 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/wasm-opt@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/wasm-opt@npm:1.11.1"
+  dependencies:
+    "@webassemblyjs/ast": 1.11.1
+    "@webassemblyjs/helper-buffer": 1.11.1
+    "@webassemblyjs/wasm-gen": 1.11.1
+    "@webassemblyjs/wasm-parser": 1.11.1
+  checksum: 21586883a20009e2b20feb67bdc451bbc6942252e038aae4c3a08e6f67b6bae0f5f88f20bfc7bd0452db5000bacaf5ab42b98cf9aa034a6c70e9fc616142e1db
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/wasm-opt@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/wasm-opt@npm:1.7.6"
@@ -4996,6 +5178,20 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/wasm-parser@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/wasm-parser@npm:1.11.1"
+  dependencies:
+    "@webassemblyjs/ast": 1.11.1
+    "@webassemblyjs/helper-api-error": 1.11.1
+    "@webassemblyjs/helper-wasm-bytecode": 1.11.1
+    "@webassemblyjs/ieee754": 1.11.1
+    "@webassemblyjs/leb128": 1.11.1
+    "@webassemblyjs/utf8": 1.11.1
+  checksum: 1521644065c360e7b27fad9f4bb2df1802d134dd62937fa1f601a1975cde56bc31a57b6e26408b9ee0228626ff3ba1131ae6f74ffb7d718415b6528c5a6dbfc2
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/wasm-parser@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/wasm-parser@npm:1.7.6"
@@ -5053,6 +5249,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@webassemblyjs/wast-printer@npm:1.11.1":
+  version: 1.11.1
+  resolution: "@webassemblyjs/wast-printer@npm:1.11.1"
+  dependencies:
+    "@webassemblyjs/ast": 1.11.1
+    "@xtuc/long": 4.2.2
+  checksum: f15ae4c2441b979a3b4fce78f3d83472fb22350c6dc3fd34bfe7c3da108e0b2360718734d961bba20e7716cb8578e964b870da55b035e209e50ec9db0378a3f7
+  languageName: node
+  linkType: hard
+
 "@webassemblyjs/wast-printer@npm:1.7.6":
   version: 1.7.6
   resolution: "@webassemblyjs/wast-printer@npm:1.7.6"
@@ -5193,6 +5399,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"acorn-import-assertions@npm:^1.7.6":
+  version: 1.8.0
+  resolution: "acorn-import-assertions@npm:1.8.0"
+  peerDependencies:
+    acorn: ^8
+  checksum: 5c4cf7c850102ba7ae0eeae0deb40fb3158c8ca5ff15c0bca43b5c47e307a1de3d8ef761788f881343680ea374631ae9e9615ba8876fee5268dbe068c98bcba6
+  languageName: node
+  linkType: hard
+
 "acorn-jsx@npm:^5.0.0":
   version: 5.3.2
   resolution: "acorn-jsx@npm:5.3.2"
@@ -5261,6 +5476,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"acorn@npm:^8.7.1":
+  version: 8.8.2
+  resolution: "acorn@npm:8.8.2"
+  bin:
+    acorn: bin/acorn
+  checksum: f790b99a1bf63ef160c967e23c46feea7787e531292bb827126334612c234ed489a0dc2c7ba33156416f0ffa8d25bf2b0fdb7f35c2ba60eb3e960572bece4001
+  languageName: node
+  linkType: hard
+
 "actual@workspace:.":
   version: 0.0.0-use.local
   resolution: "actual@workspace:."
@@ -6414,6 +6638,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"big.js@npm:^3.1.3":
+  version: 3.2.0
+  resolution: "big.js@npm:3.2.0"
+  checksum: 299449e40555625a308f01d74378677036b2ec98b30aaa89794b3afbd4eaa104b7456a989affadfd7f630dc14b3f1df250de9bddc4a6fc664e60727887bb33e7
+  languageName: node
+  linkType: hard
+
 "big.js@npm:^5.2.2":
   version: 5.2.2
   resolution: "big.js@npm:5.2.2"
@@ -6727,31 +6958,31 @@ __metadata:
   languageName: node
   linkType: hard
 
-"browserslist@npm:^4.18.1":
-  version: 4.21.3
-  resolution: "browserslist@npm:4.21.3"
+"browserslist@npm:^4.14.5, browserslist@npm:^4.21.3, browserslist@npm:^4.21.4":
+  version: 4.21.4
+  resolution: "browserslist@npm:4.21.4"
   dependencies:
-    caniuse-lite: ^1.0.30001370
-    electron-to-chromium: ^1.4.202
+    caniuse-lite: ^1.0.30001400
+    electron-to-chromium: ^1.4.251
     node-releases: ^2.0.6
-    update-browserslist-db: ^1.0.5
+    update-browserslist-db: ^1.0.9
   bin:
     browserslist: cli.js
-  checksum: ff512a7bcca1c530e2854bbdfc7be2791d0fb524097a6340e56e1d5924164c7e4e0a9b070de04cdc4c149d15cb4d4275cb7c626ebbce954278a2823aaad2452a
+  checksum: 4af3793704dbb4615bcd29059ab472344dc7961c8680aa6c4bb84f05340e14038d06a5aead58724eae69455b8fade8b8c69f1638016e87e5578969d74c078b79
   languageName: node
   linkType: hard
 
-"browserslist@npm:^4.21.3, browserslist@npm:^4.21.4":
-  version: 4.21.4
-  resolution: "browserslist@npm:4.21.4"
+"browserslist@npm:^4.18.1":
+  version: 4.21.3
+  resolution: "browserslist@npm:4.21.3"
   dependencies:
-    caniuse-lite: ^1.0.30001400
-    electron-to-chromium: ^1.4.251
+    caniuse-lite: ^1.0.30001370
+    electron-to-chromium: ^1.4.202
     node-releases: ^2.0.6
-    update-browserslist-db: ^1.0.9
+    update-browserslist-db: ^1.0.5
   bin:
     browserslist: cli.js
-  checksum: 4af3793704dbb4615bcd29059ab472344dc7961c8680aa6c4bb84f05340e14038d06a5aead58724eae69455b8fade8b8c69f1638016e87e5578969d74c078b79
+  checksum: ff512a7bcca1c530e2854bbdfc7be2791d0fb524097a6340e56e1d5924164c7e4e0a9b070de04cdc4c149d15cb4d4275cb7c626ebbce954278a2823aaad2452a
   languageName: node
   linkType: hard
 
@@ -9938,6 +10169,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"emojis-list@npm:^2.0.0":
+  version: 2.1.0
+  resolution: "emojis-list@npm:2.1.0"
+  checksum: fb61fa6356dfcc9fbe6db8e334c29da365a34d3d82a915cb59621883d3023d804fd5edad5acd42b8eec016936e81d3b38e2faf921b32e073758374253afe1272
+  languageName: node
+  linkType: hard
+
 "emojis-list@npm:^3.0.0":
   version: 3.0.0
   resolution: "emojis-list@npm:3.0.0"
@@ -9981,6 +10219,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"enhanced-resolve@npm:^5.10.0":
+  version: 5.12.0
+  resolution: "enhanced-resolve@npm:5.12.0"
+  dependencies:
+    graceful-fs: ^4.2.4
+    tapable: ^2.2.0
+  checksum: bf3f787facaf4ce3439bef59d148646344e372bef5557f0d37ea8aa02c51f50a925cd1f07b8d338f18992c29f544ec235a8c64bcdb56030196c48832a5494174
+  languageName: node
+  linkType: hard
+
 "entities@npm:^2.0.0":
   version: 2.2.0
   resolution: "entities@npm:2.2.0"
@@ -10173,6 +10421,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"es-module-lexer@npm:^0.9.0":
+  version: 0.9.3
+  resolution: "es-module-lexer@npm:0.9.3"
+  checksum: 84bbab23c396281db2c906c766af58b1ae2a1a2599844a504df10b9e8dc77ec800b3211fdaa133ff700f5703d791198807bba25d9667392d27a5e9feda344da8
+  languageName: node
+  linkType: hard
+
 "es-set-tostringtag@npm:^2.0.1":
   version: 2.0.1
   resolution: "es-set-tostringtag@npm:2.0.1"
@@ -10465,6 +10720,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"eslint-scope@npm:5.1.1":
+  version: 5.1.1
+  resolution: "eslint-scope@npm:5.1.1"
+  dependencies:
+    esrecurse: ^4.3.0
+    estraverse: ^4.1.1
+  checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb
+  languageName: node
+  linkType: hard
+
 "eslint-scope@npm:^4.0.0, eslint-scope@npm:^4.0.3":
   version: 4.0.3
   resolution: "eslint-scope@npm:4.0.3"
@@ -10576,7 +10841,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"esrecurse@npm:^4.1.0":
+"esrecurse@npm:^4.1.0, esrecurse@npm:^4.3.0":
   version: 4.3.0
   resolution: "esrecurse@npm:4.3.0"
   dependencies:
@@ -10644,7 +10909,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"events@npm:^3.0.0":
+"events@npm:^3.0.0, events@npm:^3.2.0":
   version: 3.3.0
   resolution: "events@npm:3.3.0"
   checksum: f6f487ad2198aa41d878fa31452f1a3c00958f46e9019286ff4787c84aac329332ab45c9cdc8c445928fc6d7ded294b9e005a7fce9426488518017831b272780
@@ -11956,6 +12221,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"glob-to-regexp@npm:^0.4.1":
+  version: 0.4.1
+  resolution: "glob-to-regexp@npm:0.4.1"
+  checksum: e795f4e8f06d2a15e86f76e4d92751cf8bbfcf0157cea5c2f0f35678a8195a750b34096b1256e436f0cebc1883b5ff0888c47348443e69546a5a87f9e1eb1167
+  languageName: node
+  linkType: hard
+
 "glob@npm:^7.0.0, glob@npm:^7.0.3, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6":
   version: 7.2.0
   resolution: "glob@npm:7.2.0"
@@ -14736,6 +15008,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"jest-worker@npm:^27.4.5":
+  version: 27.5.1
+  resolution: "jest-worker@npm:27.5.1"
+  dependencies:
+    "@types/node": "*"
+    merge-stream: ^2.0.0
+    supports-color: ^8.0.0
+  checksum: 98cd68b696781caed61c983a3ee30bf880b5bd021c01d98f47b143d4362b85d0737f8523761e2713d45e18b4f9a2b98af1eaee77afade4111bb65c77d6f7c980
+  languageName: node
+  linkType: hard
+
 "jest-worker@npm:^28.1.3":
   version: 28.1.3
   resolution: "jest-worker@npm:28.1.3"
@@ -14959,7 +15242,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"json-parse-even-better-errors@npm:^2.3.0":
+"json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1":
   version: 2.3.1
   resolution: "json-parse-even-better-errors@npm:2.3.1"
   checksum: 798ed4cf3354a2d9ccd78e86d2169515a0097a5c133337807cdf7f1fc32e1391d207ccfc276518cc1d7d8d4db93288b8a50ba4293d212ad1336e52a8ec0a941f
@@ -15010,6 +15293,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"json5@npm:^0.5.0":
+  version: 0.5.1
+  resolution: "json5@npm:0.5.1"
+  bin:
+    json5: lib/cli.js
+  checksum: 9b85bf06955b23eaa4b7328aa8892e3887e81ca731dd27af04a5f5f1458fbc5e1de57a24442e3272f8a888dd1abe1cb68eb693324035f6b3aeba4fcab7667d62
+  languageName: node
+  linkType: hard
+
 "json5@npm:^1.0.1":
   version: 1.0.1
   resolution: "json5@npm:1.0.1"
@@ -15330,6 +15622,25 @@ __metadata:
   languageName: node
   linkType: hard
 
+"loader-runner@npm:^4.2.0":
+  version: 4.3.0
+  resolution: "loader-runner@npm:4.3.0"
+  checksum: a90e00dee9a16be118ea43fec3192d0b491fe03a32ed48a4132eb61d498f5536a03a1315531c19d284392a8726a4ecad71d82044c28d7f22ef62e029bf761569
+  languageName: node
+  linkType: hard
+
+"loader-utils@npm:^0.2.5":
+  version: 0.2.17
+  resolution: "loader-utils@npm:0.2.17"
+  dependencies:
+    big.js: ^3.1.3
+    emojis-list: ^2.0.0
+    json5: ^0.5.0
+    object-assign: ^4.0.1
+  checksum: 3045c83ef8b19d66d4c25e3245120c579883f473fe0d0559552f55502be913725c4d558a7c866191a74b19ef2af20b094afe3b144ae1e717ea4c245d52f60a09
+  languageName: node
+  linkType: hard
+
 "loader-utils@npm:^1.0.1, loader-utils@npm:^1.0.2, loader-utils@npm:^1.1.0, loader-utils@npm:^1.2.3, loader-utils@npm:^1.4.0":
   version: 1.4.0
   resolution: "loader-utils@npm:1.4.0"
@@ -15585,6 +15896,7 @@ __metadata:
     "@rschedule/json-tools": ^1.2.0
     "@rschedule/standard-date-adapter": ^1.2.0
     "@types/jest": ^27.5.0
+    "@types/webpack": ^5.28.0
     absurd-sql: 0.0.53
     adm-zip: ^0.5.9
     babel-loader: ^8.0.6
@@ -15617,6 +15929,9 @@ __metadata:
     node-fetch: ^2.6.9
     node-libofx: "*"
     npm-run-all: ^4.1.3
+    pegjs: ^0.10.0
+    pegjs-jest-transformer: ^1.2.3
+    pegjs-loader: ^0.5.6
     perf-deets: ^1.0.15
     regenerator-runtime: ^0.13.7
     sanitize-filename: ^1.6.1
@@ -16907,7 +17222,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"neo-async@npm:^2.5.0, neo-async@npm:^2.6.1":
+"neo-async@npm:^2.5.0, neo-async@npm:^2.6.1, neo-async@npm:^2.6.2":
   version: 2.6.2
   resolution: "neo-async@npm:2.6.2"
   checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9
@@ -18167,6 +18482,39 @@ __metadata:
   languageName: node
   linkType: hard
 
+"pegjs-jest-transformer@npm:^1.2.3":
+  version: 1.2.3
+  resolution: "pegjs-jest-transformer@npm:1.2.3"
+  dependencies:
+    typescript: ">=4.5 <5.0"
+  peerDependencies:
+    jest: ^29.0.0
+    pegjs: ^0.10.0
+  checksum: 2af4d48e6162fda8a0ed98b8c02780727e0528dee5af5c6dd1261945d155943f55cd7e58791419991b88759bb9d89e57e0fec5ec96177cef0e24bd508b6b0eae
+  languageName: node
+  linkType: hard
+
+"pegjs-loader@npm:^0.5.6":
+  version: 0.5.6
+  resolution: "pegjs-loader@npm:0.5.6"
+  dependencies:
+    loader-utils: ^0.2.5
+  peerDependencies:
+    pegjs: ^0.10.0
+    webpack: ">=1"
+  checksum: 26f7a1a49c05cc61bb619e0158da18416e3574729be4fda4af366000f0a264743b692f87273415f73651c9bf20b9306e43822b7a7053103a1fdeca27cead003d
+  languageName: node
+  linkType: hard
+
+"pegjs@npm:^0.10.0":
+  version: 0.10.0
+  resolution: "pegjs@npm:0.10.0"
+  bin:
+    pegjs: bin/pegjs
+  checksum: 65d184ca0e1823ec0a3e7f384d7fd771bcbbc7abf460c82c9704022c1fa325425dc9007c92982b951879c3c9d4c39bf5cd6d99690e0540ff5016c04ca1ecd17e
+  languageName: node
+  linkType: hard
+
 "pend@npm:~1.2.0":
   version: 1.2.0
   resolution: "pend@npm:1.2.0"
@@ -21148,7 +21496,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"schema-utils@npm:^3.0.0":
+"schema-utils@npm:^3.0.0, schema-utils@npm:^3.1.0, schema-utils@npm:^3.1.1":
   version: 3.1.1
   resolution: "schema-utils@npm:3.1.1"
   dependencies:
@@ -21328,6 +21676,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"serialize-javascript@npm:^6.0.0":
+  version: 6.0.1
+  resolution: "serialize-javascript@npm:6.0.1"
+  dependencies:
+    randombytes: ^2.1.0
+  checksum: 3c4f4cb61d0893b988415bdb67243637333f3f574e9e9cc9a006a2ced0b390b0b3b44aef8d51c951272a9002ec50885eefdc0298891bc27eb2fe7510ea87dc4f
+  languageName: node
+  linkType: hard
+
 "serve-index@npm:^1.9.1":
   version: 1.9.1
   resolution: "serve-index@npm:1.9.1"
@@ -21761,7 +22118,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.19, source-map-support@npm:^0.5.21, source-map-support@npm:~0.5.10, source-map-support@npm:~0.5.12":
+"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.19, source-map-support@npm:^0.5.21, source-map-support@npm:~0.5.10, source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.20":
   version: 0.5.21
   resolution: "source-map-support@npm:0.5.21"
   dependencies:
@@ -22465,6 +22822,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"tapable@npm:^2.1.1, tapable@npm:^2.2.0":
+  version: 2.2.1
+  resolution: "tapable@npm:2.2.1"
+  checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51
+  languageName: node
+  linkType: hard
+
 "tar-fs@npm:^2.0.0":
   version: 2.1.1
   resolution: "tar-fs@npm:2.1.1"
@@ -22588,6 +22952,28 @@ __metadata:
   languageName: node
   linkType: hard
 
+"terser-webpack-plugin@npm:^5.1.3":
+  version: 5.3.6
+  resolution: "terser-webpack-plugin@npm:5.3.6"
+  dependencies:
+    "@jridgewell/trace-mapping": ^0.3.14
+    jest-worker: ^27.4.5
+    schema-utils: ^3.1.1
+    serialize-javascript: ^6.0.0
+    terser: ^5.14.1
+  peerDependencies:
+    webpack: ^5.1.0
+  peerDependenciesMeta:
+    "@swc/core":
+      optional: true
+    esbuild:
+      optional: true
+    uglify-js:
+      optional: true
+  checksum: 8f3448d7fdb0434ce6a0c09d95c462bfd2f4a5a430233d854163337f734a7f5c07c74513d16081e06d4ca33d366d5b1a36f5444219bc41a7403afd6162107bad
+  languageName: node
+  linkType: hard
+
 "terser@npm:^3.8.1":
   version: 3.17.0
   resolution: "terser@npm:3.17.0"
@@ -22614,6 +23000,20 @@ __metadata:
   languageName: node
   linkType: hard
 
+"terser@npm:^5.14.1":
+  version: 5.16.1
+  resolution: "terser@npm:5.16.1"
+  dependencies:
+    "@jridgewell/source-map": ^0.3.2
+    acorn: ^8.5.0
+    commander: ^2.20.0
+    source-map-support: ~0.5.20
+  bin:
+    terser: bin/terser
+  checksum: cb524123504a2f0d9140c1e1a8628c83bba9cacc404c6aca79e2493a38dfdf21275617ba75b91006b3f1ff586e401ab31121160cd253699f334c6340ea2756f5
+  languageName: node
+  linkType: hard
+
 "test-exclude@npm:^6.0.0":
   version: 6.0.0
   resolution: "test-exclude@npm:6.0.0"
@@ -23115,6 +23515,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"typescript@npm:>=4.5 <5.0":
+  version: 4.9.4
+  resolution: "typescript@npm:4.9.4"
+  bin:
+    tsc: bin/tsc
+    tsserver: bin/tsserver
+  checksum: e782fb9e0031cb258a80000f6c13530288c6d63f1177ed43f770533fdc15740d271554cdae86701c1dd2c83b082cea808b07e97fd68b38a172a83dbf9e0d0ef9
+  languageName: node
+  linkType: hard
+
 "typescript@npm:^4.6.4":
   version: 4.7.4
   resolution: "typescript@npm:4.7.4"
@@ -23125,6 +23535,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"typescript@patch:typescript@>=4.5 <5.0#~builtin<compat/typescript>":
+  version: 4.9.4
+  resolution: "typescript@patch:typescript@npm%3A4.9.4#~builtin<compat/typescript>::version=4.9.4&hash=bda367"
+  bin:
+    tsc: bin/tsc
+    tsserver: bin/tsserver
+  checksum: 37f6e2c3c5e2aa5934b85b0fddbf32eeac8b1bacf3a5b51d01946936d03f5377fe86255d4e5a4ae628fd0cd553386355ad362c57f13b4635064400f3e8e05b9d
+  languageName: node
+  linkType: hard
+
 "typescript@patch:typescript@^4.6.4#~builtin<compat/typescript>":
   version: 4.7.4
   resolution: "typescript@patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=bda367"
@@ -24233,6 +24653,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"watchpack@npm:^2.4.0":
+  version: 2.4.0
+  resolution: "watchpack@npm:2.4.0"
+  dependencies:
+    glob-to-regexp: ^0.4.1
+    graceful-fs: ^4.1.2
+  checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131
+  languageName: node
+  linkType: hard
+
 "wbuf@npm:^1.1.0, wbuf@npm:^1.7.3":
   version: 1.7.3
   resolution: "wbuf@npm:1.7.3"
@@ -24398,6 +24828,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"webpack-sources@npm:^3.2.3":
+  version: 3.2.3
+  resolution: "webpack-sources@npm:3.2.3"
+  checksum: 989e401b9fe3536529e2a99dac8c1bdc50e3a0a2c8669cbafad31271eadd994bc9405f88a3039cd2e29db5e6d9d0926ceb7a1a4e7409ece021fe79c37d9c4607
+  languageName: node
+  linkType: hard
+
 "webpack@npm:4.19.1":
   version: 4.19.1
   resolution: "webpack@npm:4.19.1"
@@ -24470,6 +24907,43 @@ __metadata:
   languageName: node
   linkType: hard
 
+"webpack@npm:^5":
+  version: 5.75.0
+  resolution: "webpack@npm:5.75.0"
+  dependencies:
+    "@types/eslint-scope": ^3.7.3
+    "@types/estree": ^0.0.51
+    "@webassemblyjs/ast": 1.11.1
+    "@webassemblyjs/wasm-edit": 1.11.1
+    "@webassemblyjs/wasm-parser": 1.11.1
+    acorn: ^8.7.1
+    acorn-import-assertions: ^1.7.6
+    browserslist: ^4.14.5
+    chrome-trace-event: ^1.0.2
+    enhanced-resolve: ^5.10.0
+    es-module-lexer: ^0.9.0
+    eslint-scope: 5.1.1
+    events: ^3.2.0
+    glob-to-regexp: ^0.4.1
+    graceful-fs: ^4.2.9
+    json-parse-even-better-errors: ^2.3.1
+    loader-runner: ^4.2.0
+    mime-types: ^2.1.27
+    neo-async: ^2.6.2
+    schema-utils: ^3.1.0
+    tapable: ^2.1.1
+    terser-webpack-plugin: ^5.1.3
+    watchpack: ^2.4.0
+    webpack-sources: ^3.2.3
+  peerDependenciesMeta:
+    webpack-cli:
+      optional: true
+  bin:
+    webpack: bin/webpack.js
+  checksum: 2bcc5f3c195f375944e8af2f00bf2feea39cb9fda5f763b0d1b00077f1c51783db25c94d3fae96a07dead9fa085e6ae7474417e5ab31719c9776ea5969ceb83a
+  languageName: node
+  linkType: hard
+
 "websocket-driver@npm:0.6.5":
   version: 0.6.5
   resolution: "websocket-driver@npm:0.6.5"