diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 78f211df9..e7af5a6a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -472,6 +472,8 @@ jobs: working-directory: report-react - run: npm install working-directory: accessibility-checker-extension + - run: npm install + working-directory: accessibility-checker-extension/test - run: npm install working-directory: rule-server - run: npm run build @@ -484,6 +486,9 @@ jobs: working-directory: accessibility-checker-extension - run: npm run package:browser working-directory: accessibility-checker-extension + - name: UI Tests + run: npm test + working-directory: accessibility-checker-extension/test - name: Upload packed extension uses: actions/upload-artifact@v1 with: @@ -498,9 +503,6 @@ jobs: with: name: accessibility-checker-extension for Firefox path: accessibility-checker-extension/package/accessibility-checker-extension.zip - - name: Jest tests - run: npm test - working-directory: accessibility-checker-extension rule-deploy: runs-on: ubuntu-22.04 diff --git a/accessibility-checker-extension/package.json b/accessibility-checker-extension/package.json index bb36d31df..8dc53e7f4 100644 --- a/accessibility-checker-extension/package.json +++ b/accessibility-checker-extension/package.json @@ -12,8 +12,7 @@ "build:watch:local": "node preprocess && npm run build:report && cross-env NODE_ENV=watch_local SASS_PATH=node_modules:src:node_modules/carbon-components/scss/globals/scss/vendor webpack --mode production", "clean": "shx rm -rf ./dist && shx rm -rf ./package", "clean:all": "shx rm -rf ./dist && shx rm -rf ./coverage && shx rm -rf ./package && shx rm -rf ./node_modules", - "test": "jest", - "test:coverage": "jest --collect-coverage", + "test": "cd test && npm test", "package:browser": "npm run build:prod && shx mkdir -p package && cd dist && zip -Zd -r ../package/accessibility-checker-extension.zip ." }, "license": "Apache-2.0", @@ -33,10 +32,8 @@ "webext-redux": "^2.1.9" }, "devDependencies": { - "@jest/globals": "^29.7.0", "@svgr/webpack": "^6.1.2", "@types/chrome": "^0.0.171", - "@types/jest": "^29.5.1", "@types/markdown-to-jsx": "^7.0.0", "@types/node": "^18.15.3", "@types/react": "17.0.37", @@ -51,8 +48,6 @@ "css-loader": "^6.5.1", "html-webpack-plugin": "^5.5.0", "identity-obj-proxy": "^3.0.0", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", "mini-css-extract-plugin": "^2.4.5", "react-test-renderer": "^17.0.2", "resize-observer-polyfill": "^1.5.1", @@ -61,7 +56,6 @@ "shx": "^0.3.3", "style-loader": "^3.3.1", "terser-webpack-plugin": "^5.3.7", - "ts-jest": "^29.1.0", "ts-loader": "^9.2.6", "tslint": "^5.20.1", "typescript": "^4.5.4", diff --git a/accessibility-checker-extension/src/html/devtoolsElements.html b/accessibility-checker-extension/src/html/devtoolsElements.html index 4e8d3714c..bdfa48a9a 100644 --- a/accessibility-checker-extension/src/html/devtoolsElements.html +++ b/accessibility-checker-extension/src/html/devtoolsElements.html @@ -1,5 +1,5 @@ - + IBM Accessibility Checker Extension: Assessment diff --git a/accessibility-checker-extension/src/html/devtoolsMain.html b/accessibility-checker-extension/src/html/devtoolsMain.html index 34b3d897b..b6afd235b 100644 --- a/accessibility-checker-extension/src/html/devtoolsMain.html +++ b/accessibility-checker-extension/src/html/devtoolsMain.html @@ -1,5 +1,5 @@ - + IBM Accessibility Checker Extension: Checker diff --git a/accessibility-checker-extension/src/ts/background/backgroundController.ts b/accessibility-checker-extension/src/ts/background/backgroundController.ts index 8225804a6..f1b0acfb4 100644 --- a/accessibility-checker-extension/src/ts/background/backgroundController.ts +++ b/accessibility-checker-extension/src/ts/background/backgroundController.ts @@ -116,7 +116,7 @@ class BackgroundController extends Controller { this.addEventListener(listener, `BG_onTabUpdate`); } - public async getTabInfo(tabId?: number) : Promise { + public async getTabInfo(tabId: number) : Promise { return this.hook("getTabInfo", tabId, async () => { let tab = await new Promise(async (resolve2) => { let manifest = chrome.runtime.getManifest(); @@ -317,12 +317,12 @@ class BackgroundController extends Controller { /** * Get the rulesets for the currently loaded engine */ - public async getRulesets(senderTabId: number) : Promise { - return this.hook("getRulesets", senderTabId, async () => { - await this.initTab(senderTabId!); + public async getRulesets(contentTabId: number) : Promise { + return this.hook("getRulesets", contentTabId, async () => { + await this.initTab(contentTabId!); // let isLoaded = await this.isEngineLoaded(senderTabId); // isLoaded && console.log("Engine loaded", senderTabId) || console.log("Engine not loaded", senderTabId); - return await myExecuteScript2(senderTabId, () => { + return await myExecuteScript2(contentTabId, () => { let checker = new (window).aceIBMa.Checker(); return checker.rulesets; }); @@ -336,15 +336,16 @@ class BackgroundController extends Controller { } ///// Scan related functions ///////////////////////////////////////// - public async requestScan(senderTabId: number) { - return this.hook("requestScan", senderTabId, async () => { - getDevtoolsController(false, "remote", senderTabId).setScanningState("initializing"); - await this.initTab(senderTabId!); + public async requestScan(tabIds: {toolTabId: number, contentTabId: number}) { + return this.hook("requestScan", tabIds, async () => { + const { toolTabId, contentTabId } = tabIds; + getDevtoolsController(toolTabId, false, "remote").setScanningState("initializing"); + await this.initTab(contentTabId!); // We want this to execute after the message returns (async () => { let settings = await this.getSettings(); - getDevtoolsController(false, "remote", senderTabId).setScanningState("running"); - let report : IReport = await myExecuteScript2(senderTabId, (settings: ISettings) => { + getDevtoolsController(toolTabId, false, "remote").setScanningState("running"); + let report : IReport = await myExecuteScript2(contentTabId, (settings: ISettings) => { let checker = new (window).aceIBMa.Checker(); if (Object.keys(checker.engine.nlsMap).length === 0) { // Some problem grabbing messages for given locale. Let's try to get en-US data out of the engine @@ -415,7 +416,7 @@ class BackgroundController extends Controller { let browser = (navigator.userAgent.match(/\) ([^)]*)$/) || ["", "Unknown"])[1]; this.metrics.profileV2(report.totalTime, browser, settings.selected_ruleset.id); this.metrics.sendLogsV2(); - getDevtoolsController(false, "remote", senderTabId).setScanningState("processing"); + getDevtoolsController(toolTabId, false, "remote").setScanningState("processing"); if (report) { for (const result of report.results) { if (result.ruleTime > 50) { @@ -459,8 +460,8 @@ class BackgroundController extends Controller { report.counts = counts; } - getDevtoolsController(false, "remote", senderTabId).setReport(report); - getDevtoolsController(false, "remote", senderTabId).setScanningState("idle"); + getDevtoolsController(toolTabId, false, "remote").setReport(report); + getDevtoolsController(toolTabId, false, "remote").setScanningState("idle"); })(); return {}; }); diff --git a/accessibility-checker-extension/src/ts/contentScripts/TabStopHighlight.ts b/accessibility-checker-extension/src/ts/contentScripts/TabStopHighlight.ts index f37cd0ddc..d573b5762 100644 --- a/accessibility-checker-extension/src/ts/contentScripts/TabStopHighlight.ts +++ b/accessibility-checker-extension/src/ts/contentScripts/TabStopHighlight.ts @@ -229,7 +229,7 @@ export default class TabStopHighlight { let issue = this.getIssueByXpath(elementXpath,regularTabstops); if (issue) { let tabId = await getBGController().getTabId(); - let devtoolsController = getDevtoolsController(true, "remote", tabId); + let devtoolsController = getDevtoolsController(tabId, true, "remote"); await devtoolsController.setSelectedIssue(null); if (await devtoolsController.getActivePanel() === "elements") { await devtoolsController.inspectPath(elementXpath,element); @@ -247,7 +247,7 @@ export default class TabStopHighlight { let issue = this.getIssueByXpath(elementXpath,tabStopsErrors); if (issue) { let tabId = await getBGController().getTabId(); - let devtoolsController = getDevtoolsController(true, "remote", tabId); + let devtoolsController = getDevtoolsController(tabId, true, "remote"); await devtoolsController.setSelectedIssue(issue); if (await devtoolsController.getActivePanel() === "elements") { await devtoolsController.inspectPath(elementXpath,element); diff --git a/accessibility-checker-extension/src/ts/contentScripts/viewInspect.ts b/accessibility-checker-extension/src/ts/contentScripts/viewInspect.ts index 02ebc242a..2574a6b6e 100644 --- a/accessibility-checker-extension/src/ts/contentScripts/viewInspect.ts +++ b/accessibility-checker-extension/src/ts/contentScripts/viewInspect.ts @@ -24,7 +24,7 @@ type Overlays = { elem: HTMLDivElement, info: HTMLDivElement }; (async () => { let myTabId = await getBGController().getTabId()!; - let devtoolsController = getDevtoolsController(true, "remote", myTabId); + let devtoolsController = getDevtoolsController(myTabId, true); function setProps(objToModify: T, objPropsToSet: Partial) { for (const key in objPropsToSet) { diff --git a/accessibility-checker-extension/src/ts/contentScripts/viewKCM.ts b/accessibility-checker-extension/src/ts/contentScripts/viewKCM.ts index 60c611329..5a1319508 100644 --- a/accessibility-checker-extension/src/ts/contentScripts/viewKCM.ts +++ b/accessibility-checker-extension/src/ts/contentScripts/viewKCM.ts @@ -28,7 +28,7 @@ let myKCMState = false; (async() => { let settings = await bgController.getSettings(); let myTabId = await bgController.getTabId()!; - let devtoolsController = getDevtoolsController(true, "remote", myTabId); + let devtoolsController = getDevtoolsController(myTabId, true); async function refreshDrawing() { // if viewState.kcm === true then scan has occurred and KCM button has been pushed @@ -305,7 +305,7 @@ function deleteDrawing(classToRemove: string) { document.documentElement.addEventListener("keypress", async (evt: KeyboardEvent) => { if (evt.code === "KeyS" && evt.ctrlKey && evt.altKey) { let tabId = await bgController.getTabId(); - bgController.requestScan(tabId); + bgController.requestScan({ toolTabId: tabId, contentTabId: tabId }); evt.preventDefault(); evt.stopPropagation(); } diff --git a/accessibility-checker-extension/src/ts/devtools/components/helpScreen.tsx b/accessibility-checker-extension/src/ts/devtools/components/helpScreen.tsx index 4ff7d522f..885b72f3f 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/helpScreen.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/helpScreen.tsx @@ -19,6 +19,7 @@ import { Column, InlineLoading, Grid } from "@carbon/react"; import { IIssue } from "../../interfaces/interfaces"; import { getDevtoolsController } from "../devtoolsController"; import { getBGController } from "../../background/backgroundController"; +import { getDevtoolsAppController } from "../devtoolsAppController"; interface IHelpScreenState { issue: IIssue | null @@ -38,13 +39,14 @@ export default class HelpScreen extends React.Component { - HelpScreen.devtoolsController.addSelectedIssueListener(async (issue) => { + this.devtoolsController.addSelectedIssueListener(async (issue) => { this.setIssue(issue); }); - let issue = await HelpScreen.devtoolsController.getSelectedIssue(); + let issue = await this.devtoolsController.getSelectedIssue(); this.setIssue(issue!); } diff --git a/accessibility-checker-extension/src/ts/devtools/components/reportSection.tsx b/accessibility-checker-extension/src/ts/devtools/components/reportSection.tsx index d2e88a4c7..8731d89d3 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/reportSection.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/reportSection.tsx @@ -40,9 +40,6 @@ import { getDevtoolsAppController } from '../devtoolsAppController'; import { ReportTabs } from './reports/reportTabs'; import { UtilKCM } from '../../util/UtilKCM'; import { getBGController, issueBaselineMatch } from '../../background/backgroundController'; -import { getTabId } from '../../util/tabId'; - -let devtoolsController = getDevtoolsController(); interface ReportSectionProps { panel: ePanel; @@ -60,10 +57,11 @@ interface ReportSectionState { ignoredIssues: UIIssue[] } -let bgController = getBGController(); -let appController = getDevtoolsAppController(); - export class ReportSection extends React.Component { + private bgController = getBGController(); + private devtoolsAppController = getDevtoolsAppController(); + private devtoolsController = getDevtoolsController(this.devtoolsAppController.toolTabId); + state: ReportSectionState = { report: null, selectedPath: null, @@ -76,42 +74,42 @@ export class ReportSection extends React.Component { - devtoolsController.addReportListener(this.reportListener); - let report = await devtoolsController.getReport(); + this.devtoolsController.addReportListener(this.reportListener); + let report = await this.devtoolsController.getReport(); this.setState({ - canScan: (await bgController.getTabInfo(getTabId()!)).canScan + canScan: (await this.bgController.getTabInfo(this.devtoolsAppController.contentTabId)).canScan }); this.reportListener(report!); - devtoolsController.addSelectedElementPathListener(this.selectedElementListener); - let path = await devtoolsController.getSelectedElementPath(); + this.devtoolsController.addSelectedElementPathListener(this.selectedElementListener); + let path = await this.devtoolsController.getSelectedElementPath(); this.setPath(path!); - devtoolsController.addFocusModeListener(async (newValue: boolean) => { + this.devtoolsController.addFocusModeListener(async (newValue: boolean) => { this.setState({ focusMode: newValue }); }) - devtoolsController.addViewStateListener(async (viewState: ViewState) => { + this.devtoolsController.addViewStateListener(async (viewState: ViewState) => { this.setState({ viewState }); }) this.setState({ - focusMode: await devtoolsController.getFocusMode(), - viewState: (await devtoolsController.getViewState())! + focusMode: await this.devtoolsController.getFocusMode(), + viewState: (await this.devtoolsController.getViewState())! }) - bgController.addIgnoreUpdateListener(async ({ url, issues }) => { - if (url === (await bgController.getTabInfo(getTabId())).url) { + this.bgController.addIgnoreUpdateListener(async ({ url, issues }) => { + if (url === (await this.bgController.getTabInfo(this.devtoolsAppController.contentTabId!)).url) { this.setState({ ignoredIssues: issues }); } }) - appController.addLevelFilterListener(() => { + this.devtoolsAppController.addLevelFilterListener(() => { this.setState({}); }) } componentWillUnmount(): void { - devtoolsController.removeReportListener(this.reportListener); + this.devtoolsController.removeReportListener(this.reportListener); } onResetFilters() { - appController.setLevelFilters({ + this.devtoolsAppController.setLevelFilters({ "Violation": true, "Needs review": true, "Recommendation": true, @@ -123,12 +121,12 @@ export class ReportSection extends React.Component issue.value[1] !== "PASS" || issue.ruleId === "detector_tabbable"); } - let url = (await bgController.getTabInfo(getTabId())).url!; - let alreadyIgnored = await bgController.getIgnore(url); + let url = (await this.bgController.getTabInfo(this.devtoolsAppController.contentTabId!)).url!; + let alreadyIgnored = await this.bgController.getIgnore(url); this.setState({ ignoredIssues: alreadyIgnored, report, - canScan: (await bgController.getTabInfo(getTabId()!)).canScan + canScan: (await this.bgController.getTabInfo(this.devtoolsAppController.contentTabId!)).canScan }); } @@ -188,7 +186,7 @@ export class ReportSection extends React.Component { issue.ignored = this.state.ignoredIssues.some(ignoredIssue => issueBaselineMatch(ignoredIssue, issue)); - const checked = appController.getLevelFilters(); + const checked = this.devtoolsAppController.getLevelFilters(); let retVal = ( ((checked["Hidden"] && issue.ignored) || checked[UtilIssue.valueToStringSingular(issue.value) as eFilterLevel]) && (!this.state.focusMode || !this.state.selectedPath @@ -213,8 +211,8 @@ export class ReportSection extends React.Component = []; - for (const key of appController.getLevelFilterKeys()) { - if (appController.getLevelFilter(key)) { + for (const key of this.devtoolsAppController.getLevelFilterKeys()) { + if (this.devtoolsAppController.getLevelFilter(key)) { levelSelectedItems.push(filterItems.find(filtItem => filtItem.text === UtilIssue.singToStringPlural(key))!) } } @@ -275,14 +273,14 @@ export class ReportSection extends React.Component { - let checked = appController.getLevelFilters(); + let checked = this.devtoolsAppController.getLevelFilters(); if (evt.selectedItems != undefined) { checked["Violation"] = evt.selectedItems.some((item: any) => item.text === "Violations"); checked["Needs review"] = evt.selectedItems.some((item: any) => item.text === "Needs review"); checked["Recommendation"] = evt.selectedItems.some((item: any) => item.text === "Recommendations"); checked["Hidden"] = evt.selectedItems.some((item: any) => item.text === "Hidden"); } - appController.setLevelFilters(checked); + this.devtoolsAppController.setLevelFilters(checked); }} /> } @@ -293,7 +291,7 @@ export class ReportSection extends React.Component devtoolsController.exportXLS("last") } + onClick={() => this.devtoolsController.exportXLS("last") } >Export XLS @@ -314,7 +312,7 @@ export class ReportSection extends React.Component { - getDevtoolsAppController().setSecondaryView("kcm_overview"); - getDevtoolsAppController().openSecondary("#kcmInfo"); + this.devtoolsAppController.setSecondaryView("kcm_overview"); + this.devtoolsAppController.openSecondary("#kcmInfo"); }).bind(this)}> @@ -386,7 +384,7 @@ export class ReportSection extends React.Component extends React.Component, ReportTreeGridState> { - private static devtoolsAppController = getDevtoolsAppController(); - private static devtoolsController = getDevtoolsController(); - private static bgcontroller = getBGController(); + private devtoolsAppController = getDevtoolsAppController(); + private devtoolsController = getDevtoolsController(this.devtoolsAppController.toolTabId); + private bgcontroller = getBGController(); private treeGridRef = React.createRef(); state: ReportTreeGridState = { expandedGroups: [], @@ -100,7 +99,7 @@ export class ReportTreeGrid extends React.Component { - ReportTreeGrid.devtoolsController.addSelectedIssueListener(async (issue) => { + this.devtoolsController.addSelectedIssueListener(async (issue) => { for (const group of this.props.rowData!) { for (const groupIssue of group.children) { if (groupIssue.path.dom === issue.path.dom @@ -112,17 +111,17 @@ export class ReportTreeGrid extends React.Component 0) { this.setState({ expandedGroups: this.props.rowData?.map(group => group.id), tabRowId: "tableGridHeader" }); } - ReportTreeGrid.devtoolsController.addViewStateListener(async (viewState: ViewState) => { + this.devtoolsController.addViewStateListener(async (viewState: ViewState) => { this.setState({ viewState }); }) this.setState({ - viewState: (await ReportTreeGrid.devtoolsController.getViewState())! + viewState: (await this.devtoolsController.getViewState())! }) } @@ -222,19 +221,19 @@ export class ReportTreeGrid extends React.Component extends React.Component value.id === focusedElemId); @@ -575,7 +574,7 @@ export class ReportTreeGrid extends React.Component { - getDevtoolsController().setFocusMode(false); + this.devtoolsController.setFocusMode(false); }} >turn off focus view, extends React.Component { + onClick={(evt: any) => { this.onRow(group, thisIssue); - ReportTreeGrid.devtoolsAppController.setSecondaryView("help"); - ReportTreeGrid.devtoolsAppController.openSecondary(`#${rowId} a`); + this.devtoolsAppController.setSecondaryView("help"); + this.devtoolsAppController.openSecondary(`#${rowId} a`); + evt.preventDefault(); }} // onKeyDown={(evt: React.KeyboardEvent) => { // if (evt.key === "Enter" || evt.key === "Return") { // this.onRow(group, thisIssue); - // ReportTreeGrid.devtoolsAppController.openSecondary(`#${rowId} a`); + // this.devtoolsAppController.openSecondary(`#${rowId} a`); // } // }} >Learn more @@ -870,11 +870,11 @@ export class ReportTreeGrid extends React.Component { - let url = (await ReportTreeGrid.bgcontroller.getTabInfo(getTabId())).url!; - ReportTreeGrid.bgcontroller.setIgnore(url, this.state.checkedIssues, ignoreAction !== "Show"); + let url = (await this.bgcontroller.getTabInfo(this.devtoolsAppController.contentTabId!)).url!; + this.bgcontroller.setIgnore(url, this.state.checkedIssues, ignoreAction !== "Show"); this.setState({checkedIssues: []}); - let report = await ReportTreeGrid.devtoolsController.getReport(); - await ReportTreeGrid.devtoolsController.setReport(report); + let report = await this.devtoolsController.getReport(); + await this.devtoolsController.setReport(report); this.props.onFilterToolbar(true); }} >{ignoreAction} diff --git a/accessibility-checker-extension/src/ts/devtools/components/reports/reportReqts.tsx b/accessibility-checker-extension/src/ts/devtools/components/reports/reportReqts.tsx index 93f2c4257..7324f21af 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/reports/reportReqts.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/reports/reportReqts.tsx @@ -21,8 +21,8 @@ import { UtilIssue } from '../../../util/UtilIssue'; import "../reportSection.scss"; import { getBGController } from '../../../background/backgroundController'; -import { getTabId } from '../../../util/tabId'; import { ePanel } from '../../devtoolsController'; +import { getDevtoolsAppController } from '../../devtoolsAppController'; interface ReportProps { unfilteredCount: number @@ -49,8 +49,9 @@ export class ReportReqts extends React.Component { async componentDidMount(): Promise { let bgController = getBGController(); + let appController = getDevtoolsAppController(); let settings = await bgController.getSettings(); - let rulesets = await bgController.getRulesets(getTabId()!); + let rulesets = await bgController.getRulesets(appController.contentTabId!); let ruleset = rulesets.find(policy => policy.id === settings.selected_ruleset.id); if (ruleset) { this.setState({ ruleset }); diff --git a/accessibility-checker-extension/src/ts/devtools/components/scanSection.tsx b/accessibility-checker-extension/src/ts/devtools/components/scanSection.tsx index 95c87cd2f..476253b95 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/scanSection.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/scanSection.tsx @@ -20,7 +20,6 @@ import { IIssue, IReport, UIIssue, eFilterLevel } from '../../interfaces/interfa import { UtilIssue } from '../../util/UtilIssue'; import { UtilIssueReact } from '../../util/UtilIssueReact'; import { getDevtoolsController, ScanningState, ViewState } from '../devtoolsController'; -import { getTabId } from '../../util/tabId'; import { getBGController, issueBaselineMatch, TabChangeType } from '../../background/backgroundController'; import { Button, @@ -45,9 +44,7 @@ import "./scanSection.scss"; import { getDevtoolsAppController } from '../devtoolsAppController'; import { DefinitionTooltip } from '@carbon/react'; import { BrowserDetection } from "../../util/browserDetection"; - -let devtoolsController = getDevtoolsController(); -let bgController = getBGController(); +import { getTabIdAsync } from '../../util/tabId'; interface ScanSectionState { report: IReport | null, @@ -98,6 +95,10 @@ type CountType = { } export class ScanSection extends React.Component<{}, ScanSectionState> { + private devtoolsAppController = getDevtoolsAppController(); + private devtoolsController = getDevtoolsController(this.devtoolsAppController.toolTabId); + private bgController = getBGController(); + state : ScanSectionState = { report: null, selectedPath: null, @@ -132,8 +133,8 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { hasReportContent = true; } // If a scan never started, we can't be done - let url = (await bgController.getTabInfo(getTabId())).url!; - let alreadyIgnored = await bgController.getIgnore(url); + let url = (await this.bgController.getTabInfo(getDevtoolsAppController().contentTabId)).url!; + let alreadyIgnored = await this.bgController.getIgnore(url); self.setState( { ignoredIssues: alreadyIgnored, scanningState: this.state.scanningState !== "idle"? "done" : "idle", @@ -154,63 +155,64 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { async componentDidMount(): Promise { - devtoolsController.addReportListener(this.reportListener); - devtoolsController.addScanningStateListener(async (newState) => { + let tabId = getDevtoolsAppController().contentTabId + this.devtoolsController.addReportListener(this.reportListener); + this.devtoolsController.addScanningStateListener(async (newState) => { this.setState({scanningState: newState }); }); - devtoolsController.addViewStateListener(async (newState) => { + this.devtoolsController.addViewStateListener(async (newState) => { this.setState( { viewState: newState }); }) - devtoolsController.addStoreReportsListener(async (newState) => { + this.devtoolsController.addStoreReportsListener(async (newState) => { this.setState( { storeReports: newState, - storedReportsCount: (await devtoolsController.getStoredReportsMeta()).length + storedReportsCount: (await this.devtoolsController.getStoredReportsMeta()).length }); }) - devtoolsController.addStoredReportsMetaListener(async (newState) => { + this.devtoolsController.addStoredReportsMetaListener(async (newState) => { this.setState( { storedReportsCount: newState.length }); }) - devtoolsController.addSelectedElementPathListener(async (newPath) => { + this.devtoolsController.addSelectedElementPathListener(async (newPath) => { this.setState( { selectedElemPath: newPath }); }) - devtoolsController.addFocusModeListener(async (newValue) => { + this.devtoolsController.addFocusModeListener(async (newValue) => { this.setState({ focusMode: newValue }) }) - bgController.addTabChangeListener(async (content: TabChangeType) => { + this.bgController.addTabChangeListener(async (content: TabChangeType) => { if (content.changeInfo.status) { this.setState({ pageStatus: content.changeInfo.status, scannedOnce: false }); } if (content.changeInfo.status === "complete") { this.setState({ - canScan: (await bgController.getTabInfo(getTabId()!)).canScan + canScan: (await this.bgController.getTabInfo(tabId)).canScan }); } }); - bgController.addIgnoreUpdateListener(async ({ url, issues }) => { - if (url === (await bgController.getTabInfo(getTabId())).url) { + this.bgController.addIgnoreUpdateListener(async ({ url, issues }) => { + if (url === (await this.bgController.getTabInfo(tabId)).url) { this.setState({ ignoredIssues: issues }); } }) - this.reportListener((await devtoolsController.getReport())!); + this.reportListener((await this.devtoolsController.getReport())!); this.setState({ - viewState: (await devtoolsController.getViewState())!, - storeReports: (await devtoolsController.getStoreReports()), - selectedElemPath: (await devtoolsController.getSelectedElementPath())! || "/html", - focusMode: (await devtoolsController.getFocusMode()), - storedReportsCount: (await devtoolsController.getStoredReportsMeta()).length, - canScan: (await bgController.getTabInfo(getTabId()!)).canScan + viewState: (await this.devtoolsController.getViewState())!, + storeReports: (await this.devtoolsController.getStoreReports()), + selectedElemPath: (await this.devtoolsController.getSelectedElementPath())! || "/html", + focusMode: (await this.devtoolsController.getFocusMode()), + storedReportsCount: (await this.devtoolsController.getStoredReportsMeta()).length, + canScan: (await this.bgController.getTabInfo(tabId)).canScan }); } componentWillUnmount(): void { - devtoolsController.removeReportListener(this.reportListener); + this.devtoolsController.removeReportListener(this.reportListener); } async scan() { this.setState( { scannedOnce: true }); - await bgController.requestScan(getTabId()!); + await this.bgController.requestScan({ contentTabId: this.devtoolsAppController.contentTabId!, toolTabId: await getTabIdAsync()}); // The scan is done here so can calc issues found and issue type counts // see newReport in reportListener } @@ -353,19 +355,19 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { {/* devtoolsController.exportXLS("last") } + onClick={() => this.devtoolsController.exportXLS("last") } /> */} { - devtoolsController.setStoreReports(!this.state.storeReports); + this.devtoolsController.setStoreReports(!this.state.storeReports); }} /> devtoolsController.exportXLS("all") } + onClick={() => this.devtoolsController.exportXLS("all") } /> { selectionMode="manual" selectedIndex={this.state.focusMode ? 0 : 1} onChange={(newState: { index: string, name: "All" | "Focused", text: string }) => { - devtoolsController.setFocusMode(newState.name === "Focused"); + this.devtoolsController.setFocusMode(newState.name === "Focused"); }} > { disabled={!this.state.reportContent} iconDescription="Keyboard Checker Mode" tooltipPosition="left" onClick={async () => { - let settings = await bgController.getSettings(); + let settings = await this.bgController.getSettings(); let newState :ViewState = JSON.parse(JSON.stringify(this.state.viewState)); newState.kcm = !newState.kcm; let devtoolsAppController = getDevtoolsAppController(); @@ -438,7 +440,7 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { devtoolsAppController.closeSecondary(); } } - await devtoolsController.setViewState(newState); + await this.devtoolsController.setViewState(newState); }} size="sm" kind="secondary" @@ -495,10 +497,10 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { className= {totalCount === 0 ? "darkLink totalCountDisable" : "darkLink totalCountEnable"} aria-disabled={totalCount === 0} inline={true} - onClick={() => { - let appController = getDevtoolsAppController(); + onClick={(evt: any) => { getDevtoolsAppController().setSecondaryView("summary"); - appController.openSecondary("totalIssuesCount"); + this.devtoolsAppController.openSecondary("totalIssuesCount"); + evt.preventDefault(); }}>{totalCount} issues found @@ -518,7 +520,7 @@ export class ScanSection extends React.Component<{}, ScanSectionState> { this.setState({ confirmClearStored: false }); }).bind(this)} onRequestSubmit={(() => { - devtoolsController.clearStoredReports(); + this.devtoolsController.clearStoredReports(); this.setState({ storedReportsCount: 0, confirmClearStored: false diff --git a/accessibility-checker-extension/src/ts/devtools/components/storedScreen.tsx b/accessibility-checker-extension/src/ts/devtools/components/storedScreen.tsx index 053b508bc..94fe3e0bb 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/storedScreen.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/storedScreen.tsx @@ -34,6 +34,7 @@ import { getDevtoolsController } from "../devtoolsController"; import { BrowserDetection } from '../../util/browserDetection'; import "./storedScreen.scss"; import { BasicTable } from "./BasicTable"; +import { getDevtoolsAppController } from "../devtoolsAppController"; interface IStoredScreenState { storedReports: IStoredReportMeta[] @@ -45,7 +46,8 @@ interface IStoredScreenProps { } export default class StoredScreen extends React.Component { - private devtoolsController = getDevtoolsController(); + private devtoolsAppController = getDevtoolsAppController(); + private devtoolsController = getDevtoolsController(this.devtoolsAppController.toolTabId); state: IStoredScreenState = { storedReports: [] } @@ -154,7 +156,7 @@ export default class StoredScreen extends React.Component scan.id === deleteScan.id); newList.splice(idx, 1); } - await getDevtoolsController().setStoredReportsMeta(newList); + await this.devtoolsController.setStoredReportsMeta(newList); this.setState({ deleteSelectedRows: undefined }); }}> Delete diff --git a/accessibility-checker-extension/src/ts/devtools/components/summaryScreen.tsx b/accessibility-checker-extension/src/ts/devtools/components/summaryScreen.tsx index 21b5903d4..31db3df98 100644 --- a/accessibility-checker-extension/src/ts/devtools/components/summaryScreen.tsx +++ b/accessibility-checker-extension/src/ts/devtools/components/summaryScreen.tsx @@ -25,7 +25,6 @@ import { getBGController } from '../../background/backgroundController'; import { getDevtoolsAppController } from '../devtoolsAppController'; import { BrowserDetection } from '../../util/browserDetection'; - import { getTabId } from '../../util/tabId'; import "./summaryScreen.scss"; interface ISummaryScreenState { @@ -38,34 +37,36 @@ } - let bgController = getBGController(); - let appController = getDevtoolsAppController(); export default class SummaryScreen extends React.Component { - private devtoolsController = getDevtoolsController(); + private devtoolsAppController = getDevtoolsAppController(); + private devtoolsController = getDevtoolsController(this.devtoolsAppController.toolTabId); + private bgController = getBGController(); + private appController = getDevtoolsAppController(); state: ISummaryScreenState = { ignoredIssues: [] } async componentDidMount(): Promise { let self = this; + let contentTabInfo = await this.bgController.getTabInfo(this.appController.contentTabId!); this.devtoolsController.addReportListener(async (newState) => { - let url = (await bgController.getTabInfo(getTabId())).url!; - let alreadyIgnored = await bgController.getIgnore(url); + let url = contentTabInfo.url!; + let alreadyIgnored = await this.bgController.getIgnore(url); self.setState({ ignoredIssues: alreadyIgnored, report: newState, reportMeta: await self.devtoolsController.getReportMeta() || undefined }); }) - appController.addLevelFilterListener(() => { + this.appController.addLevelFilterListener(() => { this.setState({}); }) - bgController.addIgnoreUpdateListener(async ({ url, issues }) => { - if (url === (await bgController.getTabInfo(getTabId())).url) { + this.bgController.addIgnoreUpdateListener(async ({ url, issues }) => { + if (url === contentTabInfo.url) { this.setState({ ignoredIssues: issues }); } }) - let url = (await bgController.getTabInfo(getTabId())).url!; - let alreadyIgnored = await bgController.getIgnore(url); + let url = contentTabInfo.url!; + let alreadyIgnored = await this.bgController.getIgnore(url); this.setState({ ignoredIssues: alreadyIgnored, report: await self.devtoolsController.getReport() || undefined, @@ -148,11 +149,11 @@ { - let checked = appController.getLevelFilters(); + let checked = this.appController.getLevelFilters(); checked["Violation"] = !checked["Violation"]; - appController.setLevelFilters(checked); + this.appController.setLevelFilters(checked); }} >
@@ -167,11 +168,11 @@ { - let checked = appController.getLevelFilters(); + let checked = this.appController.getLevelFilters(); checked["Needs review"] = !checked["Needs review"]; - appController.setLevelFilters(checked); + this.appController.setLevelFilters(checked); }} >
@@ -184,11 +185,11 @@ { - let checked = appController.getLevelFilters(); + let checked = this.appController.getLevelFilters(); checked["Recommendation"] = !checked["Recommendation"]; - appController.setLevelFilters(checked); + this.appController.setLevelFilters(checked); }} >
diff --git a/accessibility-checker-extension/src/ts/devtools/devToolsApp.tsx b/accessibility-checker-extension/src/ts/devtools/devToolsApp.tsx index 888d6f986..3f5841a7c 100644 --- a/accessibility-checker-extension/src/ts/devtools/devToolsApp.tsx +++ b/accessibility-checker-extension/src/ts/devtools/devToolsApp.tsx @@ -54,8 +54,8 @@ interface DevToolsAppState { } export class DevToolsApp extends React.Component { - bgController = getBGController(); - devtoolsAppController = getDevtoolsAppController(); + private bgController = getBGController(); + private devtoolsAppController = getDevtoolsAppController(); state : DevToolsAppState = { secondaryView: "checkerViewAware", diff --git a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts index c5d3dd055..b9d7980bc 100644 --- a/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts +++ b/accessibility-checker-extension/src/ts/devtools/devtoolsAppController.ts @@ -19,7 +19,6 @@ import { getDevtoolsController } from "./devtoolsController"; export type eSecondaryView = "splash" | "summary" | "stored" | "help" | "kcm_overview" | "checkerViewAware"; -let devtoolsController = getDevtoolsController(); export type LevelFilters = { [key in eFilterLevel]: boolean @@ -46,13 +45,16 @@ export class DevtoolsAppController { "Hidden": false }; - constructor() { - getDevtoolsController().addSelectedIssueListener(async () => { + private devToolsController; + + constructor(public toolTabId: number, public contentTabId: number) { + this.devToolsController = getDevtoolsController(toolTabId); + this.devToolsController.addSelectedIssueListener(async () => { if (!this.secondaryOpen) { this.setSecondaryView("help"); } }); - getDevtoolsController().addReportListener(async (report: IReport) => { + this.devToolsController.addReportListener(async (report: IReport) => { if (!report) { this.setSecondaryView("splash"); } @@ -197,7 +199,7 @@ export class DevtoolsAppController { console.error(err); } })($0)`, async (result: string) => { - await devtoolsController.setSelectedElementPath(result, true); + await this.devToolsController.setSelectedElementPath(result, true); }); }); chrome.devtools.inspectedWindow.eval(`inspect(document.documentElement);`); @@ -226,9 +228,11 @@ export class DevtoolsAppController { } let singleton : DevtoolsAppController; -export function getDevtoolsAppController() { - if (!singleton) { - singleton = new DevtoolsAppController(); +export function getDevtoolsAppController(toolTabId?: number, contentTabId?: number) { + if (!singleton && toolTabId && contentTabId) { + singleton = new DevtoolsAppController(toolTabId, contentTabId); + } else if (!singleton) { + throw new Error("Controller not initialized") } return singleton; } diff --git a/accessibility-checker-extension/src/ts/devtools/devtoolsController.ts b/accessibility-checker-extension/src/ts/devtools/devtoolsController.ts index 6132adff6..32331bdee 100644 --- a/accessibility-checker-extension/src/ts/devtools/devtoolsController.ts +++ b/accessibility-checker-extension/src/ts/devtools/devtoolsController.ts @@ -20,7 +20,7 @@ import { CommonMessaging } from "../messaging/commonMessaging"; import { Controller, eControllerType, ListenerType } from "../messaging/controller"; import Config from "../util/config"; import { genReport } from "../util/htmlReport/genReport"; -import { getTabId } from "../util/tabId"; +import { getTabIdSync } from "../util/tabId"; import MultiScanData from "../util/xlsxReport/multiScanReport/xlsx/MultiScanData"; import MultiScanReport from "../util/xlsxReport/multiScanReport/xlsx/MultiScanReport"; @@ -55,6 +55,22 @@ export class DevtoolsController extends Controller { ///// Stored reports functions ///////////////////////////////////////// + /** + * Wait for connection to open + */ + public async awaitConnection(): Promise { + let resp = null; + do { + resp = await this.hook("awaitConnection", null, async () => { + return "OK"; + }) + if (!resp) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + } while (resp === null); + return resp; + } + /** * Get stored reports */ @@ -249,9 +265,8 @@ export class DevtoolsController extends Controller { let bgController = getBGController(); let settings = await bgController.getSettings(); if (report) { - let tabId = getTabId(); - let tabInfo = await bgController.getTabInfo(tabId); - let ignored: IIssue[] = await bgController.getIgnore(tabInfo.url!); + let contentTabInfo = await bgController.getTabInfo(this.contentTabId!); + let ignored: IIssue[] = await bgController.getIgnore(contentTabInfo.url!); let newCounts = await this.getCountsWithHidden(report.counts, report.results, ignored); const now = new Date().getTime(); devtoolsState!.lastReportMeta = { @@ -260,17 +275,17 @@ export class DevtoolsController extends Controller { label: `scan_${this.scanCounter++}`, ruleset: settings.selected_archive.id, guideline: settings.selected_ruleset.id, - pageTitle: tabInfo.title!, - pageURL: tabInfo.url!, - screenshot: await bgController.getScreenshot(tabId), + pageTitle: contentTabInfo.title!, + pageURL: contentTabInfo.url!, + screenshot: await bgController.getScreenshot(this.contentTabId), storedScanData: MultiScanData.issues_sheet_rows({ settings: settings, report: report, ignored: ignored, - pageTitle: tabInfo.title!, - pageURL: tabInfo.url!, + pageTitle: contentTabInfo.title!, + pageURL: contentTabInfo.url!, timestamp: now+"", - rulesets: await bgController.getRulesets(tabId!) + rulesets: await bgController.getRulesets(this.contentTabId!) }), testedUniqueElements: report.testedUniqueElements, counts: newCounts @@ -617,10 +632,12 @@ export class DevtoolsController extends Controller { } private async htmlReportHandler() { + if (!this.contentTabId) { + throw new Error("Cannot call this function directly from remote controllers") + } let bgController = await getBGController(); - let tabId = getTabId(); - let rulesets = await bgController.getRulesets(tabId!); - let tabInfo = await bgController.getTabInfo(getTabId()); + let rulesets = await bgController.getRulesets(this.contentTabId); + let tabInfo = await bgController.getTabInfo(this.contentTabId); if (devtoolsState?.lastReport && rulesets) { let reportObj: any = { tabURL: tabInfo.url, @@ -720,8 +737,8 @@ export class DevtoolsController extends Controller { /////////////////////////////////////////////////////////////////////////// ///// PRIVATE API ///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// - constructor(isContentScript: boolean, type: eControllerType, tabId?: number) { - super(type, { type: "devTools", tabId: (tabId || getTabId())!, relay: isContentScript}, "DT"); + constructor(toolTabId: number, isContentScript: boolean, type: eControllerType, private contentTabId?: number) { + super(type, { type: "devTools", tabId: (toolTabId || getTabIdSync())!, relay: isContentScript}, "DT"); if (type === "local") { let self = this; devtoolsState = { @@ -765,7 +782,8 @@ export class DevtoolsController extends Controller { "DT_exportXLS": async(msgBody) => self.exportXLS(msgBody.content), "DT_setScanningState": async(msgBody) => self.setScanningState(msgBody.content), "DT_setActivePanel": async(msgBody) => self.setActivePanel(msgBody.content), - "DT_getActivePanel": async() => self.getActivePanel() + "DT_getActivePanel": async() => self.getActivePanel(), + "DT_awaitConnection": async() => self.awaitConnection() } // Hook the above definitions @@ -807,15 +825,20 @@ let singletons : { * Get a devtools controller * @param relay * @param type Set to false if sending messages in the same context (e.g., from devtools panel to devtools main) - * @param tabId + * @param toolTabId * @returns */ -export function getDevtoolsController(isContentScript?: boolean, type?: eControllerType, tabId?: number) { - if (!singletons[(tabId || getTabId())!]) { +export function getDevtoolsController(toolTabId: number, isContentScript?: boolean, type?: eControllerType, contentTabId?: number) { + type = type || "remote"; + if (!singletons[toolTabId] && contentTabId) { // console.log("Creating devtools controller", type); - singletons[(tabId || getTabId())!] = new DevtoolsController(isContentScript === true, type || "remote", tabId); + singletons[toolTabId] = new DevtoolsController(toolTabId, isContentScript === true, type, contentTabId); + } else if (!singletons[toolTabId] && type === "remote") { + singletons[toolTabId] = new DevtoolsController(toolTabId, isContentScript === true, type); + } else if (!singletons[toolTabId]) { + throw new Error("Initialization error"); } - return singletons[(tabId || getTabId())!]; + return singletons[toolTabId]; } diff --git a/accessibility-checker-extension/src/ts/devtools/index.tsx b/accessibility-checker-extension/src/ts/devtools/index.tsx index e5829fba2..46aa690e1 100644 --- a/accessibility-checker-extension/src/ts/devtools/index.tsx +++ b/accessibility-checker-extension/src/ts/devtools/index.tsx @@ -15,9 +15,12 @@ *****************************************************************************/ import Config from "../util/config"; +import { getTabIdSync } from "../util/tabId"; import { getDevtoolsController } from "./devtoolsController"; let localStr = (Config.engineEndpoint && Config.engineEndpoint.includes("localhost") && " (local)") || ""; let devStr = (Config.workspace && Config.workspace === "development" && " (dev)") || ""; +let devtoolsController = getDevtoolsController(getTabIdSync()!, false, "local", getTabIdSync()!); + chrome.devtools.panels.elements.createSidebarPane("Accessibility Checker"+devStr+localStr, function(newPanel) { //sidebar initialization code here @@ -42,4 +45,3 @@ chrome.devtools.panels.create("Accessibility Assessment"+devStr+localStr, "", "d } ); -let devtoolsController = getDevtoolsController(false, "local"); diff --git a/accessibility-checker-extension/src/ts/devtools/indexElements.tsx b/accessibility-checker-extension/src/ts/devtools/indexElements.tsx index d96d55a1f..783861392 100644 --- a/accessibility-checker-extension/src/ts/devtools/indexElements.tsx +++ b/accessibility-checker-extension/src/ts/devtools/indexElements.tsx @@ -18,9 +18,26 @@ import * as React from 'react'; import ReactDOM from 'react-dom'; import { DevToolsApp } from './devToolsApp'; import { getDevtoolsAppController } from './devtoolsAppController'; +import { getDevtoolsController } from './devtoolsController'; +import { getTabIdAsync } from '../util/tabId'; -getDevtoolsAppController(); +(async () => { + if (document?.location?.protocol === "chrome-extension:" && document?.location?.search.startsWith("?index=")) { + let index = parseInt(decodeURIComponent(document.location.search.substring("?index=".length))); + let tabRef = (await chrome.tabs.query({ index }))[0]; + let contentTabId = tabRef.id; + let toolTabId = await getTabIdAsync(); + let dtc = getDevtoolsController(toolTabId, false, "local", contentTabId); + getDevtoolsAppController(toolTabId, contentTabId); + await dtc.awaitConnection(); + } else { + let toolTabId = await getTabIdAsync(); + let dtc = getDevtoolsController(toolTabId, false, "remote", toolTabId) + getDevtoolsAppController(toolTabId, toolTabId); + await dtc.awaitConnection(); + } -ReactDOM.render( - , document.getElementById('pageapp-root')); + ReactDOM.render( + , document.getElementById('pageapp-root')); +})(); \ No newline at end of file diff --git a/accessibility-checker-extension/src/ts/devtools/indexMain.tsx b/accessibility-checker-extension/src/ts/devtools/indexMain.tsx index ce4c919b8..067d5702a 100644 --- a/accessibility-checker-extension/src/ts/devtools/indexMain.tsx +++ b/accessibility-checker-extension/src/ts/devtools/indexMain.tsx @@ -18,9 +18,29 @@ import * as React from 'react'; import ReactDOM from 'react-dom'; import { DevToolsApp } from './devToolsApp'; import { getDevtoolsAppController } from './devtoolsAppController'; +import { getDevtoolsController } from './devtoolsController'; +import { getTabIdAsync } from '../util/tabId'; -getDevtoolsAppController(); +(async () => { + if (document?.location?.protocol === "chrome-extension:" && document?.location?.search.startsWith("?index=")) { + let index = parseInt(decodeURIComponent(document.location.search.substring("?index=".length))); + let tabRef = (await chrome.tabs.query({ index }))[0]; + let contentTabId = tabRef.id; + let toolTabId = await getTabIdAsync(); + if (!toolTabId || !contentTabId) { + console.warn("Test initializing", toolTabId, contentTabId); + } + let dtc = getDevtoolsController(toolTabId, false, "local", contentTabId); + getDevtoolsAppController(toolTabId, contentTabId); + await dtc.awaitConnection(); + } else { + let toolTabId = await getTabIdAsync(); + let dtc = getDevtoolsController(toolTabId, false, "remote", toolTabId) + getDevtoolsAppController(toolTabId, toolTabId); + await dtc.awaitConnection(); + } -ReactDOM.render( - , document.getElementById('pageapp-root')); + ReactDOM.render( + , document.getElementById('pageapp-root')); +})(); \ No newline at end of file diff --git a/accessibility-checker-extension/src/ts/messaging/controller.ts b/accessibility-checker-extension/src/ts/messaging/controller.ts index 5680a8404..69788a327 100644 --- a/accessibility-checker-extension/src/ts/messaging/controller.ts +++ b/accessibility-checker-extension/src/ts/messaging/controller.ts @@ -16,7 +16,7 @@ import { IMessage, MsgDestType } from "../interfaces/interfaces"; import Config from "../util/config"; -import { getTabId } from "../util/tabId"; +import { getTabIdAsync } from "../util/tabId"; import { CommonMessaging } from "./commonMessaging"; export type eControllerType = "local" | "remote"; @@ -61,7 +61,7 @@ export class Controller { || (message.dest.type === "background" && this.ctrlDest.type === "background")) { this.notifyEventListeners(msgId, this.ctrlDest.tabId, message.content); } - }, [msgId], getTabId()); + }, [msgId], await getTabIdAsync()); } } @@ -159,7 +159,7 @@ export class Controller { ) { CommonMessaging.addMsgListener((message: IMessage, senderTabId?: number) => { return func(message, senderTabId); - }, msgNames, getTabId()); + }, msgNames, await getTabIdAsync()); } } diff --git a/accessibility-checker-extension/src/ts/options/OptionsApp.tsx b/accessibility-checker-extension/src/ts/options/OptionsApp.tsx index 098ca8727..8b9ca458d 100644 --- a/accessibility-checker-extension/src/ts/options/OptionsApp.tsx +++ b/accessibility-checker-extension/src/ts/options/OptionsApp.tsx @@ -178,7 +178,7 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> { let tabStoredScans = (await getBGController().getSessionState()).tabStoredCount; for (const tabId in tabStoredScans) { if (tabStoredScans[tabId] > 0) { - getDevtoolsController(false, "remote", parseInt(tabId)).clearStoredReports(); + getDevtoolsController(parseInt(tabId), false, "remote").clearStoredReports(); } } this.setState({storedScansExist: false}); diff --git a/accessibility-checker-extension/src/ts/util/tabId.ts b/accessibility-checker-extension/src/ts/util/tabId.ts index 4f745dacb..2e4489b33 100644 --- a/accessibility-checker-extension/src/ts/util/tabId.ts +++ b/accessibility-checker-extension/src/ts/util/tabId.ts @@ -14,10 +14,21 @@ limitations under the License. *****************************************************************************/ -export function getTabId() { +import { getBGController } from "../background/backgroundController"; + +export function getTabIdSync() { if (chrome && chrome.devtools && chrome.devtools.inspectedWindow && chrome.devtools.inspectedWindow.tabId) { return chrome.devtools.inspectedWindow.tabId; } else { return undefined; } +} + +export async function getTabIdAsync() { + let tabId = getTabIdSync(); + if (typeof tabId !== "undefined") { + return tabId; + } else { + return getBGController().getTabId(); + } } \ No newline at end of file diff --git a/accessibility-checker-extension/test/.achecker/baselines/Accessibility Assessment Panel default view is accessible.json b/accessibility-checker-extension/test/.achecker/baselines/Accessibility Assessment Panel default view is accessible.json new file mode 100644 index 000000000..71020a55b --- /dev/null +++ b/accessibility-checker-extension/test/.achecker/baselines/Accessibility Assessment Panel default view is accessible.json @@ -0,0 +1,208 @@ +{ + "results": [ + { + "ruleId": "aria_attribute_valid", + "value": [ + "VIOLATION", + "FAIL" + ], + "path": { + "dom": "/html[1]/body[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[2]/div[2]/div[1]/div[1]/div[2]/a[1]", + "aria": "/document[1]/main[1]/link[1]" + }, + "ruleTime": 0, + "reasonId": "Fail_invalid_implicit_role_attr", + "message": "The ARIA attributes \"aria-disabled\" are not valid for the element with implicit ARIA role \"link\"", + "messageArgs": [ + "aria-disabled", + "a", + "link" + ], + "apiArgs": [], + "bounds": { + "left": 491, + "top": 86, + "height": 19, + "width": 94 + }, + "snippet": "", + "category": "Accessibility", + "ignored": true, + "level": "violation", + "help": "https://able.ibm.com/rules/archives/2024.02.02/doc/en-US/aria_attribute_valid.html#%7B%22message%22%3A%22The%20ARIA%20attributes%20%5C%22aria-disabled%5C%22%20are%20not%20valid%20for%20the%20element%20%3Ca%3E%20with%20implicit%20ARIA%20role%20%5C%22link%5C%22%22%2C%22snippet%22%3A%22%3Ca%20aria-disabled%3D%5C%22true%5C%22%20id%3D%5C%22totalIssuesCount%5C%22%20href%3D%5C%22%230%5C%22%20class%3D%5C%22cds--link%20darkLink%20totalCountDisable%20cds--link--inline%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22Fail_invalid_implicit_role_attr%22%2C%22ruleId%22%3A%22aria_attribute_valid%22%2C%22msgArgs%22%3A%5B%22aria-disabled%22%2C%22a%22%2C%22link%22%5D%7D" + }, + { + "ruleId": "aria_attribute_valid", + "value": [ + "VIOLATION", + "FAIL" + ], + "path": { + "dom": "/html[1]/body[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[4]/div[1]/div[1]/div[2]/div[1]/div[1]", + "aria": "/document[1]/main[1]/generic[1]" + }, + "ruleTime": 0, + "reasonId": "Fail_invalid_implicit_role_attr", + "message": "The ARIA attributes \"aria-label\" are not valid for the element
with implicit ARIA role \"generic\"", + "messageArgs": [ + "aria-label", + "div", + "generic" + ], + "apiArgs": [], + "bounds": { + "left": 34, + "top": 111, + "height": 32, + "width": 160 + }, + "snippet": "
", + "category": "Accessibility", + "ignored": true, + "level": "violation", + "help": "https://able.ibm.com/rules/archives/2024.02.02/doc/en-US/aria_attribute_valid.html#%7B%22message%22%3A%22The%20ARIA%20attributes%20%5C%22aria-label%5C%22%20are%20not%20valid%20for%20the%20element%20%3Cdiv%3E%20with%20implicit%20ARIA%20role%20%5C%22generic%5C%22%22%2C%22snippet%22%3A%22%3Cdiv%20class%3D%5C%22cds--dropdown%20cds--dropdown--disabled%20cds--dropdown--sm%20cds--list-box%20cds--list-box--sm%5C%22%20id%3D%5C%22reportView%5C%22%20aria-label%3D%5C%22Select%20report%20view%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22Fail_invalid_implicit_role_attr%22%2C%22ruleId%22%3A%22aria_attribute_valid%22%2C%22msgArgs%22%3A%5B%22aria-label%22%2C%22div%22%2C%22generic%22%5D%7D" + }, + { + "ruleId": "aria_id_unique", + "value": [ + "VIOLATION", + "FAIL" + ], + "path": { + "dom": "/html[1]/body[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[4]/div[1]/div[1]/div[2]/div[1]/div[1]/div[1]", + "aria": "/document[1]/main[1]/generic[1]/listbox[1]" + }, + "ruleTime": 0, + "reasonId": "Fail_1", + "message": "The 'id' \"downshift-3-label\" specified for the ARIA property 'aria-labelledby' value is not valid", + "messageArgs": [ + "downshift-3-label", + "aria-labelledby", + "div" + ], + "apiArgs": [], + "bounds": { + "left": 35, + "top": 143, + "height": 0, + "width": 158 + }, + "snippet": "
", + "category": "Accessibility", + "ignored": true, + "level": "violation", + "help": "https://able.ibm.com/rules/archives/2024.02.02/doc/en-US/aria_id_unique.html#%7B%22message%22%3A%22The%20'id'%20%5C%22downshift-3-label%5C%22%20specified%20for%20the%20ARIA%20property%20'aria-labelledby'%20value%20is%20not%20valid%22%2C%22snippet%22%3A%22%3Cdiv%20tabindex%3D%5C%22-1%5C%22%20aria-labelledby%3D%5C%22downshift-3-label%5C%22%20role%3D%5C%22listbox%5C%22%20class%3D%5C%22cds--list-box__menu%5C%22%20id%3D%5C%22downshift-3-menu%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22Fail_1%22%2C%22ruleId%22%3A%22aria_id_unique%22%2C%22msgArgs%22%3A%5B%22downshift-3-label%22%2C%22aria-labelledby%22%2C%22div%22%5D%7D" + }, + { + "ruleId": "input_label_exists", + "value": [ + "VIOLATION", + "FAIL" + ], + "path": { + "dom": "/html[1]/body[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[4]/div[1]/div[1]/div[2]/div[1]/div[1]/div[1]", + "aria": "/document[1]/main[1]/generic[1]/listbox[1]" + }, + "ruleTime": 0, + "reasonId": "Fail_2", + "message": "Form control with \"listbox\" role has no associated label", + "messageArgs": [ + "listbox" + ], + "apiArgs": [], + "bounds": { + "left": 35, + "top": 143, + "height": 0, + "width": 158 + }, + "snippet": "
", + "category": "Accessibility", + "ignored": true, + "level": "violation", + "help": "https://able.ibm.com/rules/archives/2024.02.02/doc/en-US/input_label_exists.html#%7B%22message%22%3A%22Form%20control%20with%20%5C%22listbox%5C%22%20role%20has%20no%20associated%20label%22%2C%22snippet%22%3A%22%3Cdiv%20tabindex%3D%5C%22-1%5C%22%20aria-labelledby%3D%5C%22downshift-3-label%5C%22%20role%3D%5C%22listbox%5C%22%20class%3D%5C%22cds--list-box__menu%5C%22%20id%3D%5C%22downshift-3-menu%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22Fail_2%22%2C%22ruleId%22%3A%22input_label_exists%22%2C%22msgArgs%22%3A%5B%22listbox%22%5D%7D" + }, + { + "ruleId": "text_contrast_sufficient", + "value": [ + "VIOLATION", + "FAIL" + ], + "path": { + "dom": "/html[1]/body[1]/div[1]/div[1]/div[1]/div[2]/div[1]/div[1]/h2[1]/div[3]", + "aria": "/document[1]/main[1]/heading[2]" + }, + "ruleTime": 0, + "reasonId": "Fail_1", + "message": "Text contrast of 1.55 with its background is less than the WCAG AA minimum requirements for text of size 12px and weight of 400", + "messageArgs": [ + "1.55", + 12, + 400, + "#c6c6c6", + "#f4f4f4", + false, + false + ], + "apiArgs": [], + "bounds": { + "left": 632, + "top": 116, + "height": 16, + "width": 252 + }, + "snippet": "
", + "category": "Accessibility", + "ignored": false, + "level": "violation", + "help": "https://able.ibm.com/rules/archives/2024.02.02/doc/en-US/text_contrast_sufficient.html#%7B%22message%22%3A%22Text%20contrast%20of%201.55%20with%20its%20background%20is%20less%20than%20the%20WCAG%20AA%20minimum%20requirements%20for%20text%20of%20size%2012px%20and%20weight%20of%20400%22%2C%22snippet%22%3A%22%3Cdiv%20class%3D%5C%22version%5C%22%3E%22%2C%22value%22%3A%5B%22VIOLATION%22%2C%22FAIL%22%5D%2C%22reasonId%22%3A%22Fail_1%22%2C%22ruleId%22%3A%22text_contrast_sufficient%22%2C%22msgArgs%22%3A%5B%221.55%22%2C12%2C400%2C%22%23c6c6c6%22%2C%22%23f4f4f4%22%2Cfalse%2Cfalse%5D%7D" + } + ], + "numExecuted": 1609, + "ruleTime": 548, + "nls": { + "text_contrast_sufficient": { + "0": "The contrast ratio of text with its background must meet WCAG AA requirements", + "Fail_1": "Text contrast of {0} with its background is less than the WCAG AA minimum requirements for text of size {1}px and weight of {2}" + }, + "aria_id_unique": { + "0": "The ARIA property must reference a non-empty unique id of an existing element that is visible", + "Fail_1": "The 'id' \"{0}\" specified for the ARIA property '{1}' value is not valid" + }, + "aria_attribute_valid": { + "0": "ARIA attributes must be valid for the element and ARIA role to which they are assigned", + "Fail_invalid_implicit_role_attr": "The ARIA attributes \"{0}\" are not valid for the element <{1}> with implicit ARIA role \"{2}\"" + }, + "input_label_exists": { + "0": "Each form control must have an associated label", + "Fail_2": "Form control with \"{0}\" role has no associated label" + } + }, + "summary": { + "counts": { + "violation": 1, + "potentialviolation": 14, + "recommendation": 2, + "potentialrecommendation": 5, + "manual": 1, + "pass": 1582, + "ignored": 4, + "elements": 173, + "elementsViolation": 1, + "elementsViolationReview": 15 + }, + "scanTime": 877, + "ruleArchive": "02 February 2024 Deployment (02February2024)", + "policies": [ + "IBM_Accessibility" + ], + "reportLevels": [ + "violation" + ], + "startScan": 1715383969356, + "URL": "chrome-extension://ejlipppldaabbocmlfpncldampfmjdio/devtoolsMain.html?index=1" + }, + "scanID": "36628b44-67df-4a34-9bac-dd54d58c4b4e", + "toolID": "accessibility-checker-v3.1.67", + "label": "Accessibility Assessment Panel default view is accessible" +} \ No newline at end of file diff --git a/accessibility-checker-extension/test/.gitignore b/accessibility-checker-extension/test/.gitignore new file mode 100644 index 000000000..ff5923174 --- /dev/null +++ b/accessibility-checker-extension/test/.gitignore @@ -0,0 +1,3 @@ +dist +.achecker/results +@rerun.txt \ No newline at end of file diff --git a/accessibility-checker-extension/test/achecker.js b/accessibility-checker-extension/test/achecker.js new file mode 100644 index 000000000..7382009a9 --- /dev/null +++ b/accessibility-checker-extension/test/achecker.js @@ -0,0 +1,50 @@ +module.exports = { + // optional - Specify the rule archive + // Default: latest + // Run `npx aat archives` for a list of valid ruleArchive ids and policy ids + ruleArchive: 'versioned', + + // optional - Specify one or many policies to scan. + // Run `npx aat archives` for a list of valid ruleArchive ids and policy ids + policies: ['IBM_Accessibility'], + + // optional - Specify one or many violation levels on which to fail the test + // i.e. If specified violation then the testcase will only fail if + // a violation is found during the scan. + // i.e. failLevels: ["violation"] + // i.e. failLevels: ["violation","potential violation"] or refer to below as a list + // Default: ["violation","potential violation"] + failLevels: ['violation'], + + // optional - Specify one or many violation levels which should be reported + // i.e. If specified violation then in the report it would only contain + // results which are level of violation. + // i.e. reportLevels: ["violation"] + // Valid values: violation, potentialviolation, recommendation, potentialrecommendation, manual + // Default: ["violation","potential violation"] + reportLevels: [ + 'violation' + ], + + // Optional - Which type should the results be outputted to + // Valid values: json, csv + // Default: json + outputFormat: ['json'], + + // Optional - Specify labels that you would like associated to your scan + // + // i.e. + // label: ["Firefox","master","V12","Linux"] + // Default: N/A + label: [], + + // optional - Where the scan results should be saved. + // Default: results + outputFolder: '.achecker/results', + + // optional - Where the baseline results should be loaded from + // Default: baselines + baselineFolder: '.achecker/baselines', + + captureScreenshots: false + }; \ No newline at end of file diff --git a/accessibility-checker-extension/test/cucumber.json b/accessibility-checker-extension/test/cucumber.json new file mode 100644 index 000000000..8e9ac80ab --- /dev/null +++ b/accessibility-checker-extension/test/cucumber.json @@ -0,0 +1,14 @@ +{ + "default": { + "requireModule": ["ts-node/register"], + "require": ["support/**/*.ts"], + "format": [ + "@cucumber/pretty-formatter", + "rerun:@rerun.txt", + "message:dist/cucumber.ndjson", + "json:dist/cucumber.json", + "junit:dist/TEST-cucumber.xml", + "html:dist/cucumber.html" + ] + } + } \ No newline at end of file diff --git a/accessibility-checker-extension/test/features/TC_Assessment.feature b/accessibility-checker-extension/test/features/TC_Assessment.feature new file mode 100644 index 000000000..f424046a4 --- /dev/null +++ b/accessibility-checker-extension/test/features/TC_Assessment.feature @@ -0,0 +1,14 @@ +@e2e +Feature: Accessibility Assessment Panel + + Scenario: default view is accessible + Given "desktop" page "altoro" and panel "assessment" + Then elem ".reportTreeGridEmptyText" text is "This page has not been scanned." + Then page is accessible + + Scenario: altoro scan is accessible + Given "desktop" page "altoro" and panel "assessment" + Then elem ".reportTreeGridEmptyText" text is "This page has not been scanned." + When user activates Button "Scan" + Then elem ".reportTreeGrid #tableGridHeader .gridHeaderCell > span" is visible + Then elem "#totalIssuesCount" text ends with "issues found" \ No newline at end of file diff --git a/accessibility-checker-extension/test/package-lock.json b/accessibility-checker-extension/test/package-lock.json new file mode 100644 index 000000000..8ae3f87ad --- /dev/null +++ b/accessibility-checker-extension/test/package-lock.json @@ -0,0 +1,4457 @@ +{ + "name": "test", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "test", + "version": "1.0.0", + "license": "See LICENCSE.md", + "dependencies": { + "ts-node": "^10.9.2" + }, + "devDependencies": { + "@cucumber/cucumber": "^10.3.1", + "@cucumber/pretty-formatter": "^1.0.0", + "@types/chai": "^4.3.11", + "accessibility-checker": "^3.1.67", + "chai": "^5.0.3", + "puppeteer": "^21.10.0", + "typescript": "^5.3.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cucumber/ci-environment": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/ci-environment/-/ci-environment-10.0.1.tgz", + "integrity": "sha512-/+ooDMPtKSmvcPMDYnMZt4LuoipfFfHaYspStI4shqw8FyKcfQAmekz6G+QKWjQQrvM+7Hkljwx58MEwPCwwzg==", + "dev": true + }, + "node_modules/@cucumber/cucumber": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/@cucumber/cucumber/-/cucumber-10.7.0.tgz", + "integrity": "sha512-8E5vqOIpZOJlRH/aoZc50+yahrObvkbZSxI5WUqM39V3BHNpfzNaPpuLYpSHD2j+gTlubZ8c56RE3Udq38m66g==", + "dev": true, + "dependencies": { + "@cucumber/ci-environment": "10.0.1", + "@cucumber/cucumber-expressions": "17.1.0", + "@cucumber/gherkin": "28.0.0", + "@cucumber/gherkin-streams": "5.0.1", + "@cucumber/gherkin-utils": "9.0.0", + "@cucumber/html-formatter": "21.3.1", + "@cucumber/message-streams": "4.0.1", + "@cucumber/messages": "24.1.0", + "@cucumber/tag-expressions": "6.1.0", + "assertion-error-formatter": "^3.0.0", + "capital-case": "^1.0.4", + "chalk": "^4.1.2", + "cli-table3": "0.6.3", + "commander": "^10.0.0", + "debug": "^4.3.4", + "error-stack-parser": "^2.1.4", + "figures": "^3.2.0", + "glob": "^10.3.10", + "has-ansi": "^4.0.1", + "indent-string": "^4.0.0", + "is-installed-globally": "^0.4.0", + "is-stream": "^2.0.0", + "knuth-shuffle-seeded": "^1.0.6", + "lodash.merge": "^4.6.2", + "lodash.mergewith": "^4.6.2", + "luxon": "3.2.1", + "mkdirp": "^2.1.5", + "mz": "^2.7.0", + "progress": "^2.0.3", + "read-pkg-up": "^7.0.1", + "resolve-pkg": "^2.0.0", + "semver": "7.5.3", + "string-argv": "0.3.1", + "strip-ansi": "6.0.1", + "supports-color": "^8.1.1", + "tmp": "0.2.3", + "type-fest": "^4.8.3", + "util-arity": "^1.1.0", + "xmlbuilder": "^15.1.1", + "yaml": "^2.2.2", + "yup": "1.2.0" + }, + "bin": { + "cucumber-js": "bin/cucumber.js" + }, + "engines": { + "node": "18 || >=20" + }, + "funding": { + "url": "https://opencollective.com/cucumber" + } + }, + "node_modules/@cucumber/cucumber-expressions": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/cucumber-expressions/-/cucumber-expressions-17.1.0.tgz", + "integrity": "sha512-PCv/ppsPynniKPWJr5v566daCVe+pbxQpHGrIu/Ev57cCH9Rv+X0F6lio4Id3Z64TaG7btCRLUGewIgLwmrwOA==", + "dev": true, + "dependencies": { + "regexp-match-indices": "1.0.2" + } + }, + "node_modules/@cucumber/gherkin": { + "version": "28.0.0", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-28.0.0.tgz", + "integrity": "sha512-Ee6zJQq0OmIUPdW0mSnsCsrWA2PZAELNDPICD2pLfs0Oz7RAPgj80UsD2UCtqyAhw2qAR62aqlktKUlai5zl/A==", + "dev": true, + "dependencies": { + "@cucumber/messages": ">=19.1.4 <=24" + } + }, + "node_modules/@cucumber/gherkin-streams": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin-streams/-/gherkin-streams-5.0.1.tgz", + "integrity": "sha512-/7VkIE/ASxIP/jd4Crlp4JHXqdNFxPGQokqWqsaCCiqBiu5qHoKMxcWNlp9njVL/n9yN4S08OmY3ZR8uC5x74Q==", + "dev": true, + "dependencies": { + "commander": "9.1.0", + "source-map-support": "0.5.21" + }, + "bin": { + "gherkin-javascript": "bin/gherkin" + }, + "peerDependencies": { + "@cucumber/gherkin": ">=22.0.0", + "@cucumber/message-streams": ">=4.0.0", + "@cucumber/messages": ">=17.1.1" + } + }, + "node_modules/@cucumber/gherkin-streams/node_modules/commander": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.1.0.tgz", + "integrity": "sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/@cucumber/gherkin-utils": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@cucumber/gherkin-utils/-/gherkin-utils-9.0.0.tgz", + "integrity": "sha512-clk4q39uj7pztZuZtyI54V8lRsCUz0Y/p8XRjIeHh7ExeEztpWkp4ca9q1FjUOPfQQ8E7OgqFbqoQQXZ1Bx7fw==", + "dev": true, + "dependencies": { + "@cucumber/gherkin": "^28.0.0", + "@cucumber/messages": "^24.0.0", + "@teppeis/multimaps": "3.0.0", + "commander": "12.0.0", + "source-map-support": "^0.5.21" + }, + "bin": { + "gherkin-utils": "bin/gherkin-utils" + } + }, + "node_modules/@cucumber/gherkin-utils/node_modules/commander": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", + "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cucumber/html-formatter": { + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/@cucumber/html-formatter/-/html-formatter-21.3.1.tgz", + "integrity": "sha512-M1zbre7e8MsecXheqNv62BKY5J06YJSv1LmsD7sJ3mu5t1jirLjj2It1HqPsX5CQAfg9n69xFRugPgLMSte9TA==", + "dev": true, + "peerDependencies": { + "@cucumber/messages": ">=18" + } + }, + "node_modules/@cucumber/message-streams": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/message-streams/-/message-streams-4.0.1.tgz", + "integrity": "sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA==", + "dev": true, + "peerDependencies": { + "@cucumber/messages": ">=17.1.1" + } + }, + "node_modules/@cucumber/messages": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-24.1.0.tgz", + "integrity": "sha512-hxVHiBurORcobhVk80I9+JkaKaNXkW6YwGOEFIh/2aO+apAN+5XJgUUWjng9NwqaQrW1sCFuawLB1AuzmBaNdQ==", + "dev": true, + "dependencies": { + "@types/uuid": "9.0.8", + "class-transformer": "0.5.1", + "reflect-metadata": "0.2.1", + "uuid": "9.0.1" + } + }, + "node_modules/@cucumber/pretty-formatter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-1.0.1.tgz", + "integrity": "sha512-A1lU4VVP0aUWdOTmpdzvXOyEYuPtBDI0xYwYJnmoMDplzxMdhcHk86lyyvYDoMoPzzq6OkOE3isuosvUU4X7IQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^5.0.0", + "cli-table3": "^0.6.0", + "figures": "^3.2.0", + "ts-dedent": "^2.0.0" + }, + "peerDependencies": { + "@cucumber/cucumber": ">=7.0.0", + "@cucumber/messages": "*" + } + }, + "node_modules/@cucumber/tag-expressions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-6.1.0.tgz", + "integrity": "sha512-+3DwRumrCJG27AtzCIL37A/X+A/gSfxOPLg8pZaruh5SLumsTmpvilwroVWBT2fPzmno/tGXypeK5a7NHU4RzA==", + "dev": true + }, + "node_modules/@fast-csv/format": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", + "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", + "dev": true, + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isboolean": "^3.0.3", + "lodash.isequal": "^4.5.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0" + } + }, + "node_modules/@fast-csv/format/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "dev": true + }, + "node_modules/@fast-csv/parse": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", + "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", + "dev": true, + "dependencies": { + "@types/node": "^14.0.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.groupby": "^4.6.0", + "lodash.isfunction": "^3.0.9", + "lodash.isnil": "^4.0.0", + "lodash.isundefined": "^3.0.1", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/@fast-csv/parse/node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.9.1.tgz", + "integrity": "sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==", + "dev": true, + "dependencies": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "progress": "2.0.3", + "proxy-agent": "6.3.1", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=16.3.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@puppeteer/browsers/node_modules/proxy-agent": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", + "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@teppeis/multimaps": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@teppeis/multimaps/-/multimaps-3.0.0.tgz", + "integrity": "sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@testim/chrome-version": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz", + "integrity": "sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==", + "dev": true + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + }, + "node_modules/@types/chai": { + "version": "4.3.16", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", + "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", + "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/accessibility-checker": { + "version": "3.1.71", + "resolved": "https://registry.npmjs.org/accessibility-checker/-/accessibility-checker-3.1.71.tgz", + "integrity": "sha512-iDXIWxBv06cBfPSILJhB4viSa7FrlYS6FOZwLPSXOrzVlYzJEFpKRRzuBOei0OR0q3ftlvMp+Q9bpds5lTfV+w==", + "dev": true, + "dependencies": { + "axios": "^1.4.0", + "chromedriver": "*", + "deep-diff": "^1.0.2", + "exceljs": "^4.3.0", + "js-yaml": "^4.1.0", + "puppeteer": "^13.0.0", + "string-hash": "^1.1.3" + }, + "bin": { + "achecker": "bin/achecker.js" + } + }, + "node_modules/accessibility-checker/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/accessibility-checker/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/accessibility-checker/node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/accessibility-checker/node_modules/devtools-protocol": { + "version": "0.0.981744", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.981744.tgz", + "integrity": "sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==", + "dev": true + }, + "node_modules/accessibility-checker/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/accessibility-checker/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/accessibility-checker/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/accessibility-checker/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/accessibility-checker/node_modules/puppeteer": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-13.7.0.tgz", + "integrity": "sha512-U1uufzBjz3+PkpCxFrWzh4OrMIdIb2ztzCu0YEPfRHjHswcSwHZswnK+WdsOQJsRV8WeTg3jLhJR4D867+fjsA==", + "deprecated": "< 21.9.0 is no longer supported", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.981744", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "pkg-dir": "4.2.0", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.5.0" + }, + "engines": { + "node": ">=10.18.1" + } + }, + "node_modules/accessibility-checker/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/accessibility-checker/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/accessibility-checker/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dev": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/assertion-error-formatter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz", + "integrity": "sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==", + "dev": true, + "dependencies": { + "diff": "^4.0.1", + "pad-right": "^0.2.2", + "repeat-string": "^1.6.1" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bare-events": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", + "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", + "dev": true, + "optional": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dev": true, + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/chai": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", + "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", + "dev": true, + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dev": true, + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "engines": { + "node": ">= 16" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/chromedriver": { + "version": "124.0.3", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-124.0.3.tgz", + "integrity": "sha512-k6Xu9fwDMgi//bGHB944QMmDHF0BBWGk4PAyVZBEuP6wnZMfQP4V6Sv+l/nuAPA006RllS6X07ZpjPwRPS4BaA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@testim/chrome-version": "^1.1.4", + "axios": "^1.6.7", + "compare-versions": "^6.1.0", + "extract-zip": "^2.0.1", + "proxy-agent": "^6.4.0", + "proxy-from-env": "^1.1.0", + "tcp-port-used": "^1.0.2" + }, + "bin": { + "chromedriver": "bin/chromedriver" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chromium-bidi": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.8.tgz", + "integrity": "sha512-blqh+1cEQbHBKmok3rVJkBlBxt9beKBgOsxbFgs7UJcoVbbeZ+K7+6liAsjgpc8l1Xd55cQUy14fXZdGSb4zIw==", + "dev": true, + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "dev": true + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/compare-versions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==", + "dev": true + }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dev": true, + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/dayjs": { + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-diff": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz", + "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==", + "dev": true + }, + "node_modules/deep-eql": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz", + "integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1232444", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1232444.tgz", + "integrity": "sha512-pM27vqEfxSxRkTMnF+XCmxSEb6duO5R+t8A9DEEJgy4Wz2RVanje2mmj99B6A3zv2r/qGfYlOvYznUhuokizmg==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/exceljs": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", + "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", + "dev": true, + "dependencies": { + "archiver": "^5.0.0", + "dayjs": "^1.8.34", + "fast-csv": "^4.3.1", + "jszip": "^3.10.1", + "readable-stream": "^3.6.0", + "saxes": "^5.0.1", + "tmp": "^0.2.0", + "unzipper": "^0.10.11", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/exceljs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-csv": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", + "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", + "dev": true, + "dependencies": { + "@fast-csv/format": "4.3.5", + "@fast-csv/parse": "4.3.6" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dev": true, + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/glob": { + "version": "10.3.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", + "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-ansi": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-4.0.1.tgz", + "integrity": "sha512-Qr4RtTm30xvEdqUXbSBVWDu+PrTokJOwe/FU+VdfJPk+MXAPoeOzKpRyrDTnZIJwAkQ4oBLTU53nu0HrkF/Z2A==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-regex": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "dev": true + }, + "node_modules/is2": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.9.tgz", + "integrity": "sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "ip-regex": "^4.1.0", + "is-url": "^1.2.4" + }, + "engines": { + "node": ">=v0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/knuth-shuffle-seeded": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz", + "integrity": "sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg==", + "dev": true, + "dependencies": { + "seed-random": "~2.2.0" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "dev": true + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", + "dev": true + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true + }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "dev": true + }, + "node_modules/lodash.isnil": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", + "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.isundefined": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", + "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/loupe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", + "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/luxon": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz", + "integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", + "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "dev": true, + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pad-right": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", + "integrity": "sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g==", + "dev": true, + "dependencies": { + "repeat-string": "^1.5.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "dev": true + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/puppeteer": { + "version": "21.11.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-21.11.0.tgz", + "integrity": "sha512-9jTHuYe22TD3sNxy0nEIzC7ZrlRnDgeX3xPkbS7PnbdwYjl2o/z/YuCrRBwezdKpbTDTJ4VqIggzNyeRcKq3cg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@puppeteer/browsers": "1.9.1", + "cosmiconfig": "9.0.0", + "puppeteer-core": "21.11.0" + }, + "bin": { + "puppeteer": "lib/esm/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=16.13.2" + } + }, + "node_modules/puppeteer-core": { + "version": "21.11.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.11.0.tgz", + "integrity": "sha512-ArbnyA3U5SGHokEvkfWjW+O8hOxV1RSJxOgriX/3A4xZRqixt9ZFHD0yPgZQF05Qj0oAqi8H/7stDorjoHY90Q==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "1.9.1", + "chromium-bidi": "0.5.8", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1232444", + "ws": "8.16.0" + }, + "engines": { + "node": ">=16.13.2" + } + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==", + "deprecated": "This version has a critical bug in fallback handling. Please upgrade to reflect-metadata@0.2.2 or newer.", + "dev": true + }, + "node_modules/regexp-match-indices": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz", + "integrity": "sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ==", + "dev": true, + "dependencies": { + "regexp-tree": "^0.1.11" + } + }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-2.0.0.tgz", + "integrity": "sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/seed-random": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", + "integrity": "sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==", + "dev": true + }, + "node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "node_modules/streamx": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/tar-fs/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tcp-port-used": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz", + "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==", + "dev": true, + "dependencies": { + "debug": "4.3.1", + "is2": "^2.0.6" + } + }, + "node_modules/tcp-port-used/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "dev": true + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-fest": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz", + "integrity": "sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/unzipper/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "dev": true + }, + "node_modules/util-arity": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz", + "integrity": "sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/yup": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.2.0.tgz", + "integrity": "sha512-PPqYKSAXjpRCgLgLKVGPA33v5c/WgEx3wi6NFjIiegz90zSwyMpvTFp/uGcVnnbx6to28pgnzp/q8ih3QRjLMQ==", + "dev": true, + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dev": true, + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dev": true, + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/zip-stream/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + } + } +} diff --git a/accessibility-checker-extension/test/package.json b/accessibility-checker-extension/test/package.json new file mode 100644 index 000000000..f12112f4c --- /dev/null +++ b/accessibility-checker-extension/test/package.json @@ -0,0 +1,24 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "QA for the Accessibilty Checker extension", + "scripts": { + "test": "npm run test:e2e", + "test:all": "./node_modules/.bin/cucumber-js features/**/*.feature --format @cucumber/pretty-formatter", + "test:e2e": "./node_modules/.bin/cucumber-js features/**/*.feature --format @cucumber/pretty-formatter --tags @e2e", + "test:debug": "./node_modules/.bin/cucumber-js features/**/*.feature --format @cucumber/pretty-formatter --tags @debug" + }, + "license": "See LICENCSE.md", + "devDependencies": { + "@cucumber/cucumber": "^10.3.1", + "@cucumber/pretty-formatter": "^1.0.0", + "@types/chai": "^4.3.11", + "accessibility-checker": "^3.1.67", + "chai": "^5.0.3", + "puppeteer": "^21.10.0", + "typescript": "^5.3.3" + }, + "dependencies": { + "ts-node": "^10.9.2" + } +} diff --git a/accessibility-checker-extension/test/support/BrowserWrapper.ts b/accessibility-checker-extension/test/support/BrowserWrapper.ts new file mode 100644 index 000000000..e1e56d482 --- /dev/null +++ b/accessibility-checker-extension/test/support/BrowserWrapper.ts @@ -0,0 +1,141 @@ +import { createHash } from 'crypto'; +import { join } from 'path'; +import {Browser, launch, Page} from 'puppeteer'; +// import {CustomWorld} from './CustomWorld'; + +let one: BrowserWrapper | null = null; + +const PANEL_MAP : { [key: string]: string } = { + "assessment": "/devtoolsMain.html", + "quickGuide": "/quickGuideAC.html", + "userGuide": "/usingAC.html", + "options": "/options.html" +} + +const PAGE_MAP : { [key: string]: {tabId: number, url: string} } = { + "altoro": { + tabId: 1, + url: "https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud" + } +}; + +const MAP1 = "0123456789abcdef"; +const MAP2 = "abcdefghijklmnop"; +const EXTENSION_PATH = join(process.cwd(), "../dist") +const EXTENSION_ID = createHash('sha256') + .update(EXTENSION_PATH) + .digest('hex') + .split("") + .map(ch => MAP2[MAP1.indexOf(ch)]) + .join("") + .substring(0,32); + +export class BrowserWrapper { + browser: Promise | null = null; + tabs: Page[] = []; + homepage: string + + constructor() { + this.homepage = `chrome-extension://${EXTENSION_ID}`; + this.browser = launch({ + headless: process.env.TRAVIS === "true" ? "new" : "new", + ignoreHTTPSErrors: true, + args: [ + `--disable-extensions-except=${EXTENSION_PATH}`, + `--load-extension=${EXTENSION_PATH}`, + '--enable-automation' + ] + }).then(async browser => { + for (const key in PAGE_MAP) { + let p = await browser.newPage(); + await p.goto(PAGE_MAP[key].url); + while (await p.evaluate(() => Promise.resolve(document.readyState)) !== "complete") { + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + await new Promise(resolve => setTimeout(resolve, 3000)); + return browser; + }) + } + + panelKeyToURL(key: string) { + if (key in PANEL_MAP) { + return `${this.homepage}${PANEL_MAP[key]}` + } else { + return null; + } + } + + pageKeyToTabId(key: string) { + if (key in PAGE_MAP) { + return PAGE_MAP[key].tabId; + } else { + return null; + } + } + + pageKeyToTabUrl(key: string) { + if (key in PAGE_MAP) { + return PAGE_MAP[key].url; + } else { + return null; + } + } + + page(): Page { + return this.tabs[this.tabs.length-1]; + } + + async openTab(widthKey: "mobile" | "tablet" | "desktop", url?: string) { + const width = { + "mobile": 400, + "tablet": 800, + "desktop": 1200 + } + const tab = await (await this.browser!).newPage()!; + tab.on('console', async e => { + const args = await Promise.all(e.args().map(a => a.jsonValue())); + console.log(`[${e.type()}]:`,...args); + }); + + // https://github.com/puppeteer/puppeteer/issues/8166 + await tab.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36') + + await tab.setViewport({ + width: width[widthKey], + height: 1080 + }) + if (url) { + await tab.goto(url); + } + this.tabs.push(tab); + return tab; + } + + async closeTab() { + const tab = this.tabs.pop(); + if (tab) { + await tab.close(); + } + } + + async closeBrowser() { + for (const tab of this.tabs) { + try { + await tab.close(); + } catch (err) {} + } + + if (this.browser) { + (await this.browser).close(); + } + this.browser = null; + } + + static get() { + if (!one) { + one = new BrowserWrapper(); + } + return one; + } +} \ No newline at end of file diff --git a/accessibility-checker-extension/test/support/CustomWorld.ts b/accessibility-checker-extension/test/support/CustomWorld.ts new file mode 100644 index 000000000..223f359be --- /dev/null +++ b/accessibility-checker-extension/test/support/CustomWorld.ts @@ -0,0 +1,24 @@ +import {World, IWorldOptions, ITestCaseHookParameter } from '@cucumber/cucumber'; +import { BrowserWrapper } from './BrowserWrapper'; +import { randomUUID } from "crypto"; +// const guuid = randomUUID(); + +export class CustomWorld extends World { + readonly browser: BrowserWrapper; + scenario?: ITestCaseHookParameter; + scenarioData: { [key: string]: string } = {}; + uuid = randomUUID(); + + constructor(options: IWorldOptions) { + super(options); + this.browser = BrowserWrapper.get(); + } + + async init(): Promise { + // await this.browser.newContext(); + } + + async destroy(): Promise { + // See steps_generic After. If the scenario fails, we won't close the context for this scenario + } +} \ No newline at end of file diff --git a/accessibility-checker-extension/test/support/hooks.ts b/accessibility-checker-extension/test/support/hooks.ts new file mode 100644 index 000000000..0b08beada --- /dev/null +++ b/accessibility-checker-extension/test/support/hooks.ts @@ -0,0 +1,10 @@ +import {Before, After} from '@cucumber/cucumber'; +import { CustomWorld } from './CustomWorld'; + +Before(async function(this: CustomWorld) { + await this.init(); +}); + +After(async function(this: CustomWorld) { + await this.destroy(); +}); \ No newline at end of file diff --git a/accessibility-checker-extension/test/support/index.ts b/accessibility-checker-extension/test/support/index.ts new file mode 100644 index 000000000..65c917729 --- /dev/null +++ b/accessibility-checker-extension/test/support/index.ts @@ -0,0 +1,5 @@ +import {setDefaultTimeout, setWorldConstructor} from '@cucumber/cucumber'; +import { CustomWorld } from './CustomWorld'; + +setWorldConstructor(CustomWorld); +setDefaultTimeout(60 * 1000); diff --git a/accessibility-checker-extension/test/support/pages/Page.ts b/accessibility-checker-extension/test/support/pages/Page.ts new file mode 100644 index 000000000..2c0f105a0 --- /dev/null +++ b/accessibility-checker-extension/test/support/pages/Page.ts @@ -0,0 +1,6 @@ +// import { BrowserWrapper } from "../BrowserWrapper"; + +export class Page { + constructor() { + } +} \ No newline at end of file diff --git a/accessibility-checker-extension/test/support/setupAfterEnv.ts b/accessibility-checker-extension/test/support/setupAfterEnv.ts deleted file mode 100644 index 80d564210..000000000 --- a/accessibility-checker-extension/test/support/setupAfterEnv.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { toBeAccessible } from './toBeAccessible'; -expect.extend({ toBeAccessible }); \ No newline at end of file diff --git a/accessibility-checker-extension/test/support/steps/steps_carbon.ts b/accessibility-checker-extension/test/support/steps/steps_carbon.ts new file mode 100644 index 000000000..5d346f708 --- /dev/null +++ b/accessibility-checker-extension/test/support/steps/steps_carbon.ts @@ -0,0 +1,176 @@ +import {When, Then} from '@cucumber/cucumber'; +import {CustomWorld} from '../CustomWorld'; +import { CarbonUtil } from '../util/carbon'; + +/////////////////////////////////////////////////////////////////////////////// +// UIShell +//// +Then(`header name is {string}`, async function(txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.UIShell.header_name_equals(page, txt); +}) + +/////////////////////////////////////////////////////////////////////////////// +// Button +//// + +When(`user activates Button {string}`, async function(txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Button.activate(page, txt); +}) + +Then(`Button {string} exists`, async function(txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Button.exists(page, txt); +}) + +Then(`Button {string} is disabled`, async function(txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Button.isDisabled(page, txt); +}) + +Then(`Button {string} is enabled`, async function(txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Button.isEnabled(page, txt); +}) + +/////////////////////////////////////////////////////////////////////////////// +// DataTable Button +//// +When(`user activates Button {string} in DataTable when column {int} is {string}`, async function(butLabel: string, col: number, txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.DataTable.activateRowButton(page, butLabel, col, txt, true); +}) + +When(`user activates Link {string} in DataTable when column {int} is {string}`, async function(butLabel: string, col: number, txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.DataTable.activateRowLink(page, butLabel, col, txt, true); +}) + +When(`user activates Link {string} in DataTable when column {int} is {string}, skipping search`, async function(butLabel: string, col: number, txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.DataTable.activateRowLink(page, butLabel, col, txt, false); +}) + +When(`user activates Checkbox in DataTable when column {int} is {string}`, async function(col: number, txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.DataTable.activateRowCheckbox(page, col, txt, true); +}) + +/////////////////////////////////////////////////////////////////////////////// +// Dropdown +//// + +When(`user activates Dropdown {string} {string}`, async function(label: string, txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Dropdown.activate(page, label, txt); +}) + +/////////////////////////////////////////////////////////////////////////////// +// Link +//// + +When(`user activates Link {string}`, async function(txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Link.activate(page, txt); +}) + +Then(`Link {string} exists`, async function(txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Link.exists(page, txt); +}) + + +/////////////////////////////////////////////////////////////////////////////// +// Menu +//// + +When(`user activates Menu {string} {string}`, async function(label: string, txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Menu.activate(page, label, txt); +}) + +/////////////////////////////////////////////////////////////////////////////// +// Modal +//// + +Then (`Modal title is {string}`, async function(txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Modal.exists_title(page, txt); +}) + +/////////////////////////////////////////////////////////////////////////////// +// Notification +//// +Then (`Notification {string} exists`, async function (txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Notification.exists_title(page, txt); + +}) +/////////////////////////////////////////////////////////////////////////////// +// Radio +//// + +When (`user selects Radio {string} {string}`, async function(label: string, value: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Radio.select(page, label, value); +}); + +Then (`Radio {string} has value {string}`, async function(label: string, value: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Radio.value_exists(page, label, value); +}); + +Then (`Radio {string} has enabled option {string}`, async function(label: string, value: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Radio.option_enabled(page, label, value); +}); + +Then (`Radio {string} has disabled option {string}`, async function(label: string, value: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Radio.option_disabled(page, label, value); +}); + +/////////////////////////////////////////////////////////////////////////////// +// Tab +//// +When (`user selects Tab {string}`, async function(label: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.Tab.select(page, label); +}); + +/////////////////////////////////////////////////////////////////////////////// +// TextArea +//// +Then(`TextArea {string} exists`, async function(label: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.TextArea.exists(page, label); +}) + +When(`user types into TextArea {string} {string}`, async function (label: string, txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.TextArea.type(page, label, txt); +}); + +/////////////////////////////////////////////////////////////////////////////// +// TextInput +//// +Then(`TextInput {string} exists`, async function(label: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.TextInput.exists(page, label); +}) + +When(`user types into TextInput {string} {string}`, async function (label: string, txt: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.TextInput.type(page, label, txt); +}); + +When(`user clears TextInput {string}`, async function (label: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.TextInput.clear(page, label); +}); + +Then(`TextInput {string} value is {string}`, async function (label: string, value: string) { + const page = (this as CustomWorld).browser.page(); + await CarbonUtil.TextInput.exists_value(page, label, value); +}) diff --git a/accessibility-checker-extension/test/support/steps/steps_generic.ts b/accessibility-checker-extension/test/support/steps/steps_generic.ts new file mode 100644 index 000000000..6db092932 --- /dev/null +++ b/accessibility-checker-extension/test/support/steps/steps_generic.ts @@ -0,0 +1,105 @@ +import {Given, When, Then, After, AfterAll, ITestCaseHookParameter, Before} from '@cucumber/cucumber'; +import {CustomWorld} from '../CustomWorld'; +import { BrowserWrapper } from '../BrowserWrapper'; +import { strict as assert } from "assert"; +import { PupUtil } from "../util/pup"; + +Given("{string} page {string} and panel {string}", async function(widthKey, pageKey, panelKey) { + const browser : BrowserWrapper = this.browser; + const index = browser.pageKeyToTabId(pageKey)!; + const panelUrl = browser.panelKeyToURL(panelKey); + await browser.openTab(widthKey, `${panelUrl}?index=${encodeURIComponent(index)}`); + // assert.strictEqual(false, true, "Test"); +}); + +Then("Banner is loaded", function() { + +}) + +Then('manual step {string}', function (_str: string) { + return 'pending'; +}); + +Then('manual step', function (_docString) { + return 'pending'; +}); + +Then(`page is accessible`, async function() { + const w = this as CustomWorld; + return PupUtil.accessibilityScan(w.browser.page(), this.scenario.gherkinDocument.feature.name+" "+this.scenario.pickle.name); +}); + +Then(`page is accessible with label {string}`, async function(label: string) { + const w = this as CustomWorld; + return PupUtil.accessibilityScan(w.browser.page(), this.scenario.gherkinDocument.feature.name+" "+this.scenario.pickle.name + " " + label); +}); + +When(`user clicks xpath {string}`, async function (xpath) { await PupUtil.xpathClick(this.browser.page(), xpath); }); + +When(`user clicks elem {string}`, async function (elemId) { await PupUtil.elemClick(this.browser.page(), elemId); }); + +When(`user clicks elem {string} and waits for elem {string}`, async function (elemId, waitId) { await PupUtil.elemClick(this.browser.page(), elemId, waitId); }); + +When(`user types into elem {string} {string}`, async function (elemId, text) { await PupUtil.elemType(this.browser.page(), elemId, text); }); + +When(`user types into elem {string} {string} and waits for elem {string}`, async function (elemId, text, waitId) { await PupUtil.elemType(this.browser.page(), elemId, text, waitId); }); + +When(`wait {int}`, async function(ms) { + await PupUtil.wait(ms); +}) + +When (`user closes tab`, async function() { + const b = BrowserWrapper.get(); + b.closeTab(); +}) + +Then(`elem {string} is visible`, async function (elemId) { await PupUtil.elemVisible(this.browser.page(), elemId); }); + +Then(`elem {string} is not visible`, async function (elemId) { await PupUtil.elemNotVisible(this.browser.page(), elemId); }); + +Then(`elem {string} text is {string}`, async function (elemId, text) { + await PupUtil.assertElemTextEquals(this.browser.page(), elemId, text); +}); + +Then(`elem {string} text starts with {string}`, async function (elemId, text) { await PupUtil.assertElemTextStartsWith(this.browser.page(), elemId, text); }); + +Then(`elem {string} text ends with {string}`, async function (elemId, text) { await PupUtil.assertElemTextEndsWith(this.browser.page(), elemId, text); }); + +Then(`fail`, function () { + assert.strictEqual(false, true); +}) + + +Before(async function (scenario: ITestCaseHookParameter) { + const w = this as CustomWorld; + w.scenario = scenario; +}); + +After(async function (scenario) { + const w = this as CustomWorld; + /* enum Status { + UNKNOWN = 0, + PASSED = 1, + SKIPPED = 2, + PENDING = 3, + UNDEFINED = 4, + AMBIGUOUS = 5, + FAILED = 6 + } */ + if (scenario.result?.status === "FAILED") { + if (this.browser.page()) { + let bodyHTML = await this.browser.page().evaluate(() => document.body.innerHTML); + console.error(bodyHTML); + } + } + if (scenario.result?.status === "PASSED" || process.env.TRAVIS === "true") { + await w.browser.closeTab(); + } +}); + +AfterAll(async () => { + const b = BrowserWrapper.get(); + if (b.tabs.length === 0) { + b.closeBrowser(); + } +}) \ No newline at end of file diff --git a/accessibility-checker-extension/test/support/testUtil.ts b/accessibility-checker-extension/test/support/testUtil.ts deleted file mode 100644 index 646a6b1fd..000000000 --- a/accessibility-checker-extension/test/support/testUtil.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from 'react'; -import ReactDOM from 'react-dom'; - -export function setupTest(component: React.ReactElement) { - // JSDom does not implement this and an error was being - // thrown from jest-axe because of it. - const { getComputedStyle } = window; - window.getComputedStyle = (elt) => getComputedStyle(elt); - document.documentElement.setAttribute("lang", "en-US"); - if (!document.querySelector("head title")) { - const title = document.createElement("title"); - title.innerHTML = "Test page"; - document.querySelector("head")?.appendChild(title); - } - document.body.innerHTML = `
`; - ReactDOM.render(component, document.getElementById('testRoot')); -} diff --git a/accessibility-checker-extension/test/support/toBeAccessible.ts b/accessibility-checker-extension/test/support/toBeAccessible.ts deleted file mode 100644 index 6f5ae89ff..000000000 --- a/accessibility-checker-extension/test/support/toBeAccessible.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright IBM Corp. 2019 - * - * This source code is licensed under the Apache-2.0 license found in the - * LICENSE file in the root directory of this source tree. - */ - -'use strict'; - -import { getCompliance, assertCompliance, stringifyResults } from "accessibility-checker"; -import { ICheckerReport } from "accessibility-checker/lib/api/IChecker"; - -declare global { - namespace jest { - interface Matchers { - toBeAccessible: () => CustomMatcherResult; - } - } -} - -export async function toBeAccessible(this: any, node: any) { - let results = await getCompliance(node, this.currentTestName.replace(/[ \\/]/g, "_")); - let pass = assertCompliance(results.report as ICheckerReport) === 0; - return { - pass, - message: () => (pass ? "" : stringifyResults(results.report as ICheckerReport)) - }; -} diff --git a/accessibility-checker-extension/test/support/util/carbon.ts b/accessibility-checker-extension/test/support/util/carbon.ts new file mode 100644 index 000000000..dcb109513 --- /dev/null +++ b/accessibility-checker-extension/test/support/util/carbon.ts @@ -0,0 +1,192 @@ +import { ElementHandle, Page } from "puppeteer"; +import { PupUtil } from "./pup"; + +let UI_MODE: "mouse" | "keyboard" | "touch" = (process.env.UI_MODE || "mouse") as "mouse" | "keyboard" | "touch"; + +export namespace CarbonUtil { + export namespace UIShell { + export async function header_name_equals(page: Page, txt: string) { + await PupUtil.elemVisible(page, `//header[@aria-label="${txt}"]`) + } + } + + export namespace Button { + export async function activate(page: Page, txt: string) { + let src : Page | ElementHandle = page; + try { + let modal = await page.waitForXPath(`//div[contains(@class, 'cds--modal')][contains(@class, 'is-visible')]`, { timeout: 10 }); + if (modal) { + src = modal; + } + } catch (err) { + } + let selector = `//button[text()='${txt}']|//button[@aria-label='${txt}']|//span[contains(@class, 'cds--popover-container')][span[@role='tooltip']/span[text()='${txt}']]//button`; + if (UI_MODE === "mouse") { + await PupUtil.elemClick(src, selector); + } else if (UI_MODE === "keyboard") { + await PupUtil.elemPress(src, selector, "Space"); + } else if (UI_MODE === "touch") { + await PupUtil.elemTap(src, selector); + } + } + + export async function exists(page: Page, txt: string) { + await PupUtil.elemVisible(page, `//button[text()='${txt}']|//button[@aria-label='${txt}']|//span[contains(@class, 'cds--popover-container')][span[@role='tooltip']/span[text()='${txt}']]//button`); + } + + export async function isDisabled(page: Page, txt: string) { + await PupUtil.elemVisible(page, + `//button[text()='${txt}'][contains(@class, 'cds--btn--disabled')]|//button[@aria-label='${txt}'][contains(@class, 'cds--btn--disabled')]`) + } + + export async function isEnabled(page: Page, txt: string) { + await PupUtil.elemVisible(page, + `//button[text()='${txt}'][not(contains(@class, 'cds--btn--disabled'))]|//button[@aria-label='${txt}'][not(contains(@class, 'cds--btn--disabled'))]`) + } + } + + export namespace Dropdown { + export async function activate(scope: Page | ElementHandle, label: string, value: string) { + await PupUtil.elemClick(scope, `//div[label[contains(text(), '${label}')]]/label|//button[@role='combobox'][.//*[@class='cds--list-box__label'][.='${label}']]`); + await PupUtil.elemClick(scope, `//div[label[contains(text(), '${label}')]]//li[.='${value}']|//div[button[@role='combobox'][./span[.='${label}']]]//li[.='${value}']`); + await PupUtil.elemVisible(scope, `//button[@role='combobox'][@title='${value}']`); + } + } + + export namespace Link { + export async function activate(page: Page, txt: string) { + await PupUtil.elemClick(page, `//a[@href][.='${txt}']`); + } + + export async function exists(page: Page, txt: string) { + await PupUtil.elemVisible(page, `//a[@href][.='${txt}']`); + } + + export async function exists_not(page: Page, txt: string) { + await PupUtil.elemNotVisible(page, `//a[@href][.='${txt}']`); + } + } + + export namespace Menu { + export async function activate(page: Page, buttonLabel: string, itemLabel: string) { + await PupUtil.elemClick(page, `//button[@aria-haspopup='true'][translate(text(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='${buttonLabel.toLowerCase()}']|//button[@aria-haspopup='true'][translate(@aria-label,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='${buttonLabel.toLowerCase()}']|//span[contains(@class, 'cds--popover-container')][span[@role='tooltip']/span[translate(text(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='${buttonLabel.toLowerCase()}']]//button[@aria-haspopup='true']`) + await PupUtil.elemClick(page, `//button[@role='menuitem']/div[text()='${itemLabel}']`); + } + + export async function exists(page: Page, txt: string) { + await PupUtil.elemVisible(page, `//button[@role='menuitem']/div[text()='${txt}']`); + } + } + + export namespace Modal { + export async function exists_title(page: Page, txt: string) { + await PupUtil.elemVisible(page, `//h3[contains(@class, 'cds--modal-header__heading')][text()='${txt}']`) + } + } + + export namespace Notification { + export async function exists_title(page: Page, txt: string) { + await PupUtil.elemVisible(page, `//div[role='status']//div[contains(@class, '__title')][text()='${txt}']`) + } + } + + export namespace Radio { + export async function select(scope: Page | ElementHandle, label: string, value: string) { + let labelSelector = label.includes(" ...") ? `starts-with(normalize-space(text()),'${label.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${label}'`; + let valueSelector = value.includes(" ...") ? `starts-with(normalize-space(text()),'${value.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${value}'`; + await PupUtil.elemClick(scope, `//fieldset[legend/span[${labelSelector}]]//div[label/span[${valueSelector}]]/label` + +`|//fieldset[legend[${labelSelector}]]//div[label/span[${valueSelector}]]/label`); + await Radio.value_exists(scope, label, value); + } + + export async function value_exists(scope: Page | ElementHandle, label: string, value: string) { + let labelSelector = label.includes(" ...") ? `starts-with(normalize-space(text()),'${label.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${label}'`; + let valueSelector = value.includes(" ...") ? `starts-with(normalize-space(text()),'${value.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${value}'`; + await PupUtil.elemVisible(scope, `//fieldset[legend/span[${labelSelector}]]//div[label/span[${valueSelector}]]/label` + +`|//fieldset[legend[${labelSelector}]]//div[label/span[${valueSelector}]]/label`); + } + + export async function option_disabled(scope: Page | ElementHandle, label: string, value: string) { + let labelSelector = label.includes(" ...") ? `starts-with(normalize-space(text()),'${label.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${label}'`; + let valueSelector = value.includes(" ...") ? `starts-with(normalize-space(text()),'${value.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${value}'`; + await PupUtil.elemVisible(scope, `//fieldset[legend/span[${labelSelector}]]//div[label/span[${valueSelector}]]//input[@disabled]` + +`|//fieldset[legend[${labelSelector}]]//div[label/span[${valueSelector}]]//input[@disabled]`); + } + + export async function option_enabled(scope: Page | ElementHandle, label: string, value: string) { + let labelSelector = label.includes(" ...") ? `starts-with(normalize-space(text()),'${label.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${label}'`; + let valueSelector = value.includes(" ...") ? `starts-with(normalize-space(text()),'${value.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${value}'`; + await PupUtil.elemVisible(scope, `//fieldset[legend/span[${labelSelector}]]//div[label/span[${valueSelector}]]//input[not(@disabled)]` + +`|//fieldset[legend[${labelSelector}]]//div[label/span[${valueSelector}]]//input[not(@disabled)]`); + } + } + + export namespace DataTable { + // When user activates Button {string} in DataTable when column {int} is {string} + export async function activateRowButton(page: Page, butLabel: string, col: number, txt: string, bSearch: boolean) { + if (bSearch) { + let selector = `//div[contains(@class, "cds--search")]//input`; + await PupUtil.elemType(page, selector, txt); + } + await PupUtil.elemClick(page, `//tr[td[${col+1}][text()='${txt}']]//span[contains(@class, 'cds--popover-container')][span[@role='tooltip']/span[text()='${butLabel}']]//button`) + } + // When user activates Button {string} in DataTable when column {int} is {string} + export async function activateRowLink(page: Page, linkTxt: string, col: number, txt: string, bSearch: boolean) { + let linkSelector = linkTxt.includes(" ...") ? `starts-with(normalize-space(text()),'${linkTxt.replace(/ \.\.\./, "")}')` : `normalize-space(text())='${linkTxt}'`; + if (bSearch) { + let selector = `//div[contains(@class, "cds--search")]//input`; + await PupUtil.elemType(page, selector, txt); + } + await PupUtil.elemClick(page, `//tr[td[${col+1}][.='${txt}']]//a[${linkSelector}]`); + } + // When user activates Checkbox in DataTable when column {int} is {string} + export async function activateRowCheckbox(page: Page, col: number, txt: string, bSearch: boolean) { + if (bSearch) { + let selector = `//div[contains(@class, "cds--search")]//input`; + await PupUtil.elemType(page, selector, txt); + } + await PupUtil.elemClick(page, `//tr[td[${col+1}][.='${txt}']]//input[@type='checkbox']`); + } + } + + export namespace Tab { + export async function select(page: Page, label: string) { + await PupUtil.elemClick(page, `//button[@role='tab'][.='${label}']`); + } + } + + export namespace TextArea { + export async function exists(scope: Page | ElementHandle, label: string) { + await PupUtil.elemVisible(scope, `//div[contains(@class, "cds--form-item")][.//label[.='${label}']]//textarea`) + } + + export async function type(scope: Page | ElementHandle, label: string, text: string) { + let selector = `//div[contains(@class, "cds--form-item")][.//label[.='${label}']]//textarea`; + await PupUtil.elemType(scope, selector, text); + } + } + + export namespace TextInput { + export async function exists(page: Page, label: string) { + await PupUtil.elemVisible(page, `//div[contains(@class, "cds--text-input-wrapper")][.//label[text()='${label}']]//input` + +`|//div[contains(@class, "cds--search")][label[text()='${label}']]//input`) + } + + export async function exists_value(page: Page, label: string, value: string) { + await PupUtil.elemVisible(page, `//div[contains(@class, "cds--text-input-wrapper")][.//label[text()='${label}']]//input` + +`|//div[contains(@class, "cds--search")][label[text()='${label}']]//input[@value='${value}']`) + } + + export async function type(page: Page, label: string, text: string) { + let selector = `//div[contains(@class, "cds--text-input-wrapper")][.//label[text()='${label}']]//input` + +`|//div[contains(@class, "cds--search")][label[text()='${label}']]//input`; + await PupUtil.elemType(page, selector, text); + } + + export async function clear(page: Page, label: string) { + await PupUtil.elemClear(page, `//div[contains(@class, "cds--text-input-wrapper")][.//label[text()='${label}']]//input` + +`|//div[contains(@class, "cds--search")][label[text()='${label}']]//input`); + } + } +} + diff --git a/accessibility-checker-extension/test/support/util/pup.ts b/accessibility-checker-extension/test/support/util/pup.ts new file mode 100644 index 000000000..1b29ab4b2 --- /dev/null +++ b/accessibility-checker-extension/test/support/util/pup.ts @@ -0,0 +1,221 @@ +import { Page, ElementHandle, KeyInput } from "puppeteer"; +import { strict as assert } from "assert"; +import { IBaselineReport, IBaselineResult } from "accessibility-checker/lib/common/engine/IReport"; +import { assertCompliance, getBaseline, getCompliance } from "accessibility-checker"; + + +export namespace PupUtil { + export async function elemVisible(src: Page | ElementHandle, selector: string, bWait?: boolean) { + let retVal: ElementHandle | null; + if (typeof (src as ElementHandle).toElement === "undefined") { + // Dealing with a page root + const page = src as Page; + if (selector.startsWith("//") || selector.startsWith("self:")) { + retVal = await page.waitForXPath(selector, {visible: true}) as ElementHandle; + } else { + retVal = await page.waitForSelector(selector, {visible: true})!; + } + } else { + // Dealing with an element root + const elem = src as ElementHandle + if (selector.startsWith("//")) { + selector = `xpath/.${selector.replace(/\|/g, "|.")}` + retVal = await elem.waitForSelector(selector, {visible: true}); + } else if (selector.startsWith("self:")) { + selector = `xpath/${selector}` + retVal = await elem.waitForSelector(selector, {visible: true}); + } else { + retVal = await elem.waitForSelector(selector, {visible: true})!; + } + } + if (bWait) { + // Wait after detection + await wait(1500); + } + return retVal; + } + + export async function elemNotVisible(page: Page, selector: string) { + try { + if (selector.startsWith("//")) { + await page.waitForXPath(selector, {timeout: 100, visible: true}); + } else { + await page.waitForSelector(selector, {timeout: 100, visible: true}); + } + } catch(err) { + return; + } + assert.strictEqual(false, true); + } + + export async function untilElemNotVisible(page: Page, selector: string) { + let count = 0; + do { + try { + if (selector.startsWith("//")) { + await page.waitForXPath(selector, {timeout: 100, visible: true}); + } else { + await page.waitForSelector(selector, {timeout: 100, visible: true}); + } + } catch(err) { + return; + } + await new Promise(resolve => setTimeout(resolve, 100)); + ++count; + } while (count < 50); + assert.strictEqual(false, true); + } + + export async function pathVisible(page: Page, selector: string) { + if (selector.startsWith("//")) { + return await page.waitForXPath(selector, {visible: true}); + } else { + return await page.waitForSelector(selector, {visible: true}); + } + } + + export async function assertElemTextEquals(page: Page, selector: string, matchText: string) { + let elem = await elemVisible(page, selector)!; + if (elem) { + const content = await page.evaluate((elem) => ((elem as any).value || elem.textContent).trim().replace(/[\u00A0\u1680​\u180e\u2000-\u2009\u200a​\u200b​\u202f\u205f​\u3000]/g,' '), elem); + assert.strictEqual(content, matchText); + } + } + + export async function assertElemTextStartsWith(page: Page, selector: string, matchText: string) { + let elem = await elemVisible(page, selector)!; + if (elem) { + await elemVisible(elem, `self::node()[starts-with(.,'${matchText}')]`); + } + // let content = await page.evaluate((elem) => ((elem as any).value || elem.textContent).trim().replace(/[\u00A0\u1680​\u180e\u2000-\u2009\u200a​\u200b​\u202f\u205f​\u3000]/g,' '), elem); + // content = content.substring(0, matchText.length); + // assert.strictEqual(content, matchText, "Does not start with expected text"); + } + + export async function assertElemTextEndsWith(page: Page, selector: string, matchText: string) { + let elem = await elemVisible(page, selector)!; + if (elem) { + await elemVisible(elem, `self::node()['${matchText}'=substring(., string-length(.)-string-length('${matchText}')+1)]`); + } + // let content = await page.evaluate((elem) => ((elem as any).value || elem.textContent).trim().replace(/[\u00A0\u1680​\u180e\u2000-\u2009\u200a​\u200b​\u202f\u205f​\u3000]/g,' '), elem); + // content = content.substring(0, matchText.length); + // assert.strictEqual(content, matchText, "Does not start with expected text"); + } + + export async function assertElemTextContains(page: Page, selector: string, matchText: string) { + let elem = await elemVisible(page, selector)!; + if (elem) { + let content = await page.evaluate((elem) => ((elem as any).value || elem.textContent).trim().replace(/[\u00A0\u1680​\u180e\u2000-\u2009\u200a​\u200b​\u202f\u205f​\u3000]/g,' '), elem); + const idx = content.indexOf(matchText); + if (idx >= 0) { + content = content.substring(idx, idx+matchText.length); + } + assert.strictEqual(content, matchText, "Does not contain expected text"); + } + } + + export async function elemClick(page: Page | ElementHandle, clickElemSelector: string, waitElemSelector?: string) { + let elem: ElementHandle = await elemVisible(page, clickElemSelector) as any; + await elem.click(); + if (waitElemSelector) { + await elemVisible(page, waitElemSelector); + } + return elem; + } + + export async function elemTap(page: Page | ElementHandle, clickElemSelector: string, waitElemSelector?: string) { + let elem: ElementHandle = await elemVisible(page, clickElemSelector) as any; + if (elem) { + await elem.tap(); + if (waitElemSelector) { + await elemVisible(page, waitElemSelector); + } + } + } + + export async function elemPress(page: Page | ElementHandle, clickElemSelector: string, key: KeyInput, waitElemSelector?: string) { + let elem: ElementHandle = await elemVisible(page, clickElemSelector) as any; + if (elem) { + await elem.press(key); + if (waitElemSelector) { + await elemVisible(page, waitElemSelector); + } + } + } + export async function elemType(page: Page | ElementHandle, elemSelector: string, text: string, waitElemSelector?: string) { + let elem = await elemVisible(page, elemSelector)!; + if (elem) { + await elem.type(text); + if (waitElemSelector) { + await elemVisible(page, waitElemSelector); + } + } + } + + export async function elemClear(page: Page, elemSelector: string, waitElemSelector?: string) { + let elem = await elemVisible(page, elemSelector)! + if (elem) { + await elem.click({ clickCount: 3 }) + await page.keyboard.press('Backspace'); + if (waitElemSelector) { + await elemVisible(page, waitElemSelector); + } + } + } + + export async function elemSelect(page: Page, elemSelector:string, option: string, waitElemSelector?: string) { + let elem = await elemVisible(page, elemSelector)!; + if (elem) { + await elem.select(option); + if (waitElemSelector) { + await elemVisible(page, waitElemSelector); + } + } + } + + export async function xpathClick(page: Page, xpath: string, waitElemSelector?: string) { + let elem = await page.waitForXPath(xpath, {visible: true}) as unknown as HTMLElement; + await elem.click(); + if (waitElemSelector) { + await elemVisible(page, waitElemSelector); + } + } + + export async function wait(num: number) { + return await new Promise((resolve, _reject) => { + setTimeout(() => { + resolve(); + }, num); + }) + } + + function serialize(results: IBaselineResult[]) { + let retVal = ""; + for (const item of results) { + if (item.value[0] === "VIOLATION" && item.value[1] === "FAIL") { + retVal += `${item.message} (${item.path.dom}) + `; + } + } + return retVal; + } + + export async function accessibilityScan(page: Page, fullLabel:string) { + let result = await getCompliance(page, fullLabel); + let report = result.report as IBaselineReport; + if (assertCompliance(report) === 0) { + return + } else { + let baseline = getBaseline(fullLabel); + let message = (baseline ? `${report.summary.counts.violation} accessibility violations + Expected: + ${serialize(baseline.results)} + + ` : `No baseline + + `) + `Actual: + ${serialize(report.results)}`; + assert(report.summary.counts.violation === (baseline ? baseline.summary.counts.violation : 0), message); + } + } +} \ No newline at end of file diff --git a/accessibility-checker-extension/test/tests/HeaderSection.test.tsx b/accessibility-checker-extension/test/tests/HeaderSection.test.tsx deleted file mode 100644 index f45aa330d..000000000 --- a/accessibility-checker-extension/test/tests/HeaderSection.test.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @jest-environment jsdom - */ -'use strict'; -import * as React from 'react'; -import { HeaderSection } from '../../src/ts/devtools/components/headerSection'; -import { setupTest } from '../support/testUtil'; - -// Describe this Suite of testscases, describe is a test Suite and 'it' is a testcase. -describe("HeaderSection", () => { - test("Is accessible", async () => { - setupTest() // - await (expect(document) as any).toBeAccessible(); - }); - // Test the help button and check that it opens the Quick guide. - describe("First button", () => { - test("Label is 'Help'", async () => { - let button = document.body.querySelector("button"); - let labelId = button?.getAttribute("aria-labelledby") || ""; - let label = document.getElementById(labelId); - expect(label?.textContent).toEqual("Help"); - }); - - test("Click opens quickGuideAC.html", async () => { - let button = document.body.querySelector("button"); - // Expect click of the help button to open quickGuideAC.html - window.chrome = { runtime: { - getURL: (url: string) => url - } } as any - - (window as any).open = (url: string, target: string) => { - expect(url).toEqual("quickGuideAC.html"); - expect(target).toEqual("_blank"); - }; - - button!.click(); - }); - }); - - // Test the setting button and check that the option page comes up. - describe("Second button", () => { - test("Label is 'Settings'", async () => { - let button = document.body.querySelectorAll("button")[1]; - let labelId = button?.getAttribute("aria-labelledby") || ""; - let label = document.getElementById(labelId); - expect(label?.textContent).toEqual("Settings"); - }); - - test("Click opens options.html", async () => { - let button = document.body.querySelectorAll("button")[1]; - // Expect click of the help button to open options.html - window.chrome = { runtime: { - getURL: (url: string) => url - } } as any - - (window as any).open = (url: string, target: string) => { - expect(url).toEqual("options.html"); - expect(target).toEqual("_blank"); - }; - - button!.click(); - }); - - - }); -}); diff --git a/accessibility-checker-extension/test/tsconfig.json b/accessibility-checker-extension/test/tsconfig.json new file mode 100644 index 000000000..b922856ed --- /dev/null +++ b/accessibility-checker-extension/test/tsconfig.json @@ -0,0 +1,18 @@ +{ + "include": [ + "support/**/*.ts" + ], + "exclude": [ + "node_modules" + ], + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "resolveJsonModule": true, + "noEmit": true, + "noImplicitAny": true, + "noImplicitReturns": true + } + } \ No newline at end of file diff --git a/package.json b/package.json index 654e69638..773f10b6a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "install:accessibility-checker": "cd accessibility-checker && npm install", "install:karma-accessibility-checker": "cd karma-accessibility-checker && npm install", "install:rule-server": "cd rule-server && npm install", - "install:extension": "cd accessibility-checker-extension && npm install", + "install:extension": "cd accessibility-checker-extension && npm install && cd test && npm install", "install:report": "cd report-react && npm install", "install:cypress-accessibility-checker": "cd cypress-accessibility-checker && npm install", "install:common": "cd common/module && npm install",