From 5c79f75ab90fea9e3fdf93f894049349e6f1f8c4 Mon Sep 17 00:00:00 2001 From: blakekrammes Date: Fri, 28 Mar 2025 15:57:42 -0500 Subject: [PATCH] FIO-9618: Move email rendering to core processors * FIO-9618: implement email rendering with jsdom * FIO-9618: Add email rendering for edit grid tagpad - move all dom insertion to renderEmailUtils - todo: nested edit grids, etc * FIO-9618: Fix pathing for nested grid-table components - Clean up other logic * FIO-9618: Add typing for email rendering via core processor - Use core Evaluator string interpolation for address formatting * FIO-9618: Fix datetime timezone handling - Handle empty values corectly for various components * FIO-9618: Use updated core version * FIO-9618: Handle wizards and doubly+ nested forms correctly * FIO-9618: Fix problems with nested grids and forms ** The initial commit was authored by Brendan, the rest and majority of code by Blake Co-authored-by: Brendan Bond --- .prettierrc | 3 +- package.json | 146 ++++++------ src/core/renderEmail.ts | 395 ++++++++++++++++++++++++++------- src/core/renderEmailUtils.ts | 411 ++++++++++++++++++++++++++++++++++ yarn.lock | 416 ++++++++++++++++++++++++++++++++++- 5 files changed, 1211 insertions(+), 160 deletions(-) create mode 100644 src/core/renderEmailUtils.ts diff --git a/.prettierrc b/.prettierrc index d64d227..f2e9973 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,4 @@ { - "tabWidth": 4, "singleQuote": true, - "bracketSpacing": true + "printWidth": 100 } diff --git a/package.json b/package.json index bf84f45..6ff2c41 100644 --- a/package.json +++ b/package.json @@ -1,75 +1,77 @@ { - "name": "@formio/vm", - "version": "1.0.0-dev.5", - "main": "build/index.js", - "license": "OSL-3.0", - "engines": { - "node": ">=20.0.0" - }, - "files": [ - "build", - "package.json", - "yarn.lock", - "README.md", - "LICENSE.txt" + "name": "@formio/vm", + "version": "1.0.0-dev.5", + "main": "build/index.js", + "license": "OSL-3.0", + "engines": { + "node": ">=20.0.0" + }, + "files": [ + "build", + "package.json", + "yarn.lock", + "README.md", + "LICENSE.txt" + ], + "dependencies": { + "@formio/core": "2.4.0-dev.235.b497e17", + "@formio/js": "5.1.0-dev.6043.03460d9", + "debug": "^4.3.4", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "inputmask": "^5.0.9", + "isolated-vm": "^4.6.0", + "jsdom": "^26.0.0", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.43", + "nunjucks": "^3.2.4", + "nunjucks-date-filter": "^0.1.1" + }, + "scripts": { + "preinstall": "npx check-node-version --node \">=20.0.0\"", + "test": "npm run build && mocha -r ts-node/register -b -t 0 --no-node-snapshot 'build/**/__tests__/*.test.js'", + "start": "DOTENV_CONFIG_PATH=./.env node --no-node-snapshot build/server.js", + "build": "gulp prebuild && tsc && gulp postbuild", + "prepack": "npm run build && gulp remove-tests", + "prepare": "husky install", + "lint": "eslint ." + }, + "devDependencies": { + "@types/chai": "^4.3.11", + "@types/debug": "^4.1.10", + "@types/express": "^4.17.20", + "@types/jsdom": "^21.1.7", + "@types/lodash": "^4.14.200", + "@types/method-override": "^0.0.35", + "@types/mocha": "^10.0.6", + "@types/node": "^20.8.9", + "@types/nunjucks": "^3.2.6", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "chai": "^4.3.10", + "del": "^7.1.0", + "eslint": ">=7.0.0", + "eslint-config-prettier": "^9.1.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0", + "gulp": "^4.0.2", + "husky": ">=6", + "lint-staged": ">=10", + "mocha": "^10.2.0", + "nodemon": "^3.0.1", + "prettier": "^3.1.0", + "ts-node": "^10.9.1", + "tsc": "^2.0.4", + "typescript": "^5.2.2" + }, + "lint-staged": { + "*.ts": [ + "eslint --fix", + "prettier --write" ], - "dependencies": { - "@formio/core": "2.4.0-dev.221.e0c6673", - "@formio/js": "5.1.0-dev.6043.03460d9", - "debug": "^4.3.4", - "dotenv": "^16.3.1", - "express": "^4.18.2", - "inputmask": "^5.0.9", - "isolated-vm": "^4.6.0", - "lodash": "^4.17.21", - "moment": "^2.29.4", - "moment-timezone": "^0.5.43", - "nunjucks": "^3.2.4", - "nunjucks-date-filter": "^0.1.1" - }, - "scripts": { - "preinstall": "npx check-node-version --node \">=20.0.0\"", - "test": "npm run build && mocha -r ts-node/register -b -t 0 --no-node-snapshot 'build/**/__tests__/*.test.js'", - "start": "DOTENV_CONFIG_PATH=./.env node --no-node-snapshot build/server.js", - "build": "gulp prebuild && tsc && gulp postbuild", - "prepack": "npm run build && gulp remove-tests", - "prepare": "husky install", - "lint": "eslint ." - }, - "devDependencies": { - "@types/chai": "^4.3.11", - "@types/debug": "^4.1.10", - "@types/express": "^4.17.20", - "@types/lodash": "^4.14.200", - "@types/method-override": "^0.0.35", - "@types/mocha": "^10.0.6", - "@types/node": "^20.8.9", - "@types/nunjucks": "^3.2.6", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", - "chai": "^4.3.10", - "del": "^7.1.0", - "eslint": ">=7.0.0", - "eslint-config-prettier": "^9.1.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0", - "gulp": "^4.0.2", - "husky": ">=6", - "lint-staged": ">=10", - "mocha": "^10.2.0", - "nodemon": "^3.0.1", - "prettier": "^3.1.0", - "ts-node": "^10.9.1", - "tsc": "^2.0.4", - "typescript": "^5.2.2" - }, - "lint-staged": { - "*.ts": [ - "eslint --fix", - "prettier --write" - ], - "*.{ts,json,md}": "prettier --write" - } + "*.{ts,json,md}": "prettier --write" + } } diff --git a/src/core/renderEmail.ts b/src/core/renderEmail.ts index fded076..5772e85 100644 --- a/src/core/renderEmail.ts +++ b/src/core/renderEmail.ts @@ -1,79 +1,322 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + ProcessorContext, + ProcessorFn, + ProcessorFnSync, + ProcessorInfo, + ProcessorScope, + processSync, + Component, + ComponentPaths, + DataObject, + AddressComponent, + DateTimeComponent, + TimeComponent, + SelectBoxesComponent, + AddressComponentDataObject, +} from '@formio/core'; +import { + formatAddressValue, + formatCurrency, + formatDatetime, + formatTime, + insertDataMapTable, + insertGridTable, + insertRow, + insertSketchpadTable, + insertSurveyTable, + insertTable, + isGridBasedComponent, + isLayoutComponent, +} from './renderEmailUtils'; + +import { JSDOM } from 'jsdom'; import _ from 'lodash'; -import { Formio, Form } from '@formio/js'; import { evaluate } from '..'; - import macros from './deps/nunjucks-macros'; export type RenderEmailOptions = { - render: any; - context: any; - timeout?: number; + render: any; + context: any; + timeout?: number; +}; + +export type ComponentRenderContext = { + component: Component; + data: DataObject; + row?: any; + paths?: ComponentPaths; + parent?: Component | null; + parentId: string; + componentId: string; + document: Document; + language?: string; + directChildOfTagPad?: boolean; + directChildOfGrid?: boolean; +}; + +const renderEmailProcessorSync: ProcessorFnSync = ( + context: ProcessorContext, +) => { + const { component, paths, parent, row, scope, data } = context; + const scopeRef = scope as any; + if ((component as any).skipInEmail || isLayoutComponent(component)) return; + + const conditionallyHidden = scopeRef.conditionals.find( + (cond: any) => cond.path === paths?.dataPath && cond.conditionallyHidden, + ); + const intentionallyHidden = component.hidden; + + if (conditionallyHidden || intentionallyHidden) return; + + // the address component has all the data needed for rendering on context.data at the component's data path + // the children (if in manual mode) do not need to be iterated over since this data is redundant + // the children are the individual manual mode address fields (address1, city, etc) + if (parent?.type === 'address') return; + + if (!scopeRef.emailDom) { + scopeRef.emailDom = new JSDOM(` + + + +
+ `); + } + const document = scopeRef.emailDom.window.document; + + const language = (context as any)?.metadata?.language; + + const rowValue: any = _.get(data, paths?.dataPath ?? component.key); + + // some components (like nested forms) add .data to the path + // this makes it hard to map onto the parent while iterating through nested children + // i.e. if the parent's data path is 'form' + // and the child's is 'form.data.textField' + const componentId = paths?.dataPath?.replace(/\.data\b/g, '') ?? ''; + // remove the current component key from the path + // so we can get at the parent component's data path + // to insert child rows/tables into the parent html table + // replace the last index (for grid-based components) for easier mapping + // see comment in insertGridHtml() + const parentId = + parent && componentId.includes('.') + ? componentId.substring(0, componentId.lastIndexOf('.')).replace(/\[\d+\]$/, '') + : 'main'; + + const isGridComponent = isGridBasedComponent(component); + // this is necessary for rendering descendants of grid-based components that are wrapped by layout components + const componentIdIncludesGridParent = componentId?.includes(scopeRef.gridComponentId); + if (scopeRef.gridComponentId && !componentIdIncludesGridParent) { + scopeRef.gridComponentId = undefined; + } + + if (!scopeRef.gridComponentId && isGridComponent) { + // it will be the parent for future iterations until the data path no longer includes the key + scopeRef.gridComponentId = componentId; + } + + const componentIdIncludesTagPadParent = componentId?.includes(scopeRef.tagPadComponentId); + + if (scopeRef.tagPadComponentId && !componentIdIncludesTagPadParent) { + scopeRef.tagPadComponentId = undefined; + } + + if (!scopeRef.tagPadComponentId && component?.type === 'tagpad') { + scopeRef.tagPadComponentId = componentId; + } + + // if the parent is a layout component, we need to check + // if the current component is nested (directly) in a tagpad component + // used to determine if we need to add a tagpad row number + const directChildOfTagPad = parentId === scopeRef.tagPadComponentId; + // if the parent is a layout component, we need to check + // if the current component is nested (directly) in a grid-based component + // if it has a parent that's a nested form or a container, we don't trigger the grid-based insertion logic + const directChildOfGrid = parentId === scopeRef.gridComponentId; + + const componentRenderContext = { + component, + data, + row, + paths, + parent, + parentId, + componentId, + document, + language, + directChildOfTagPad, + directChildOfGrid, + }; + + switch (component.type) { + case 'textfield': + case 'number': + case 'password': + case 'select': + case 'radio': + case 'email': + case 'url': + case 'phoneNumber': + case 'day': + case 'tags': + case 'reviewpage': { + const outputValue = component.multiple ? rowValue?.join(', ') : rowValue; + insertRow(componentRenderContext, outputValue); + return; + } + // TODO: translation + case 'checkbox': + case 'signature': { + insertRow(componentRenderContext, rowValue ? 'Yes' : 'No'); + return; + } + case 'textarea': { + const outputValue = component.multiple + ? rowValue?.map((v: string) => v.replace(/\n/g, ' ')).join(', ') + : rowValue; + insertRow(componentRenderContext, outputValue); + return; + } + case 'selectboxes': { + const outputValue = rowValue + ? (component as SelectBoxesComponent)?.values + ?.filter((v) => rowValue[v.value]) + .map((v) => v.label) + .join(', ') + : ''; + insertRow(componentRenderContext, outputValue); + return; + } + case 'address': { + const outputValue = component.multiple + ? rowValue + ?.map((v: AddressComponentDataObject) => + formatAddressValue(v, component as AddressComponent, data), + ) + .join(', ') + : formatAddressValue(rowValue, component as AddressComponent, data); + insertRow(componentRenderContext, outputValue); + return; + } + case 'datetime': { + const timezone = (context as any)?.metadata?.timezone; + const outputValue = component.multiple + ? rowValue + ?.map((v: string) => formatDatetime(component as DateTimeComponent, timezone, v)) + .join(', ') + : formatDatetime(component as DateTimeComponent, timezone, rowValue); + insertRow(componentRenderContext, outputValue); + return; + } + case 'time': { + const outputValue = component.multiple + ? rowValue?.map((v: string) => formatTime(component as TimeComponent, v)).join(', ') + : formatTime(component as TimeComponent, rowValue); + insertRow(componentRenderContext, outputValue); + return; + } + case 'currency': { + const outputValue = component.multiple + ? rowValue?.map((v: string) => formatCurrency(component, v)).join(', ') + : formatCurrency(component, rowValue); + insertRow(componentRenderContext, outputValue); + return; + } + case 'survey': { + insertSurveyTable(componentRenderContext, rowValue); + return; + } + case 'datamap': { + insertDataMapTable(componentRenderContext, rowValue); + return; + } + //TODO: look into how options.review works for file components + case 'file': { + const outputValue = _.isArray(rowValue) + ? rowValue?.map((v: any) => v?.originalName).join(', ') + : rowValue?.originalName; + insertRow(componentRenderContext, outputValue); + return; + } + case 'sketchpad': { + insertSketchpadTable(componentRenderContext, rowValue); + return; + } + case 'datagrid': + case 'editgrid': + case 'tagpad': + case 'datatable': { + insertGridTable(componentRenderContext, rowValue); + return; + } + case 'form': { + // if no child data exists in the nested form, just render the nested form's submission id + if (!rowValue?.data) { + const outputValue = rowValue?._id; + insertRow(componentRenderContext, outputValue); + return; + } + insertTable(componentRenderContext); + return; + } + case 'container': { + insertTable(componentRenderContext); + return; + } + default: + return; + } +}; + +const renderEmailProcessor: ProcessorFn = async (context) => { + return renderEmailProcessorSync(context); +}; + +const renderEmailProcessorInfo: ProcessorInfo, void> = { + name: 'renderEmail', + process: renderEmailProcessor, + processSync: renderEmailProcessorSync, + shouldProcess: () => true, }; export async function renderEmail({ - render, - context = {}, - timeout = 500, + render, + context = {}, + timeout = 500, }: RenderEmailOptions): Promise { - if (context._private) { - delete context._private; - } - context.macros = macros; - - const renderMethod = getRenderMethod(render); - - const data: any = { - input: omitUndefined(render), - context, - submissionTableHtml: null, - }; - - if (renderMethod === 'dynamic') { - try { - const premium = await import( - // @ts-expect-error Premium is included in the server build. - '@formio/premium/dist/premium-server.min.js' - ); - Formio.use(premium); - } catch { - // eslint-disable-next-line no-empty - } - const form = await new Form(context.form, { - server: true, - noeval: true, - noDefaults: true, - submissionTimezone: context?.metadata?.timezone, - }).ready; - - form.setValue( - { data: context.data, metadata: context.metadata }, - { sanitize: true }, - ); - - // this is a hack to ensure the form is fully rendered before we get the form html - // ideally, we'd have a promise from the renderer that we can await to ensure the form is fully rendered - await new Promise((resolve) => { - setTimeout(resolve, 1000); - }); - - const submissionTableHtml = form.getView(context.data, { - email: true, - }); - - data.submissionTableHtml = submissionTableHtml; - } - - const res = await evaluate({ - deps: ['lodash', 'moment', 'core', 'nunjucks'], - data: data, - code: getScript(render), - timeout, + if (context._private) { + delete context._private; + } + context.macros = macros; + + const renderMethod = getRenderMethod(render); + + const data: any = { + input: omitUndefined(render), + context, + submissionTableHtml: null, + }; + + if (renderMethod === 'dynamic') { + const result = processSync({ + ...context, + components: context.form.components, + processors: [renderEmailProcessorInfo], }); - return res as string; + data.submissionTableHtml = (result as any).emailDom.window.document.body.innerHTML; + } + + const res = await evaluate({ + deps: ['lodash', 'moment', 'core', 'nunjucks'], + data: data, + code: getScript(render), + timeout, + }); + return res as string; } export function getScript(data: any) { - const injectDependencies = ` + const injectDependencies = ` if (_) { environment.addGlobal('_',_) } @@ -84,17 +327,17 @@ export function getScript(data: any) { environment.addGlobal('utils',utils) }`; - if (_.isString(data)) { - // Script to render a single string. - return ` + if (_.isString(data)) { + // Script to render a single string. + return ` ${injectDependencies} environment.params = context; output = unescape(environment.renderString(sanitize(input), context)); `; - } + } - // Script to render an object of properties. - return ` + // Script to render an object of properties. + return ` ${injectDependencies} environment.params = context; var rendered = {}; @@ -112,13 +355,13 @@ export function getScript(data: any) { } function getRenderMethod(render: any) { - let renderMethod = 'static'; - if (process.env.RENDER_METHOD) { - renderMethod = process.env.RENDER_METHOD; - } else if (render && render.renderingMethod) { - renderMethod = render.renderingMethod; - } - return renderMethod; + let renderMethod = 'static'; + if (process.env.RENDER_METHOD) { + renderMethod = process.env.RENDER_METHOD; + } else if (render && render.renderingMethod) { + renderMethod = render.renderingMethod; + } + return renderMethod; } const omitUndefined = (obj: any) => _.omitBy(obj, _.isUndefined); diff --git a/src/core/renderEmailUtils.ts b/src/core/renderEmailUtils.ts new file mode 100644 index 0000000..1f65047 --- /dev/null +++ b/src/core/renderEmailUtils.ts @@ -0,0 +1,411 @@ +import { + I18n, + convertFormatToMoment, + coreEnTranslation, + currentTimezone, + momentDate, + Component, + DataObject, + AddressComponent, + DateTimeComponent, + SurveyComponent, + TimeComponent, + Evaluator, + AddressComponentDataObject, + Utils, +} from '@formio/core'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ +import _ from 'lodash'; +import moment from 'moment'; +import { ComponentRenderContext } from './renderEmail'; + +export const t = ( + text: string, + language: string = 'en', + params: Record = {}, + ...args: any[] +): string => { + if (!text) { + return ''; + } + // Use _userInput: true to ignore translations from defaults + if (text in coreEnTranslation && params._userInput) { + return text; + } + const i18n = I18n.init(language); + return i18n.t(text, params, ...args); +}; + +export const isLayoutComponent = (component: Component) => { + const modelType = Utils.getModelType(component); + return modelType === 'none' || modelType === 'content'; +}; + +export const isGridBasedComponent = (component?: Component | null) => { + if (!component) return false; + const modelType = Utils.getModelType(component); + return modelType === 'nestedArray' || modelType === 'nestedDataArray'; +}; + +const shouldInsertGridChild = ( + component: Component, + parent?: Component | null, + directChildOfGrid?: boolean, // if the parent is a layout component, we use this to determine if this component is within a grid +) => isGridBasedComponent(parent) || (!isGridBasedComponent(component) && directChildOfGrid); + +const isValueInLegacyFormat = (value: AddressComponentDataObject) => { + return value && !value.mode; +}; + +// if the value is in legacy format, it won't be of type AddressComponentDataObject +// so using any instead +const normalizeValue = (value: any, component: AddressComponent) => { + return component.enableManualMode && isValueInLegacyFormat(value) + ? { + mode: 'autocomplete', + address: value, + } + : value; +}; + +const getProviderDisplayValue = ( + address: AddressComponentDataObject, + component: AddressComponent, +): string => { + let displayedProperty = ''; + switch (component.provider) { + case 'google': + displayedProperty = _.has(address, 'formattedPlace') ? 'formattedPlace' : 'formatted_address'; + break; + case 'nominatim': + displayedProperty = 'display_name'; + break; + case 'azure': + displayedProperty = 'address.freeformAddress'; + break; + case 'custom': + displayedProperty = component?.providerOptions?.displayValueProperty; + break; + } + return _.get(address, displayedProperty, ''); +}; + +export const formatAddressValue = ( + value: AddressComponentDataObject, + component: AddressComponent, + data: DataObject, +): string => { + const normalizedValue = normalizeValue(value, component); + + const { address, mode } = component.enableManualMode + ? normalizedValue + : { + address: normalizedValue, + mode: 'autocomplete', + }; + + const valueInManualMode = mode === 'manual'; + + if (component.provider && !valueInManualMode) { + return getProviderDisplayValue(address, component); + } + if (valueInManualMode) { + if (component.manualModeViewString && address) { + return Evaluator.interpolateString(component.manualModeViewString, { + address, + component, + data, + }); + } + } + if (address) { + const parts = []; + if (address.address1) parts.push(address.address1); + if (address.address2) parts.push(address.address2); + if (address.city) parts.push(address.city); + if (address.state) parts.push(address.state); + if (address.zip) parts.push(address.zip); + if (address.country) parts.push(address.country); + return parts.join(', '); + } + return ''; +}; + +export const formatCurrency = (component: Component, value?: string) => { + if (!value) return ''; + const currency = (component as any).currency; + return currency + ? Number(value).toLocaleString(undefined, { + style: 'currency', + currency, + }) + : value; +}; + +export const formatDatetime = ( + component: DateTimeComponent, + userProvidedTimezone?: string, + value?: string, +) => { + if (!value) return ''; + const rawFormat = component.format ?? 'yyyy-MM-dd hh:mm a'; + let format = convertFormatToMoment(rawFormat); + format += format.match(/z$/) ? '' : ' z'; + const displayInTimezone = component.displayInTimezone; + const locationTimezone = component.timezone; + const timezone = + displayInTimezone === 'utc' + ? 'Etc/UTC' + : userProvidedTimezone && displayInTimezone === 'submission' + ? userProvidedTimezone + : locationTimezone && displayInTimezone === 'location' + ? locationTimezone + : // of viewer (i.e. wherever this server is) + currentTimezone(); + return momentDate(value, format, timezone).format(format); +}; + +export const formatTime = (component: TimeComponent, value?: string) => { + if (!value) return ''; + const format = component.format ?? 'HH:mm'; + const dataFormat = component.dataFormat ?? 'HH:mm:ss'; + return moment(value, dataFormat).format(format); +}; + +export const insertRow = ( + componentRenderContext: ComponentRenderContext, + rawValue?: string, + label?: string, + noInsert?: boolean, // only used by insertDataMapTable +) => { + const { component, parent, parentId, document, directChildOfGrid } = componentRenderContext; + const value = component?.protected ? '--- PROTECTED ---' : rawValue ?? ''; + if (shouldInsertGridChild(component, parent, directChildOfGrid) && !noInsert) { + insertGridRow(value, componentRenderContext); + return; + } + const html = ` + + ${label ?? component?.label ?? component?.key ?? ''} + + ${value} + + + `; + if (noInsert) return html; + insertHtml(html, parentId, document); +}; + +const insertGridHeader = (componentRenderContext: ComponentRenderContext) => { + const { component, data, row, parentId, paths, document, language } = componentRenderContext; + const componentIdNoLastIndex = `${parentId}-${component.key}`; + const existingHeadValue = document.getElementById(`${componentIdNoLastIndex}-th`); + if (!existingHeadValue) { + const headValue = ` + ${t( + component?.label ?? component.key, + language, + { + data, + row, + paths, + _userInput: true, + }, + )} + `; + const parentTheadId = `${parentId}-thead`; + insertHtml(headValue, parentTheadId, document); + } +}; + +const insertGridHtml = ( + componentRenderContext: ComponentRenderContext, + childHtml: string, // child row or child table +) => { + const { document, paths, directChildOfTagPad, parentId } = componentRenderContext; + const childRowId = `${parentId}${paths?.dataIndex ?? 0}-childRow`; + const existingChildRow = document.getElementById(childRowId); + const styles = directChildOfTagPad ? 'text-align: center' : 'padding: 5px 10px;'; + const rowValue = ` + ${!existingChildRow ? `` : ''} + ${ + !existingChildRow && directChildOfTagPad + ? `${paths?.dataIndex != null ? paths.dataIndex + 1 : 0}` + : '' + } + ${childHtml} + ${!existingChildRow ? `` : ''}`; + + insertHtml( + rowValue, + // use parentId, which has no last index since when the parent grid-based table was inserted + // the componentId of that table had no index + // i.e. 'tagpad' was the componentId of the parent + // but the data path of the child would be 'tagpad[0].textfield' + // so, to derive the parentId based on the child's data path + // we need to 1: remove the component key from the path, and 2: remove the final index + // if it's a nested grid, we need every index except the last + // i.e. 'editgrid[0].editgrid1[1].textfield', the parentId would be 'editgrid[0].editgrid1' + existingChildRow ? childRowId : parentId, + document, + ); +}; + +const insertGridRow = (value: string, componentRenderContext: ComponentRenderContext) => { + const { directChildOfTagPad } = componentRenderContext; + insertGridHeader(componentRenderContext); + const styles = directChildOfTagPad ? 'text-align: center' : 'padding: 5px 10px;'; + const childValue = `${value}`; + insertGridHtml(componentRenderContext, childValue); +}; + +export const insertTable = ( + componentRenderContext: ComponentRenderContext, + rows?: string, + tHead?: string, +) => { + const { component, componentId, parentId, document, parent, directChildOfGrid } = + componentRenderContext; + if (shouldInsertGridChild(component, parent, directChildOfGrid)) { + insertGridChildTable(componentRenderContext, rows, tHead); + return; + } + const html = ` + + ${component.label ?? component.key} + + + ${tHead ?? ''} + + ${rows ?? ''} + +
+ + + `; + insertHtml(html, parentId, document); +}; + +// a child that is a table within a grid-based component +// i.e. a nested form inside of an edit grid +const insertGridChildTable = ( + componentRenderContext: ComponentRenderContext, + rows?: string, + tHead?: string, +) => { + const { componentId, directChildOfTagPad } = componentRenderContext; + insertGridHeader(componentRenderContext); + const styles = directChildOfTagPad ? 'text-align: center' : 'padding: 5px 10px;'; + const childTable = ` + + + ${tHead ?? ''} + + ${rows ?? ''} + +
+ + `; + insertGridHtml(componentRenderContext, childTable); +}; + +export const insertSketchpadTable = ( + componentRenderContext: ComponentRenderContext, + rowValue?: any[], +) => { + const { component, data, row, language = 'en' } = componentRenderContext; + const tHead = + rowValue?.length !== 0 + ? ` + + ${t(component?.label ?? component.key, language, { + data, + row, + component, + _userInput: true, + })}${t('complexData', language, { data, row, component })} + + ` + : ''; + insertTable(componentRenderContext, undefined, tHead); +}; + +// insert a grid-based table component +// i.e. an edit grid, data grid, etc. +export const insertGridTable = ( + componentRenderContext: ComponentRenderContext, + rowValue?: any[], +) => { + const { component, componentId, data, row, paths, language = 'en' } = componentRenderContext; + const tHead = + rowValue?.length !== 0 + ? ` + + + ${ + component.type === 'tagpad' + ? `${t('dots', language, { + data, + row, + paths, + })}` + : '' + } + + + ` + : ''; + insertTable(componentRenderContext, undefined, tHead); +}; + +export const insertSurveyTable = ( + componentRenderContext: ComponentRenderContext, + value: Record, +) => { + const { component, data, row, language = 'en' } = componentRenderContext; + const tHead = ` + + + ${t('surveyQuestion', language, { data, row, component })} + ${t('surveyQuestionValue', language, { data, row, component })} + + `; + const rows = value + ? Object.entries(value) + .map(([key, value]) => { + const question = _.find((component as SurveyComponent).questions, ['value', key]); + const answer = _.find((component as SurveyComponent).values, ['value', value]); + if (!question || !answer) { + return; + } + return ` + + ${question.label} + ${answer.label} + + `; + }) + .join('') + : ''; + insertTable(componentRenderContext, rows, tHead); +}; + +export const insertDataMapTable = ( + componentRenderContext: ComponentRenderContext, + value: Record, +) => { + const rows = value + ? Object.entries(value) + .map(([key, value]) => insertRow(componentRenderContext, value, key, true)) + .join('') + : ''; + insertTable(componentRenderContext, rows); +}; + +const insertHtml = (html: string, parentId: string, document: Document) => { + const parentElement = document.getElementById(parentId); + if (parentElement) { + parentElement.insertAdjacentHTML('beforeend', html); + } +}; diff --git a/yarn.lock b/yarn.lock index 24769f0..5a02231 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,17 @@ resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@asamuzakjp/css-color@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@asamuzakjp/css-color/-/css-color-3.1.1.tgz#41a612834dafd9353b89855b37baa8a03fb67bf2" + integrity sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA== + dependencies: + "@csstools/css-calc" "^2.1.2" + "@csstools/css-color-parser" "^3.0.8" + "@csstools/css-parser-algorithms" "^3.0.4" + "@csstools/css-tokenizer" "^3.0.3" + lru-cache "^10.4.3" + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -14,6 +25,34 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@csstools/color-helpers@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.0.2.tgz#82592c9a7c2b83c293d9161894e2a6471feb97b8" + integrity sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA== + +"@csstools/css-calc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.1.2.tgz#bffd55f002dab119b76d4023f95cd943e6c8c11e" + integrity sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw== + +"@csstools/css-color-parser@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.0.8.tgz#5fe9322920851450bf5e065c2b0e731b9e165394" + integrity sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ== + dependencies: + "@csstools/color-helpers" "^5.0.2" + "@csstools/css-calc" "^2.1.2" + +"@csstools/css-parser-algorithms@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz#74426e93bd1c4dcab3e441f5cc7ba4fb35d94356" + integrity sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A== + +"@csstools/css-tokenizer@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz#a5502c8539265fecbd873c1e395a890339f119c2" + integrity sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw== + "@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -51,15 +90,15 @@ resolved "https://registry.yarnpkg.com/@formio/bootstrap/-/bootstrap-3.0.0-dev.121.085d187.tgz#7cc8c3a62e531b9b508e68d08fa513241c659da6" integrity sha512-V9AgDNTiFuvw0g/+QbUu2e8c061obSInmwn3qjsxkySg1VtpuVO2hrhgS8Lqxa5Q3IKbgmkrbCJGex8GCxNAnA== -"@formio/core@2.4.0-dev.221.e0c6673": - version "2.4.0-dev.221.e0c6673" - resolved "https://registry.yarnpkg.com/@formio/core/-/core-2.4.0-dev.221.e0c6673.tgz#e04cb03331045cbc809b4b8a321618d3fda528dd" - integrity sha512-Ly6cYcDfdPMuTonkmWQkJZLmvZHF2UfCpg+vb35CkIZIeckZ0aDfTooO09MIm+lMHjxab/QAxfPr2NaDau0Nkw== +"@formio/core@2.4.0-dev.235.b497e17": + version "2.4.0-dev.235.b497e17" + resolved "https://registry.yarnpkg.com/@formio/core/-/core-2.4.0-dev.235.b497e17.tgz#f7ae2b4e12cfadca0a2b03af7d9718b4fffcbe48" + integrity sha512-0Hm9BdYLkn3z+z63OsG9JZUd9GgK/rX7h6V3PwAsv5U/66JQvVHhVoyq+w+pfplLRYNbijn6g9wrHvpoSzFQ1g== dependencies: browser-cookies "^1.2.0" - core-js "^3.39.0" + core-js "^3.40.0" dayjs "^1.11.12" - dompurify "^3.2.3" + dompurify "^3.2.4" eventemitter3 "^5.0.0" fast-json-patch "^3.1.1" fetch-ponyfill "^7.1.0" @@ -276,6 +315,15 @@ resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== +"@types/jsdom@^21.1.7": + version "21.1.7" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-21.1.7.tgz#9edcb09e0b07ce876e7833922d3274149c898cfa" + integrity sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA== + dependencies: + "@types/node" "*" + "@types/tough-cookie" "*" + parse5 "^7.0.0" + "@types/json-schema@^7.0.12": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -362,6 +410,11 @@ "@types/mime" "*" "@types/node" "*" +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + "@types/trusted-types@^2.0.7": version "2.0.7" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" @@ -496,6 +549,11 @@ acorn@^8.4.1, acorn@^8.9.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + aggregate-error@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz#25091fe1573b9e0be892aeda15c7c66a545f758e" @@ -798,6 +856,11 @@ async-settle@^1.0.0: dependencies: async-done "^1.2.2" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + atoa@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/atoa/-/atoa-1.0.0.tgz#0cc0e91a480e738f923ebc103676471779b34a49" @@ -1010,6 +1073,14 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" @@ -1231,6 +1302,13 @@ colorette@^2.0.20: resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@11.1.0: version "11.1.0" resolved "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" @@ -1324,6 +1402,11 @@ core-js@^3.39.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.40.0.tgz#2773f6b06877d8eda102fc42f828176437062476" integrity sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ== +core-js@^3.40.0: + version "3.41.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.41.0.tgz#57714dafb8c751a6095d028a7428f1fb5834a776" + integrity sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA== + core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -1357,6 +1440,14 @@ crossvent@1.5.5: dependencies: custom-event "^1.0.0" +cssstyle@^4.2.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.3.0.tgz#83db22d1aec8eb7e5ecd812b4d14a17fb3dd243d" + integrity sha512-6r0NiY0xizYqfBvWp1G7WXJ06/bZyrk7Dc6PHql82C/pKGUTKu4yAX4Y8JPamb1ob9nBKuxWzCGTRuGwU3yxJQ== + dependencies: + "@asamuzakjp/css-color" "^3.1.1" + rrweb-cssom "^0.8.0" + custom-event@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" @@ -1370,6 +1461,14 @@ d@1, d@^1.0.1: es5-ext "^0.10.50" type "^1.0.1" +data-urls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" + integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== + dependencies: + whatwg-mimetype "^4.0.0" + whatwg-url "^14.0.0" + dayjs@^1.11.12: version "1.11.13" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" @@ -1382,6 +1481,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" +debug@4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + debug@4.3.4, debug@^4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -1406,6 +1512,11 @@ decamelize@^4.0.0: resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decimal.js@^10.4.3: + version "10.5.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.5.0.tgz#0f371c7cf6c4898ce0afb09836db73cd82010f22" + integrity sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw== + decode-uri-component@^0.2.0: version "0.2.2" resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -1501,6 +1612,11 @@ del@^7.1.0: rimraf "^3.0.2" slash "^4.0.0" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -1597,6 +1713,13 @@ dompurify@^3.1.6, dompurify@^3.2.3: optionalDependencies: "@types/trusted-types" "^2.0.7" +dompurify@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.2.4.tgz#af5a5a11407524431456cf18836c55d13441cd8e" + integrity sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg== + optionalDependencies: + "@types/trusted-types" "^2.0.7" + dotenv@^16.3.1: version "16.3.1" resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" @@ -1615,6 +1738,15 @@ dragula@^3.7.3: contra "1.9.4" crossvent "1.5.5" +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + duplexify@^3.6.0: version "3.7.1" resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" @@ -1660,6 +1792,11 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + error-ex@^1.2.0: version "1.3.2" resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -1712,6 +1849,23 @@ es-abstract@^1.22.1: unbox-primitive "^1.0.2" which-typed-array "^1.1.13" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + es-set-tostringtag@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" @@ -1721,6 +1875,16 @@ es-set-tostringtag@^2.0.1: has-tostringtag "^1.0.0" hasown "^2.0.0" +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + es-shim-unscopables@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" @@ -2300,6 +2464,16 @@ for-own@^1.0.0: dependencies: for-in "^1.0.1" +form-data@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c" + integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + mime-types "^2.1.12" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -2403,6 +2577,30 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + get-stream@^8.0.1: version "8.0.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" @@ -2579,6 +2777,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.10: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -2662,6 +2865,11 @@ has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" @@ -2669,6 +2877,13 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + has-value@^0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -2707,6 +2922,13 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + he@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -2724,6 +2946,13 @@ hosted-git-info@^2.1.4: resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== +html-encoding-sniffer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" + integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== + dependencies: + whatwg-encoding "^3.1.1" + http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -2735,6 +2964,22 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-proxy-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +https-proxy-agent@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + human-signals@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" @@ -2752,6 +2997,13 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + idb@^7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" @@ -3075,6 +3327,11 @@ is-plain-object@^5.0.0: resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -3208,6 +3465,33 @@ js-yaml@4.1.0, js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsdom@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-26.0.0.tgz#446dd1ad8cfc50df7e714e58f1f972c1763b354c" + integrity sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw== + dependencies: + cssstyle "^4.2.1" + data-urls "^5.0.0" + decimal.js "^10.4.3" + form-data "^4.0.1" + html-encoding-sniffer "^4.0.0" + http-proxy-agent "^7.0.2" + https-proxy-agent "^7.0.6" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.16" + parse5 "^7.2.1" + rrweb-cssom "^0.8.0" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^5.0.0" + w3c-xmlserializer "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^3.1.1" + whatwg-mimetype "^4.0.0" + whatwg-url "^14.1.0" + ws "^8.18.0" + xml-name-validator "^5.0.0" + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -3434,6 +3718,11 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" +lru-cache@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3475,6 +3764,11 @@ matchdep@^2.0.0: resolve "^1.4.0" stack-trace "0.0.10" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -3532,7 +3826,7 @@ mime-db@1.52.0: resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -3654,7 +3948,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3805,6 +4099,11 @@ nunjucks@^3.2.4: asap "^2.0.3" commander "^5.1.0" +nwsapi@^2.2.16: + version "2.2.18" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.18.tgz#3c4d7927e1ef4d042d319438ecfda6cd81b7ee41" + integrity sha512-p1TRH/edngVEHVbwqWnxUViEmq5znDvyB+Sik5cmuLpGOIfDf/39zLiq3swPF8Vakqn+gvNiOQAZu8djYlQILA== + object-copy@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -4015,6 +4314,13 @@ parse-passwd@^1.0.0: resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== +parse5@^7.0.0, parse5@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a" + integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ== + dependencies: + entities "^4.5.0" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -4206,7 +4512,7 @@ pumpify@^1.3.5: inherits "^2.0.3" pump "^2.0.0" -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -4478,6 +4784,11 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +rrweb-cssom@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz#3021d1b4352fbf3b614aaeed0bc0d5739abe0bc2" + integrity sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -4521,11 +4832,18 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + semver-greatest-satisfied-range@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz#13e8c2658ab9691cb0cd71093240280d36f77a5b" @@ -4997,6 +5315,11 @@ sver-compat@^1.5.0: es6-iterator "^2.0.1" es6-symbol "^3.1.1" +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + tar-fs@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" @@ -5056,6 +5379,18 @@ tippy.js@^6.3.7: dependencies: "@popperjs/core" "^2.9.0" +tldts-core@^6.1.84: + version "6.1.84" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.84.tgz#f8ac2af9969bf9c2f7a99fa05d9c667b5e5b768c" + integrity sha512-NaQa1W76W2aCGjXybvnMYzGSM4x8fvG2AN/pla7qxcg0ZHbooOPhA8kctmOZUDfZyhDL27OGNbwAeig8P4p1vg== + +tldts@^6.1.32: + version "6.1.84" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.84.tgz#fb58b1ceb70972a1ecd683606cea3d06c78f7238" + integrity sha512-aRGIbCIF3teodtUFAYSdQONVmDRy21REM3o6JnqWn5ZkQBJJ4gHxhw6OfwQ+WkSAi3ASamrS4N4nyazWx6uTYg== + dependencies: + tldts-core "^6.1.84" + to-absolute-glob@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b" @@ -5115,6 +5450,20 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" +tough-cookie@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-5.1.2.tgz#66d774b4a1d9e12dc75089725af3ac75ec31bed7" + integrity sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A== + dependencies: + tldts "^6.1.32" + +tr46@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" + integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== + dependencies: + punycode "^2.3.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -5459,11 +5808,43 @@ vinyl@^2.0.0: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" +w3c-xmlserializer@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" + integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== + dependencies: + xml-name-validator "^5.0.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-encoding@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" + integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" + integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== + +whatwg-url@^14.0.0, whatwg-url@^14.1.0: + version "14.1.1" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.1.1.tgz#ce71e240c61541315833b5cdafd139a479e47058" + integrity sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ== + dependencies: + tr46 "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -5549,6 +5930,21 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@^8.18.0: + version "8.18.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" + integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== + +xml-name-validator@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" + integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"