├── .github └── workflows │ └── npm-publish.yml ├── .gitignore ├── .prettierrc.json ├── .vscode └── settings.json ├── GitVersion.yml ├── LICENSE ├── README.md ├── cli.js ├── docs ├── code-execute-overlay.png ├── control-bar.png ├── playwright-live-recorder-infographic.png └── playwright-test-play-button.png ├── example ├── PW_selectorConventions.js └── live-recorder.config.ts ├── package.json ├── src ├── browser │ ├── PW_live.css │ ├── PW_live.js │ └── PW_selectorConventions.js ├── hotModuleReload.ts ├── main.ts ├── pageObjectModel.ts ├── recorder.ts ├── testFileWriter.ts ├── types.d.ts └── utility.ts ├── tests ├── example-test-project │ ├── docs │ │ └── intro_page.ts │ ├── example.spec.after.ts │ ├── example.spec.before.ts │ └── testHelpers.ts ├── hotModuleReload.test.ts └── pageObjectModel.test.ts ├── tsconfig.json ├── tslint.json ├── vitest.config.ts └── yarn.lock /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: Node.js Package 5 | 6 | on: 7 | push: 8 | branches: 9 | - 'main' 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | with: 17 | # Get all history for version calculation 18 | fetch-depth: 0 19 | - uses: actions/setup-node@v3 20 | with: 21 | node-version: lts/* 22 | registry-url: 'https://registry.npmjs.org' 23 | scope: '@dnvgl' 24 | - name: Install GitVersion 25 | uses: gittools/actions/gitversion/setup@v0.9.7 26 | with: 27 | versionSpec: '5.x' 28 | - name: Determine Version 29 | uses: gittools/actions/gitversion/execute@v0.9.7 30 | with: 31 | useConfigFile: true 32 | - run: yarn version --new-version $GITVERSION_SEMVER --no-git-tag-version 33 | - run: yarn install --frozen-lockfile 34 | - run: yarn build 35 | - run: yarn publish --access public 36 | env: 37 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | dnvgl-playwright-live-recorder-*.tgz 4 | coverage/ -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 210 3 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "testing.automaticallyOpenPeekView": "never" 3 | } -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | mode: Mainline 2 | increment: Patch 3 | branches: {} 4 | ignore: 5 | sha: [] 6 | merge-message-formats: {} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 DNV open source 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### v2.0.59 2 | * added basic support for #16 `Support 'global' page object` and #3 `support nested page object models` 3 | 4 | ### v2.0.57 5 | * updated readme, recorded demo video 6 | 7 | ### v2.0.56 8 | * cli command fix 9 | 10 | ### v2.0.53 11 | * Display currently executing lines of code in repl on-screen 12 | * fix many issues after page navigation (tool only worked for SPAs previously) 13 | * changed (broken) postinstall to cli command `npx @dnvgl/playwright-live-recorder` 14 | 15 | ### v2.0.52 16 | * UI rework 17 | * Now aware of Page Object Model helper methods 18 | 19 | ### v2.0.48 20 | * Live code execution method much simplified and much more robust (todo: write tech doc about this) 21 | * bugfix: Make page object model tools build correct paths on non-windows filesystems 22 | 23 | ---- 24 | 25 | 26 | ![Playwright live recorder infographic](docs/playwright-live-recorder-infographic.png "Playwright live recorder infographic") 27 | 28 | 29 | # Getting Started 30 | 31 | ## Watch the video demonstration 32 | 33 | [![Getting Started](https://i.ytimg.com/vi/ys5vczHm9sw/maxresdefault.jpg)](https://youtu.be/ys5vczHm9sw) 34 | 35 | 36 | ----- 37 | ## Prerequisites 38 | 39 | `@playwright/test` (typescript) 40 | 41 | start with a repo with @playwright/test set up, if starting with a new repo see https://playwright.dev/docs/intro 42 | 43 | ## Install 44 | 45 | ``` bash 46 | npm install -D @dnvgl/playwright-live-recorder 47 | #or 48 | yarn add -D @dnvgl/playwright-live-recorder 49 | #or 50 | pnpm add -D @dnvgl/playwright-live-recorder 51 | ``` 52 | 53 | run the setup script 54 | ``` bash 55 | npx @dnvgl/playwright-live-recorder 56 | ``` 57 | 58 | Ensure baseURL is set to the root url of your webapp in `playwright.config.ts` e.g. 59 | ``` ts 60 | //playwright.config.ts 61 | export default defineConfig({ 62 | //... 63 | use: { 64 | baseURL: 'https://demo.playwright.dev/todomvc/#/', 65 | //... 66 | ``` 67 | 68 | # How to use 69 | ## Typescript Code for test 70 | 71 | In a playwright test, add the import 72 | ``` ts 73 | import { PlaywrightLiveRecorder } from '@dnvgl/playwright-live-recorder'; 74 | ``` 75 | 76 | and then add this await line at the end of the playwright test you want to record into 77 | ``` ts 78 | // note - recorded lines will be inserted here 79 | await PlaywrightLiveRecorder.start(page, s => eval(s)); 80 | ``` 81 | 82 | Run the test in headed mode 83 | 84 | > 💡 if you're using the vscode plugin `ms-playwright.playwright` it will automatically run in headed mode with PWDEBUG set to console (see modifications to `.vscode/settings.json`) 85 | > 💡 if you're running from the command line, set the environment variable `PWDEBUG=console` before running the playwright command, e.g. `playwright test --ui` 86 | 87 | Test will run, when `PlaywrightLiveRecorder.start` line is executed lib functionality will be exposed to the browser and all scripts will be loaded in the browser. Test execution waits until browser is closed. 88 | Newly recorded test lines are inserted into test file. 89 | Newly added page object model files will be created, newly added items are inserted into the page object model files. 90 | Newly added or modified test lines above `PlaywrightLiveRecorder.start` are executed upon file save. 91 | 92 | ## Browser 93 | 94 | > ![Playwright live recorder sticky bar](docs/control-bar.png "Playwright live recorder sticky bar") 95 | > Playwright live recorder adds a control bar to the top of the browser page. 96 | > * Record mode ⚪/🔴 can be toggled off/on by clicking the icon, or pressing CTRL+ALT+SHIFT+R 97 | > * The label is the page object model path+filename 98 | > * the f(x) button displays public helper functions available from your page object model file, click the green ➕ to add an example to the file 99 | > 100 | > When record is toggled on a hover tooltip is positioned next to the cursor showing the code that will be generated 101 | >> 💡 if the recorder blocks your testing session, work past it by toggling record off, clicking, then toggling it back on 102 | 103 | ## **Recording** 104 | > With record toggled on, click an element to add it to your test 105 | > * If the element is not part of the Page Object Model, you will be prompted to give it a name 106 | > * Press enter and the new property will be added to the page object model file, and the element will highlight (default: salmon color), to indicate it's a part of the page object model 107 | > * Press [esc] to skip adding to the page object model 108 | > * If the element is part of the Page Object Model, it will already be highlighted salmon color 109 | > * Clicking it will add a call to the page object model method to your test 110 | > 111 | > After clicking an element, the test code will be added and saved to your test file. File changes are automatically re-executed. 112 | > You can always modify the text code and save to re-execute changed lines. 113 | >> 💡 This is useful to change a `.click()` call to a `.fill()`, or to wrap an `expect` around the element you just clicked. Save the file and it's re-executed. 114 | >> Another powerful workflow is to edit the page object model function, save the file, and then add the same line again to the test file to force a re-execute 115 | >> You can keep iterating this way until the function implementation is correct. 116 | > 117 | > 💡 whenever code lines are executed in the test they'll display overlayed on-screen 118 | > ![code execute overlay](docs/code-execute-overlay.png "code execute overlay") 119 | 120 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | console.log('Running install script...'); 4 | 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | 8 | 9 | function findProjectRoot() { 10 | let currentDir = process.cwd(); 11 | while (!fs.existsSync(path.join(currentDir, 'package.json'))) { 12 | const parentDir = path.resolve(currentDir, '..'); 13 | if (parentDir === currentDir) throw new Error('Could not find project root'); 14 | currentDir = parentDir; 15 | } 16 | return currentDir; 17 | } 18 | 19 | const projectRoot = findProjectRoot(); 20 | process.chdir(projectRoot); 21 | 22 | // Copy dist/example file to project root 23 | const packageExamplesPath = path.resolve(path.dirname(require.resolve('@dnvgl/playwright-live-recorder')), 'example/'); 24 | for (const file of fs.readdirSync(packageExamplesPath)) { 25 | try { 26 | fs.copyFileSync(path.resolve(packageExamplesPath, file), path.resolve(projectRoot, file), fs.constants.COPYFILE_EXCL); 27 | console.log(`Copied example file ${file} to project root`); 28 | } catch (e) { 29 | if (e.code !== 'EEXIST') console.warn(`error copying file ${file} to ${projectRoot}`, e); 30 | } 31 | } 32 | 33 | // Create or modify /.vscode/settings.json 34 | const vscodeDir = path.join(process.cwd(), '.vscode'); 35 | const settingsFile = path.join(vscodeDir, 'settings.json'); 36 | 37 | if (!fs.existsSync(vscodeDir)) fs.mkdirSync(vscodeDir); 38 | const settings = fs.existsSync(settingsFile) ? JSON.parse(fs.readFileSync(settingsFile, 'utf8')) : {}; 39 | if (!settings['playwright.env']) settings['playwright.env'] = { 'PWDEBUG': 'console' }; 40 | fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2)); 41 | console.log(`Updated settings at: ${settingsFile}`); 42 | 43 | // Create or modify ./tests/package.json 44 | const testsDir = path.join(process.cwd(), 'tests'); 45 | const testsPackageFile = path.join(testsDir, 'package.json'); 46 | 47 | if (!fs.existsSync(testsDir)) fs.mkdirSync(testsDir); 48 | const testsPackage = fs.existsSync(testsPackageFile) ? JSON.parse(fs.readFileSync(testsPackageFile, 'utf8')) : {}; 49 | testsPackage.type = 'module'; 50 | fs.writeFileSync(testsPackageFile, JSON.stringify(testsPackage, null, 2)); 51 | console.log(`Updated tests package at: ${testsPackageFile}`); -------------------------------------------------------------------------------- /docs/code-execute-overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnv-opensource/playwright-live-recorder/993a7b87fc3fba16ade2ceddcab0a46a13dd4b5e/docs/code-execute-overlay.png -------------------------------------------------------------------------------- /docs/control-bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnv-opensource/playwright-live-recorder/993a7b87fc3fba16ade2ceddcab0a46a13dd4b5e/docs/control-bar.png -------------------------------------------------------------------------------- /docs/playwright-live-recorder-infographic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnv-opensource/playwright-live-recorder/993a7b87fc3fba16ade2ceddcab0a46a13dd4b5e/docs/playwright-live-recorder-infographic.png -------------------------------------------------------------------------------- /docs/playwright-test-play-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dnv-opensource/playwright-live-recorder/993a7b87fc3fba16ade2ceddcab0a46a13dd4b5e/docs/playwright-test-play-button.png -------------------------------------------------------------------------------- /example/PW_selectorConventions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * PW_selectorConventions contract: 3 | * array of { match(el) => resultType | undefined, output(x: resultType) => code: string, isPageObjectModel: boolean} 4 | * notes: 5 | * match(el) => null/undefined inidicates not a match 6 | * rules are evaluated in order (top to bottom) 7 | * currently hovered element is passed into each match 8 | */ 9 | 10 | /* var PW_selector_pageObjectModel_conventions = [ 11 | { 12 | match: el => el.closest('[data-page-object-model]')?.getAttribute('data-page-object-model'), 13 | isPageObjectModel: true, 14 | }, 15 | ]; 16 | 17 | var PW_selectorConventions = [ 18 | { 19 | match: el => { 20 | const dataTestId = el.closest('[data-testid]')?.getAttribute('data-testid') 21 | return dataTestId ? `[data-testid="${dataTestId}"]` : undefined; 22 | }, 23 | } 24 | ]; 25 | 26 | var PW_selector_base_conventions = [ 27 | { 28 | match: (el) => playwright.selector(el) 29 | }, 30 | ]; 31 | */ -------------------------------------------------------------------------------- /example/live-recorder.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightLiveRecorderConfigFile } from '@dnvgl/playwright-live-recorder'; 2 | 3 | const recorderConfig: PlaywrightLiveRecorderConfigFile = { 4 | /* overrides go here */ 5 | }; 6 | 7 | export default recorderConfig; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dnvgl/playwright-live-recorder", 3 | "type": "commonjs", 4 | "version": "2.0.58", 5 | "description": "Adds live coding in testing context from browser console when running tests. Provides programmatically configurable recorder. Introduces the idea of strong convention for Page Object Model", 6 | "main": "dist/main.js", 7 | "files": [ 8 | "dist/**/*.*", 9 | "cli.js" 10 | ], 11 | "bin": { 12 | "playwright-live-recorder": "./cli.js" 13 | }, 14 | "repository": "https://github.com/dnv-opensource/playwright-live-recorder", 15 | "author": "DNV", 16 | "license": "MIT", 17 | "private": false, 18 | "scripts": { 19 | "build": "tslint -p . && tsc && npx cpx \"src/**/*.{js,css,d.ts}\" dist && npx cpx \"example/**/*.*\" dist/example", 20 | "test": "vitest" 21 | }, 22 | "devDependencies": { 23 | "@playwright/test": "^1.0.0", 24 | "@types/async-lock": "^1.3.0", 25 | "@types/lodash": "^4.14.185", 26 | "@types/node": "^22.10.5", 27 | "cpx": "^1.5.0", 28 | "tslint": "^6.1.3", 29 | "vitest": "^2.1.8" 30 | }, 31 | "dependencies": { 32 | "async-lock": "^1.3.2", 33 | "chokidar": "^3.5.3", 34 | "error-stack-parser": "^2.1.4", 35 | "lodash": "^4.17.21", 36 | "ts-morph": "^16.0.0", 37 | "ts-node": "^10.9.2", 38 | "typescript": "^4.8.2" 39 | }, 40 | "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72" 41 | } 42 | -------------------------------------------------------------------------------- /src/browser/PW_live.css: -------------------------------------------------------------------------------- 1 | .PW { position: fixed; z-index: 2147483647; top: 0; width: 100%; pointer-events: none; } 2 | .PW-statusbar { margin: 0px auto; border-radius: 0px 0px 4px 4px; border:1px #333 solid; padding:0; border-top:0; display: inline-block; background: white; opacity:0.9; pointer-events: auto; } 3 | .PW-statusbar > div { display:flex ;min-width:15ch; justify-content:space-around; margin: 0 0 -6px 0; border-bottom: 1px solid #ccc } 4 | 5 | #PW-drag-element { user-select:none; font-size:24px; margin:-2px -4px -4px -4px; height:30px; cursor:grab; } 6 | 7 | .PW-tooltip { position: fixed; left: 0; top: 0; padding: 4px; background: LavenderBlush; outline: 1px solid black; border-radius: 4px; z-index: 2147483647; visibility: hidden; } 8 | 9 | .PW-page-object-model-overlay { position: relative; background-color: #ff8080; opacity: 0.7; z-index: 2147483646; width: 100%; height: 100%; } 10 | 11 | /* checkbox red dot styling */ 12 | .PW-checkbox-recording { margin:0 -4px -8px -4px; display:flex; align-items:center; } 13 | .PW-checkbox-recording input[type=checkbox] { visibility: collapse; width: 0; height: 0; } 14 | .PW-checkbox-recording input[type=checkbox]:checked+label { background: #d00; box-shadow: 0 0 3px #f00; } 15 | .PW-checkbox-recording label { display: block; top: 0; left: 0; width: 18px; height: 18px; border-radius: 50%; cursor: pointer; position: relative; background: #111; } 16 | 17 | .PW-pre { background: #333; color: white; margin: 0; text-align: left; } 18 | 19 | /* dropdown menu for methods */ 20 | .dropdown__category, 21 | .dropdown__menu { display: flex; list-style: none; padding: 0; margin: 0; position: relative; } 22 | 23 | .dropdown__category .dropdown__menu { display: none; } 24 | .dropdown__category:hover .dropdown__menu { display: block; } 25 | .dropdown__category .dropdown__menu { position: absolute; top: 35px; left: 0; } 26 | .dropdown__category li { padding: 0 4px; position: relative; } 27 | .dropdown__menu li { padding: 10px; position: relative; background: white; } 28 | .dropdown__category li:hover { background: #ccc; } 29 | 30 | 31 | /* Toast */ 32 | 33 | #PW_PLR_toast { display: flex; width: 100%; border-radius: 2px; position: fixed; z-index: 2147483647; left: 0; right:0; bottom: 30px; opacity: 0; transition: opacity 0.3s ease } 34 | #PW_PLR_toast.show { opacity: 0.95; } 35 | #PW_PLR_toast #PW_PLR_toast_img { box-sizing: border-box; background-color: #333; color: #fff; font-size: 16px; width: 20px; } 36 | #PW_PLR_toast #PW_PLR_toast_desc { background: #333; color: #fff; width: 100%; font-size: 16px; } 37 | 38 | 39 | /* loader */ 40 | .PW_PLR_loader { border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; width: 18px; height: 18px; animation: spin 1s linear infinite; } 41 | @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } -------------------------------------------------------------------------------- /src/browser/PW_live.js: -------------------------------------------------------------------------------- 1 | /******** UI Elements ********/ 2 | 3 | if (window.PW_statusbar) PW_statusbar.remove(); 4 | window.PW_statusbar = document.createElement("div"); 5 | PW_statusbar.classList.add("PW"); 6 | 7 | PW_statusbar.innerHTML = ` 8 |
9 |
10 |
11 | ⋮⋮ 12 | 13 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | Playwright Live Recorder 26 |
27 | 28 |
icon
message...
29 |
30 | `; 31 | 32 | document.body.prepend(PW_statusbar); 33 | 34 | window.PW_page_object_model_filename = document.getElementById("PW-page-object-model-filename"); 35 | window.PLR_pom_methods_dropdown = document.getElementById("PLR_pom_methods_dropdown"); 36 | 37 | var PLR_dragElement = document.getElementById('PW-drag-element'); 38 | var PLR_statusBar = document.getElementById('PW-statusbar'); 39 | 40 | var _pw_drag_startX, pw_drag_initialTransformX; 41 | 42 | PLR_dragElement.addEventListener('mousedown', (event) => { 43 | const tx = PLR_statusBar.style.transform; 44 | pw_drag_initialTransformX = parseInt(tx.substring(tx.indexOf('(') + 1, tx.indexOf('px')), 10); 45 | if (isNaN(pw_drag_initialTransformX)) pw_drag_initialTransformX = 0; 46 | 47 | _pw_drag_startX = event.clientX; 48 | 49 | document.addEventListener('mousemove', onMouseMove); 50 | document.addEventListener('mouseup', onMouseUp); 51 | 52 | PLR_dragElement.style.cursor = 'grabbing'; 53 | }); 54 | 55 | function onMouseMove(event) { 56 | const currentX = event.clientX; 57 | const deltaX = currentX - _pw_drag_startX; 58 | PLR_statusBar.style.transform = `translateX(${deltaX + pw_drag_initialTransformX}px)`; 59 | } 60 | 61 | function onMouseUp() { 62 | document.removeEventListener('mousemove', onMouseMove); 63 | document.removeEventListener('mouseup', onMouseUp); 64 | 65 | PLR_dragElement.style.cursor = 'grab'; 66 | } 67 | 68 | if (window.PW_tooltip) PW_tooltip.remove(); 69 | var PW_tooltip = document.createElement("div"); 70 | PW_tooltip.setAttribute("id", "PW_tooltip"); 71 | PW_tooltip.classList.add("PW-tooltip"); 72 | document.body.appendChild(PW_tooltip); 73 | window.PW_tooltip = PW_tooltip; 74 | 75 | /******** behavior ********/ 76 | 77 | if (window.PW_pages === undefined) window.PW_pages = {}; 78 | var mouse_x = 0; 79 | var mouse_y = 0; 80 | 81 | if (recordModeOn === undefined) var recordModeOn = false; 82 | PW_config().then((c) => { 83 | window.config = c; 84 | //functions serialize through as text, try to create them as functions once again 85 | config.pageObjectModel.overlay.on = eval(config.pageObjectModel.overlay.on); 86 | config.pageObjectModel.overlay.off = eval(config.pageObjectModel.overlay.off); 87 | config.pageObjectModel.generatePropertyTemplate = eval(config.pageObjectModel.generatePropertyTemplate); 88 | config.pageObjectModel.generateMethodTemplate = eval(config.pageObjectModel.generateMethodTemplate); 89 | }); 90 | 91 | function keyChord_toggleRecordMode(event) { 92 | if (!(event.ctrlKey && event.altKey && event.shiftKey && event.key === "R")) return; 93 | 94 | const chkbox = document.getElementById("PW-record-checkbox"); 95 | chkbox.checked = !chkbox.checked; //this doesn't fire the changed event handler, so call toggleRecordMode manually 96 | toggleRecordMode(chkbox.checked); 97 | } 98 | 99 | function toggleRecordMode(checked) { 100 | recordModeOn = checked; 101 | 102 | if (recordModeOn) { 103 | updateTooltipPosition(mouse_x, mouse_y); 104 | const element = document.elementFromPoint(mouse_x, mouse_y); 105 | updateTooltipContents(element); 106 | window.PW_tooltip.style.visibility = "visible"; 107 | if (config.pageObjectModel.enabled) { 108 | reload_page_object_model_elements(); 109 | } 110 | } else { 111 | window.PW_tooltip.style.visibility = "hidden"; 112 | if (config.pageObjectModel.enabled) { 113 | clearPageObjectModelElements(); 114 | } 115 | } 116 | } 117 | 118 | function updateTooltipContents(element) { 119 | const convention = PW_getSelectorConventionForElement(element); 120 | if (convention == undefined) return; 121 | 122 | const matcher = convention.match(element); 123 | if (matcher == undefined) return; 124 | 125 | if (!convention.isPageObjectModel) { 126 | PW_tooltip.innerText = typeof matcher === "string" ? matcher : JSON.stringify(matcher, undefined, "\t"); 127 | } else { 128 | const primaryAction = element.closest('[data-page-object-model-primary-action]').getAttribute("data-page-object-model-primary-action"); 129 | if (primaryAction == undefined) return; 130 | 131 | //todo - secondary actions 132 | //const secondaryActions = element.closest('[data-page-object-model-secondary-actions]').getAttribute("data-page-object-model-secondary-actions"); 133 | const output = convention.output ? convention.output(matcher) : matcher; 134 | PW_tooltip.innerText = primaryAction.replaceAll('$1', output); 135 | //todo - secondary actions 136 | } 137 | } 138 | 139 | function updateTooltipPosition(x, y) { 140 | let xOffset = 0; 141 | let yOffset = 16; 142 | if (x > window.visualViewport.width * 0.75) xOffset = -xOffset - PW_tooltip.getBoundingClientRect().width; 143 | if (y > window.visualViewport.height * 0.75) yOffset = -yOffset - PW_tooltip.getBoundingClientRect().height; 144 | PW_tooltip.style.left = x + xOffset + "px"; 145 | PW_tooltip.style.top = y + yOffset + "px"; 146 | } 147 | 148 | window.mousemove_updateToolTip_running = false; 149 | function mousemove_updateTooltip(event) { 150 | if (mousemove_updateToolTip_running === true) return; //exit early so we don't swamp the CPU 151 | try { 152 | mousemove_updateToolTip_running = true; 153 | const element = document.elementFromPoint(event.x, event.y); 154 | if (element == null) return; 155 | 156 | mouse_x = event.x; 157 | mouse_y = event.y; 158 | window.PW_tooltip.style.visibility = !recordModeOn || element.closest(".PW") ? "hidden" : "visible"; 159 | if (!recordModeOn) return; 160 | 161 | updateTooltipPosition(mouse_x, mouse_y); 162 | 163 | if (element == null) return; 164 | if (window.el === element) return; 165 | 166 | updateTooltipContents(element); 167 | window.el = element; 168 | } finally { 169 | mousemove_updateToolTip_running = false; 170 | } 171 | } 172 | 173 | async function recordModeClickHandler_swallowClick(event) { 174 | if (!recordModeOn) return; 175 | if (window.PW_executing) return; 176 | 177 | const element = document.elementFromPoint(event.x, event.y); 178 | if (element == null) return; 179 | if (element.closest(".PW")) return; 180 | 181 | event.preventDefault(); 182 | event.stopImmediatePropagation(); 183 | return element; 184 | } 185 | 186 | async function recordModeClickHandler(event) { 187 | const element = await recordModeClickHandler_swallowClick(event); 188 | if (element == null) return; 189 | 190 | let newItemName; 191 | const selectorConvention = PW_getSelectorConventionForElement(element); 192 | if (config.pageObjectModel.enabled && !selectorConvention.isPageObjectModel) { 193 | dataTestId = element.closest('[data-testid]')?.getAttribute('data-testid'); 194 | newItemName = window.prompt("Page object model item name?", dataTestId); 195 | if (newItemName != null) { 196 | const selector = selectorConvention.match(element); 197 | const nestedPages = getNestedPages(pageObjectFilePath).concat(getNestedPages('global_page.ts')); 198 | const nestedPageObjectFilePath = nestedPages.find(x => element.closest(x.selector) !== null)?.filePath; 199 | await PW_appendToPageObjectModel(nestedPageObjectFilePath ?? pageObjectFilePath, config.pageObjectModel.generatePropertyTemplate(newItemName, selector)); 200 | } else { 201 | const selector = selectorConvention.match(element); 202 | navigator.clipboard.writeText(selector); //navigator.clipboard is undefined when running? troubleshoot me 203 | } 204 | return; 205 | } 206 | 207 | const resultOutput = selectorConvention.output ? selectorConvention.output(selectorConvention.match(element)) : selectorConvention.match(element); 208 | const primaryAction = element.closest('[data-page-object-model-primary-action]').getAttribute("data-page-object-model-primary-action"); 209 | //todo - implement secondary actions 210 | const replLine = primaryAction.replaceAll('$1', resultOutput); 211 | //PW_repl.value = replLine; 212 | //PW_repl.disabled = false; 213 | 214 | if (selectorConvention.isPageObjectModel) { 215 | await PW_appendToTest(replLine, element.closest('[data-page-object-model-import]').getAttribute("data-page-object-model-import")); 216 | } else { 217 | await PW_appendToTest(replLine); 218 | } 219 | } 220 | 221 | function getNestedPages(pageObjectFilePath) { 222 | const pom = PW_pages[pageObjectFilePath]; 223 | const nestedPages = pom?.nestedPages; 224 | if (nestedPages === undefined) return []; 225 | const nestedNestedPages = nestedPages.map(x => getNestedPages(x.filePath)) 226 | return nestedPages.concat(nestedNestedPages.flat());//.uniqueBy(x => x.filePath); //todo - uniqueBy isn't in vanilla JS, fix me 227 | } 228 | 229 | PW_getSelectorConventionForElement = function (el) { 230 | const allSelectorConventions = [...PW_selector_pageObjectModel_conventions, ...(PW_selectorConventions ?? []), ...PW_selector_base_conventions]; 231 | return allSelectorConventions.find((i) => i.match(el) != null /* null or undefined */); 232 | }; 233 | 234 | window.addEventListener("keydown", keyChord_toggleRecordMode); 235 | window.addEventListener("mousemove", mousemove_updateTooltip); 236 | window.addEventListener("click", recordModeClickHandler, true); 237 | //var _PW_mousedown_element; 238 | //window.addEventListener('pointerdown', function (e) { _PW_mousedown_element = e.target; recordModeClickHandler_swallowClick(e);});//, true); 239 | //document.addEventListener('pointerup', function (e) { if (e.target === _PW_mousedown_element) recordModeClickHandler(e); });//, true); 240 | 241 | 242 | /******** page object model feature ********/ 243 | 244 | window.navigation.onnavigatesuccess = async () => await reload_page(); 245 | //window.setInterval(async () => await reload_page_object_model_elements(), 5000); //refresh the page object model highlighting every 5 seconds in case on-screen elements have changed 246 | 247 | 248 | var pageObjectFilePath = ""; 249 | 250 | async function reload_page() { 251 | if (PW_urlToFilePath === undefined) return; //test backend hasn't injected functions yet 252 | //get current page object to reflect across 253 | pageObjectFilePath = await PW_urlToFilePath(window.location.href); 254 | PW_page_object_model_filename.innerText = pageObjectFilePath ?? "Playwright Live Recorder"; 255 | await reload_page_object_model_elements(); 256 | } 257 | 258 | async function reload_page_object_model_elements() { 259 | //clearPageObjectModelElements(); 260 | 261 | const globalPageObject = window.PW_pages['global_page.ts']; 262 | if (globalPageObject !== undefined) await _reload_page_object_model_elements(globalPageObject, 'global_page.ts'); 263 | 264 | const pageObject = window.PW_pages[pageObjectFilePath]; 265 | await _reload_page_object_model_methods(pageObject, pageObjectFilePath); 266 | await _reload_page_object_model_elements(pageObject, pageObjectFilePath); 267 | } 268 | 269 | async function _reload_page_object_model_methods(pageObject, pageObjectFilePath) { 270 | window.PLR_pom_methods_dropdown.innerHTML = ""; 271 | for (var meth of pageObject?.methods ?? []) { 272 | // {name: string, args: string[], body: method.getText() } 273 | 274 | const isAsync = meth.body.includes("async"); 275 | const codeLine = `${isAsync ? 'await ':''}${pageObject.className}.${meth.name}(${meth.args.join(', ')});` 276 | const el = document.createElement("li"); 277 | el.onclick = () => PW_appendToTest(codeLine, pageObjectModelImportStatement); 278 | el.innerText = `${meth.name}(${meth.args.join(', ')})`; 279 | 280 | window.PLR_pom_methods_dropdown.appendChild(el); 281 | } 282 | 283 | { 284 | const addFunctionEl = document.createElement("li"); 285 | addFunctionEl.innerText = "+"; 286 | addFunctionEl.style = "background:green;color:white;font-size:14px;text-align:center"; 287 | 288 | addFunctionEl.onclick = () => { 289 | const newFunctionName = window.prompt("New function name?"); 290 | if (newFunctionName == null) return; 291 | PW_appendToPageObjectModel(pageObjectFilePath, config.pageObjectModel.generateMethodTemplate(newFunctionName)); 292 | }; 293 | window.PLR_pom_methods_dropdown.appendChild(addFunctionEl); 294 | } 295 | } 296 | 297 | async function _reload_page_object_model_elements(pageObject, pageObjectFilePath) { 298 | if (pageObject === undefined) return; 299 | 300 | const pageObjectModelImportStatement = await PW_importStatement(pageObject.className, pageObjectFilePath); 301 | if (recordModeOn){ 302 | for (var prop of pageObject.selectors) { 303 | try { 304 | const matchingElements = playwright.locator(prop.selector).elements; 305 | if (matchingElements.length > 1) { 306 | //todo: non-unique locator - show a warning somehow 307 | } 308 | if (matchingElements.length === 0) { 309 | console.info(`could not find element for selector ${prop.selector}. skipping.`); 310 | continue; 311 | } 312 | 313 | const primaryAction = config.pageObjectModel.primaryActionByCssSelector.find(([css]) => matchingElements[0].matches(css))[1]; 314 | const secondaryActions = config.pageObjectModel.secondaryActionByCssSelector.filter(([css]) => matchingElements[0].matches(css)).map(([, action]) => action); 315 | const dataPageObjectModel = `${pageObject.className}.${prop.selectorMethod.name}(${prop.selectorMethod.args.join(', ')})`; 316 | for (const el of matchingElements) { 317 | el.setAttribute("data-page-object-model", dataPageObjectModel); 318 | el.setAttribute("data-page-object-model-import", pageObjectModelImportStatement); 319 | 320 | el.setAttribute("data-page-object-model-primary-action", primaryAction); 321 | el.setAttribute("data-page-object-model-secondary-actions", encodeURIComponent(JSON.stringify(secondaryActions))); 322 | config.pageObjectModel.overlay.on(el, config.pageObjectModel.overlay.color); 323 | PW_overlays.push(el); 324 | } 325 | } catch (err) { 326 | console.log(err); 327 | } 328 | } 329 | 330 | //recursively load all nested pages 331 | for (var x of pageObject.nestedPages) await _reload_page_object_model_elements(window.PW_pages[x.filePath], x.filePath); 332 | } 333 | } 334 | 335 | function clearPageObjectModelElements() { 336 | if (window.PW_overlays !== undefined) for (const el of window.PW_overlays) config.pageObjectModel.overlay.off(el); 337 | 338 | //clean up any rogue elements 339 | const pageObjectModelAttributes = ['[data-page-object-model]', '[data-page-object-model-import]', '[data-page-object-model-primary-action]', '[data-page-object-model-secondary-actions]']; 340 | document.querySelectorAll(pageObjectModelAttributes.join(', ')).forEach(el => { 341 | pageObjectModelAttributes.forEach(attr => el.removeAttribute(attr)); 342 | config.pageObjectModel.overlay.off(el) 343 | }); 344 | window.PW_overlays = []; 345 | } 346 | 347 | //pageObject selector evaluation requires `playwright` object, warn user if it's not available 348 | if (!window.playwright) { 349 | PW_reportError( 350 | "Playwright live recorder will not run without additional configuration", 351 | `Add by setting environment variable 352 |
PWDEBUG=console
353 | or if using vscode ms-playwright.playwright extension, add the following into .vscode/settings.json 354 |
"playwright.env": {
355 |   "PWDEBUG": "console"
356 | },
`, 357 | true 358 | ); 359 | } 360 | 361 | PW_executionBlocks = []; 362 | function PW_callback_begin_executing(i, code, fullCodeBlock) { 363 | PW_executing = true; 364 | PW_executionBlocks.push({i, code, fullCodeBlock, isExecuting: true }); 365 | 366 | setToastContent('
', `
${code}
`); 367 | show_toast(); 368 | } 369 | 370 | function PW_callback_finished_executing(i, success, result, code, fullCodeBlock) { 371 | window.PW_executing = false; 372 | const executionBlockResult = {i, code, fullCodeBlock, isExecuting: false, success, result }; 373 | let executionBlockIndex = PW_executionBlocks.findIndex(x => x.i == i); 374 | if (executionBlockIndex == -1) PW_executionBlocks.push(executionBlockResult); 375 | else PW_executionBlocks[executionBlockIndex] = {...PW_executionBlocks[executionBlockIndex], ...executionBlockResult}; 376 | 377 | console.log(`${success ? '✅' : '❌'}\n${code}\n\n${result == undefined ? '' : JSON.stringify(result, undefined, ' ')}`); 378 | setToastContent(success ? '' : '', `
${code}
${result == undefined ? '' : encodeURIComponent(JSON.stringify(result, undefined, '  '))}
`); 379 | show_toast(success && result == undefined ? 2_000 : undefined); 380 | reload_page_object_model_elements(); 381 | } 382 | 383 | function setToastContent(img, desc) { 384 | document.getElementById("PW_PLR_toast_img").innerHTML = img; 385 | document.getElementById("PW_PLR_toast_desc").innerHTML = desc; 386 | } 387 | 388 | var show_toast_timeout; 389 | function show_toast(timeoutMs) { 390 | var x = document.getElementById("PW_PLR_toast"); 391 | x.classList.add('show'); 392 | if (show_toast_timeout) clearTimeout(show_toast_timeout); 393 | show_toast_timeout = timeoutMs ? setTimeout(function(){ x.classList.remove('show'); }, timeoutMs) : undefined; 394 | } 395 | 396 | clearPageObjectModelElements(); 397 | setTimeout(() => reload_page(), 1000); -------------------------------------------------------------------------------- /src/browser/PW_selectorConventions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * PW_selectorConventions contract: 3 | * array of { match(el) => resultType | undefined, output(x: resultType) => code: string, isPageObjectModel: boolean} 4 | * notes: 5 | * match(el) => null/undefined inidicates not a match 6 | * rules are evaluated in order (top to bottom) 7 | * currently hovered element is passed into each match 8 | */ 9 | 10 | var PW_selector_pageObjectModel_conventions = [ 11 | { 12 | match: el => el.closest('[data-page-object-model]')?.getAttribute('data-page-object-model'), 13 | isPageObjectModel: true, 14 | }, 15 | ]; 16 | 17 | var PW_selectorConventions = [ 18 | { 19 | match: el => { 20 | const dataTestId = el.closest('[data-testid]')?.getAttribute('data-testid') 21 | return dataTestId ? `[data-testid="${dataTestId}"]` : undefined; 22 | }, 23 | } 24 | ]; 25 | 26 | var PW_selector_base_conventions = [ 27 | { 28 | match: (el) => playwright.selector(el), 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /src/hotModuleReload.ts: -------------------------------------------------------------------------------- 1 | import { ts, Project, ImportDeclaration } from "ts-morph"; 2 | import nodePath from "node:path"; 3 | import chokidar from "chokidar"; 4 | import AsyncLock from "async-lock"; 5 | import fs from "node:fs/promises"; 6 | import { register } from "node:module"; 7 | 8 | import { TestCallingLocation } from "./types"; 9 | 10 | type hotModuleReloadState = { 11 | t: TestCallingLocation; 12 | testFnContents: string; 13 | imports: ImportDeclaration[]; 14 | pageEvaluate: (pageFunction: string) => Promise; 15 | evalScope: (s: string) => any; 16 | } 17 | 18 | export module hotModuleReload { 19 | export const _state: hotModuleReloadState = {}; 20 | const lock = new AsyncLock(); 21 | 22 | export async function init(testCallingLocation: TestCallingLocation, importerCustomizationHooks: string, pageEvaluate: (pageFunction: string) => (Promise | any), evalScope: (s: string) => any) { 23 | _state.t = testCallingLocation; 24 | _state.pageEvaluate = pageEvaluate; 25 | _state.evalScope = evalScope; 26 | 27 | register(importerCustomizationHooks); 28 | await _initialTestFileLoad(_state); 29 | 30 | const testFileWatcher = chokidar.watch(nodePath.resolve(_state.t.file)); 31 | testFileWatcher.on('change', async () => await hotModuleReload._reloadTestFile(_state)); 32 | } 33 | 34 | export async function _initialTestFileLoad(s: hotModuleReloadState) { 35 | s.testFnContents = (await _extractFnContents(s.t.file, s.t.testLine, s.t.testLineNumber, s.t.executingLine))!; 36 | s.imports = _extractImports(s.t.file); 37 | } 38 | 39 | export async function _reloadTestFile(s: hotModuleReloadState) { 40 | await lock.acquire('reloadTestFile', async (release) => { 41 | try { 42 | s.imports = _extractImports(s.t.file); 43 | const newTestFnContents = await (_extractFnContents(s.t.file, s.t.testLine, s.t.testLineNumber, s.t.executingLine)) ?? ''; 44 | const blockToExecute = _getBlockToExecute(s.testFnContents, newTestFnContents); 45 | s.testFnContents = newTestFnContents; 46 | if (blockToExecute === '') 47 | return; 48 | await evalLines(blockToExecute); 49 | } finally { 50 | release(); 51 | } 52 | }); 53 | } 54 | 55 | async function evalLines(lines: string) { 56 | const importsBlock = _rewriteAsDynamicImports(_state.imports).join('\n'); 57 | const wrappedEvalLines = _wrapAsyncAsPromise(importsBlock + '\n\n' + lines, _extractVariableListFrom(lines)); 58 | return _evalCore(_state.evalScope, _state.pageEvaluate, wrappedEvalLines, lines); 59 | } 60 | 61 | function _rewriteAsDynamicImports(imports: ImportDeclaration[]) 62 | { 63 | return imports.map(importDecl => { 64 | const namedImports = importDecl.getNamedImports().map(namedImport => namedImport.getName()).join(', '); 65 | const moduleSpecifier = importDecl.getModuleSpecifier().getLiteralText(); 66 | return `${(namedImports.length > 0) ? `const { ${namedImports} } = ` : ''} await import('${moduleSpecifier}');`; 67 | }); 68 | } 69 | 70 | export function _wrapAsyncAsPromise(codeBlock: string, variables: string[]) { 71 | return `(async function() { 72 | try { 73 | ${codeBlock} 74 | ${variables.length === 0 ? `` : `Object.assign(globalThis, { ${variables.join(', ')}});`} 75 | } catch (err) { 76 | console.error(err); 77 | } 78 | })()`; 79 | } 80 | 81 | export function _extractVariableListFrom(blockToExecute: string) { 82 | const proj = new Project(); 83 | const srcFile = proj.createSourceFile('./blockToExecute.ts', blockToExecute); 84 | const variableNames = srcFile.getChildrenOfKind(ts.SyntaxKind.VariableStatement).map(x => { 85 | const syntaxList = x.getChildren()[0].getChildren()[1]; 86 | const assignmentStatement = blockToExecute.slice(syntaxList.compilerNode.pos, syntaxList.compilerNode.end); 87 | const varBlock = /\s*\{?(.+)\}?\s*=/.exec(assignmentStatement)![1]; 88 | const listOfVars = varBlock.trim().replace(/}$/m, '').split(',').map(x => x.trim()); 89 | return listOfVars; 90 | }); 91 | return variableNames.flat(); 92 | } 93 | 94 | let _evalCoreCount = 1; 95 | export async function _evalCore(evalScope: (s: string) => any, pageEvaluate: (pageFunction: string) => Promise, codeBlock: string, codeBlockDescription: string) { 96 | const i = _evalCoreCount++; 97 | 98 | let result; 99 | try { 100 | await pageEvaluate(`PW_callback_begin_executing(${i}, \`${codeBlockDescription}\`, \`${codeBlock}\`)`); 101 | result = await evalScope(codeBlock); 102 | const evalString = `setTimeout(function() { var fn = (window.PW_callback_finished_executing === undefined) ? console.log : window.PW_callback_finished_executing; fn(${i}, true, ${JSON.stringify(result)}, \`${codeBlockDescription}\`, \`${codeBlock}\`); }, window.PW_callback_finished_executing === undefined ? 1000 : 0);`; 103 | await pageEvaluate(evalString); 104 | } catch (error) { 105 | if (error instanceof Error) { 106 | const evalString = `setTimeout(function() { var fn = (window.PW_callback_finished_executing === undefined) ? console.log : window.PW_callback_finished_executing; fn(${i}, false, ${error.message}, \`${codeBlockDescription}\`, \`${codeBlock}\`); }, window.PW_callback_finished_executing === undefined ? 1000 : 0);` 107 | await pageEvaluate(evalString); 108 | console.warn(error); 109 | } else { 110 | const evalString = `setTimeout(function() { var fn = (window.PW_callback_finished_executing === undefined) ? console.log : window.PW_callback_finished_executing; fn(${i}, false, \`${JSON.stringify(error)}\`, \`${codeBlockDescription}\`, \`${codeBlock}\`); }, window.PW_callback_finished_executing === undefined ? 1000 : 0);`; 111 | await pageEvaluate(evalString); 112 | console.error(error); 113 | } 114 | } 115 | return result; 116 | } 117 | 118 | export function _extractImports(filename: string) { 119 | const project = new Project(); 120 | const ast = project.addSourceFileAtPath(filename); 121 | const allImports = ast.getChildrenOfKind(ts.SyntaxKind.ImportDeclaration); 122 | return allImports; 123 | } 124 | 125 | export async function _extractFnContents(filename: string, fnDecl: string, fnDeclLineNumber: number, executingLine: string) { 126 | const src = (await fs.readFile(filename, 'utf-8')); 127 | const fnDeclIndex = src.indexOf(fnDecl); if (fnDeclIndex === -1) return undefined; 128 | const endIndex = src.indexOf(executingLine, fnDeclIndex! + fnDecl.length); if (endIndex === -1) return undefined; 129 | const fnContents = src.slice(fnDeclIndex! + fnDecl.length, endIndex); 130 | return fnContents; 131 | } 132 | 133 | export function _getBlockToExecute(oldSrc: string, newSrc: string) { 134 | if (oldSrc === undefined) return ''; 135 | 136 | const oldLines = oldSrc.split(_NEWLINE); 137 | const newLines = newSrc.split(_NEWLINE); 138 | 139 | if (oldLines.length == 0) return newSrc; 140 | const firstLineWithChangeIndex = newLines.findIndex((s, index) => oldLines.length < index || oldLines[index] !== s); 141 | if (firstLineWithChangeIndex == -1) return ''; 142 | 143 | const linesToExecute = newLines.slice(firstLineWithChangeIndex); 144 | 145 | const blockToExecute = linesToExecute.join('\n'); 146 | return blockToExecute; 147 | } 148 | 149 | const _NEWLINE = /\r\n|\n|\r/; 150 | } -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { Page, test } from "@playwright/test"; 2 | 3 | import chokidar from "chokidar"; 4 | import _ from "lodash"; 5 | import nodePath from "node:path"; 6 | 7 | import { recorder } from "./recorder"; 8 | import { testFileWriter } from "./testFileWriter"; 9 | import { hotModuleReload } from "./hotModuleReload"; 10 | import { pageObjectModel } from "./pageObjectModel"; 11 | import { getTestCallingLocation } from "./utility"; 12 | import fs from 'fs/promises'; 13 | import process from 'node:process'; 14 | import { ts } from "ts-morph"; 15 | import { PlaywrightLiveRecorderConfig, PlaywrightLiveRecorderConfigFile, PlaywrightLiveRecorderConfig_recorder, PlaywrightLiveRecorderConfig_pageObjectModel, PlaywrightLiveRecorderConfig_diagnostic, TestCallingLocation } from "./types"; 16 | export { PlaywrightLiveRecorderConfig, PlaywrightLiveRecorderConfigFile, PlaywrightLiveRecorderConfig_recorder, PlaywrightLiveRecorderConfig_pageObjectModel, PlaywrightLiveRecorderConfig_diagnostic, TestCallingLocation }; 17 | 18 | export module PlaywrightLiveRecorder { 19 | export const defaultConfig: PlaywrightLiveRecorderConfig = { 20 | recorder: { 21 | path: './PW_selectorConventions.js', 22 | basepath: './node_modules/@dnvgl/playwright-live-recorder/dist/browser/PW_selectorConventions.js' 23 | }, 24 | pageObjectModel: { 25 | enabled: true, 26 | path: './tests/', 27 | filenameConvention: '**/*_page.ts', 28 | baseUrl: undefined, 29 | actionTimeout: 5000, 30 | globalPageFilePath: 'global_page.ts', 31 | urlToFilePath: (url: string, aliases: {[key: string]: string}) => { 32 | let filePath = url 33 | .replace(new RegExp(`^${config.pageObjectModel.baseUrl}`), '') //cut out base url 34 | .replace(/[a-fA-F0-9]{8}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{12}/g, '') //cut out guids 35 | .replace(/\/\d+(?=\/)/g, '/') // cut out /###/ fragments 36 | .replace(/\d+\//g, '/') // cut out /###/ fragments if there were any left over 37 | .replace(/\/\d+$/g, '/') // cut out /### fragments at end 38 | .replace(/-/g, '_') //replace all hyphens with underscores, valid classname 39 | .replace(/\/\/+/g, '/') // if we end up with two // in a row, replace it with one 40 | .replace(/\/$/, '') // clear trailing / 41 | .replace(/^\//, ''); // clear leading / 42 | if (filePath in aliases) filePath = aliases[filePath]; //apply aliases 43 | return filePath + '_page.ts'; 44 | }, 45 | aliases: {}, 46 | propertySelectorRegex: /(.+)_selector\b/, 47 | propertyNestedTypeRegex: /(.+)_page\b/, 48 | primaryActionByCssSelector: [ 49 | ['input[type="text"], input[type=""], textarea', 'await $1.fill("");'], 50 | ['*', 'await $1.click();'] 51 | ], 52 | secondaryActionByCssSelector: [ 53 | ['input[type="text"], textarea', 'await expect($1.innerText()).toContain("");'], 54 | /// available on all element types 55 | ['*', 'await expect($1.innerText()).toContain("");'], 56 | ['*', 'await expect($1).toBeVisible();'], 57 | ['*', 'await expect($1).toBeEnabled();'] 58 | ], 59 | generateClassTemplate: (className: string) => 60 | `import type { Page } from '@playwright/test'; 61 | 62 | export class ${className} { 63 | 64 | }`, 65 | generatePropertyTemplate: (name: string, selector: string) => 66 | ` private static ${name}_selector = \`${selector}\`;\r\n` + 67 | ` static ${name}(page: Page) { return page.locator(this.${name}_selector); }\r\n\r\n`, 68 | generateMethodTemplate: (name: string) => 69 | ` static async ${name}(page: Page) {\r\n \r\n }\r\n\r\n`, 70 | overlay: { 71 | color: 'salmon', 72 | on: (el: HTMLElement, color: string) => { 73 | if (el.getAttribute('data-background')) return; 74 | el.setAttribute('data-background', el.style.background); 75 | el.style.background = color ?? 'salmon'; 76 | }, 77 | off: (el: HTMLElement) => el.style.background = el.getAttribute('data-background') ?? '', 78 | }, 79 | importerCustomizationHooks: `data:text/javascript, 80 | import { promises as fs } from 'fs'; 81 | import { fileURLToPath } from 'url'; 82 | 83 | const resolvedFilenames = new Set(); 84 | 85 | export async function resolve(specifier, context, nextResolve) { 86 | const resolved = await nextResolve(specifier, context); 87 | if (!resolved.url.endsWith('.ts')) return resolved; 88 | 89 | const urlFilename = fileURLToPath(resolved.url); 90 | const modifyMs = await fs.stat(urlFilename).then(stat => Math.floor(stat.mtimeMs)); 91 | resolved.url = resolved.url.replace(/.ts$/, '.cachebust.' + modifyMs + '.ts'); 92 | return resolved; 93 | } 94 | 95 | export async function load(url, context, nextLoad) { 96 | const original = url.replace(/\\.cachebust\\.\\d+.ts$/, '.ts'); 97 | if (original === url || resolvedFilenames.has(url)) return await nextLoad(url, context); 98 | const urlFilename = fileURLToPath(url); 99 | const originalFilename = fileURLToPath(original); 100 | await fs.copyFile(originalFilename, urlFilename); 101 | const result = await nextLoad(url, context); 102 | await fs.rm(urlFilename); 103 | resolvedFilenames.add(url); 104 | return result; 105 | } 106 | ` 107 | }, 108 | diagnostic: { 109 | browserCodeJSPath: './node_modules/@dnvgl/playwright-live-recorder/dist/browser/PW_live.js', 110 | browserCodeCSSPath: './node_modules/@dnvgl/playwright-live-recorder/dist/browser/PW_live.css', 111 | hotReloadBrowserLibFiles: false, 112 | } 113 | } 114 | 115 | let config: PlaywrightLiveRecorderConfig; 116 | export let configOverrides: PlaywrightLiveRecorderConfig = { recorder: {}, pageObjectModel: { overlay: {} }, diagnostic: {} }; 117 | 118 | 119 | /** 120 | * used to track if `start` already called, if so, don't start again 121 | */ 122 | type pageState = { PlaywrightLiveRecorder_started: boolean }; 123 | /** 124 | * @param evalScope pass value of `s => eval(s)`, this provides the test's execution scope so eval'd lines have local scope variables, relative import paths, etc 125 | */ 126 | export async function start(page: Page, evalScope: (s: string) => any) { 127 | if (evalScope.toString() !== 's => eval(s)'){ 128 | const testEval = evalScope('1+1'); 129 | if (testEval !== 2) throw new Error(`evalScope does not evaluate correctly, please verify, should look something like \`s => eval(s)\`, instead got \`${evalScope.toString()}\``); 130 | } 131 | const pageState = page; 132 | if (pageState.PlaywrightLiveRecorder_started === true) { 133 | return; 134 | } 135 | pageState.PlaywrightLiveRecorder_started = true; 136 | 137 | const isHeadless = test.info().project.use.headless; 138 | const pwdebug = process.env.PWDEBUG == 'console'; 139 | if (isHeadless !== false && !pwdebug) { 140 | console.error('startLiveCoding called while running headless or env variable PWDEBUG=console not set'); 141 | return; 142 | } 143 | config = _mergeConfig(defaultConfig, await _configFromFile(), configOverrides); 144 | if (!config.pageObjectModel.path.endsWith('/')) config.pageObjectModel.path +='/'; 145 | 146 | page.setDefaultTimeout(config.pageObjectModel.actionTimeout); 147 | 148 | const testCallingLocation = await getTestCallingLocation(); 149 | await testFileWriter.init(page, testCallingLocation); 150 | 151 | await hotModuleReload.init(testCallingLocation, config.pageObjectModel.importerCustomizationHooks, (str: string) => page.evaluate(str), evalScope); 152 | await page.exposeFunction('PW_eval', (codeBlock: string) => hotModuleReload._evalCore(evalScope, s => page.evaluate(s), codeBlock, codeBlock)); 153 | 154 | await recorder.init(config.recorder, page); 155 | 156 | await page.exposeFunction('PW_config', () => PW_config()); //expose config to browser 157 | await page.addScriptTag({ path: config.diagnostic.browserCodeJSPath }); //loading these scripts first, pageObjectModel.init watchers are dependent upon methods exposed here 158 | await page.addStyleTag({ path: config.diagnostic.browserCodeCSSPath }); 159 | 160 | if (config.pageObjectModel.enabled) { 161 | config.pageObjectModel.baseUrl = config.pageObjectModel.baseUrl ?? test.info().project.use.baseURL!; 162 | await pageObjectModel.init(nodePath.dirname(testCallingLocation.file), config.pageObjectModel, evalScope, page); 163 | } 164 | 165 | page.on('load', async page => { 166 | await page.addScriptTag({ path: config.recorder.basepath }); 167 | await page.addScriptTag({ path: config.recorder.path }); 168 | await page.addScriptTag({ path: config.diagnostic.browserCodeJSPath }); 169 | await page.addStyleTag({ path: config.diagnostic.browserCodeCSSPath }); 170 | await pageObjectModel.reloadAll(config.pageObjectModel.path, page); 171 | }); 172 | 173 | page.on('dialog', dialog => {/* allow user interaction for browser input dialog interaction */ }); 174 | 175 | if (config.diagnostic.hotReloadBrowserLibFiles) { 176 | const watch = chokidar.watch([config.diagnostic.browserCodeJSPath, config.diagnostic.browserCodeCSSPath]); 177 | watch.on('change', async path => { 178 | if (path.endsWith('.css')) await page.addStyleTag({ path }); 179 | else await page.addScriptTag({ path }); 180 | }); 181 | } 182 | 183 | await page.waitForEvent("close", { timeout: 1000 * 60 * 60 }); 184 | } 185 | 186 | export let configFilePath = './live-recorder.config.ts'; 187 | export async function _configFromFile() { 188 | //todo - try rewriting to use dynamic import instead 189 | try { 190 | const fileContents = await fs.readFile(configFilePath, { encoding: 'utf8' }); 191 | const transpiled = ts.transpileModule(fileContents, { compilerOptions: { module: ts.ModuleKind.ESNext, strict: false } }); 192 | const cleanedUp = _cleanUpTranspiledSource(transpiled.outputText); 193 | const obj = eval(cleanedUp); 194 | return obj; 195 | } catch (err) { 196 | if ((err).code === 'MODULE_NOT_FOUND') return; 197 | console.error(err); 198 | } 199 | } 200 | 201 | function _cleanUpTranspiledSource(transpiled: string) { 202 | return transpiled 203 | .replaceAll(/\bimport\b\s*({?\s*[^};]+}?)\s*from\s*([^;]*);?/g, '') 204 | .replace('export default ', ''); 205 | } 206 | 207 | 208 | 209 | 210 | /** _.merge({}, defaultConfig, configFromFile, configOverrides) */ 211 | function _mergeConfig(defaultConfig: PlaywrightLiveRecorderConfig, configFromFile: PlaywrightLiveRecorderConfig | undefined, configOverrides: PlaywrightLiveRecorderConfig) { 212 | return _.merge({}, defaultConfig, configFromFile, configOverrides); 213 | } 214 | async function PW_config() { 215 | //shenanigans to get regexp and functions to serialize reasonably 216 | (RegExp.prototype).toJSON = RegExp.prototype.toString; 217 | (Function.prototype).toJSON = Function.prototype.toString; 218 | const result = JSON.stringify(config); 219 | delete (RegExp.prototype).toJSON; 220 | delete (Function.prototype).toJSON; 221 | 222 | return JSON.parse(result); 223 | } 224 | } -------------------------------------------------------------------------------- /src/pageObjectModel.ts: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | import fs from "fs/promises"; 3 | import process from "node:process"; 4 | import nodePath from "node:path"; 5 | import chokidar from "chokidar"; 6 | import { PlaywrightLiveRecorderConfig_pageObjectModel } from "./types"; 7 | import { Page } from "@playwright/test"; 8 | import AsyncLock from "async-lock"; 9 | import { Project } from "ts-morph"; 10 | import { createQueuedRunner } from "./utility"; 11 | 12 | //scans and watches page object model files, transpiles and exposes page object models to the browser context 13 | export module pageObjectModel { 14 | export let _state: { 15 | testFileDir: string, 16 | config: PlaywrightLiveRecorderConfig_pageObjectModel, 17 | evalScope: (s: string) => Promise, 18 | page: Page, 19 | } = {}; 20 | let currentPageFilePath!: string; 21 | let currentPageFilePathWatcher!: chokidar.FSWatcher; 22 | let _project: Project; 23 | 24 | const lock = new AsyncLock(); 25 | export async function init(testFileDir: string, config: PlaywrightLiveRecorderConfig_pageObjectModel, evalScope: (s: string) => any, page: Page) { 26 | _state = {testFileDir, config, evalScope, page}; 27 | 28 | await page.exposeFunction('PW_urlToFilePath', async (url: string) => PW_urlToFilePath(url)); 29 | 30 | await page.exposeFunction('PW_importStatement', (className: string, pathFromRoot: string) => _importStatement(className, nodePath.join(process.cwd(), _state.config.path, pathFromRoot), _state.testFileDir)); 31 | 32 | await page.exposeFunction('PW_ensurePageObjectModelCreated', (path: string) => _ensurePageObjectModelCreated(fullRelativePath(path, config), classNameFromPath(path), config)); 33 | await page.exposeFunction('PW_appendToPageObjectModel', (path: string, codeBlock: string) => _appendToPageObjectModel(fullRelativePath(path, config), classNameFromPath(path), codeBlock, config)); 34 | } 35 | 36 | export async function PW_urlToFilePath(url: string) { 37 | const newfilePath = _state.config.urlToFilePath(url, _state.config.aliases); 38 | if (newfilePath === currentPageFilePath) return currentPageFilePath; 39 | currentPageFilePath = newfilePath; 40 | 41 | await reload(_state.page); 42 | return currentPageFilePath; 43 | } 44 | 45 | export function _importStatement(className: string, pathFromRoot: string, testFileDir: string) { 46 | const x = nodePath.parse(nodePath.relative(testFileDir, pathFromRoot)); 47 | let importPath = nodePath.join(x.dir, x.name).replaceAll('\\', '/'); // relative path without extension 48 | if (!(importPath.startsWith('.') || importPath.startsWith('/'))) importPath = './' + importPath; 49 | return `import { ${className} } from '${importPath}';` 50 | } 51 | 52 | export const reload = createQueuedRunner(async (page) => reload2(page)); 53 | 54 | export async function reload2(page: Page) { 55 | console.time('pageObjectModel.reload'); 56 | await lock.acquire('reload', async (release) => { 57 | try { 58 | _project = _project ?? new Project({ tsConfigFilePath: await fs.access(nodePath.join(process.cwd(), 'tsconfig.json')).then(() => true).catch(() => false) ? 'tsconfig.json' : undefined }); 59 | const filePathsToWatch = await _reload(page, [_state.config.globalPageFilePath, currentPageFilePath], _project); 60 | 61 | await currentPageFilePathWatcher?.close(); 62 | const cwd = nodePath.join(process.cwd(), _state.config.path); 63 | currentPageFilePathWatcher = chokidar.watch(filePathsToWatch, { cwd, ignoreInitial: true }) 64 | .on( 'add', /*path*/() => reload(_state.page)) 65 | .on('change', /*path*/() => reload(_state.page)); 66 | 67 | await page.evaluate('if (reload_page_object_model_elements) reload_page_object_model_elements()'); 68 | } catch (e) { 69 | console.error(`error calling page.addScriptTag for page object model ${currentPageFilePath}`); 70 | console.error(e); 71 | await page.evaluate('if (reload_page_object_model_elements) reload_page_object_model_elements()'); 72 | } finally { 73 | release(); 74 | } 75 | }); 76 | console.timeEnd('pageObjectModel.reload'); 77 | } 78 | 79 | async function _reload(page: Page, filePaths: string[], project?: Project) { 80 | const all = await Promise.all(filePaths.map(async filePath => { 81 | const parsed = nodePath.parse(filePath); 82 | const absolutePath = nodePath.join(process.cwd(), _state.config.path, parsed.dir, parsed.base); 83 | const exists = fs.access(absolutePath).then(() => true).catch(() => false); 84 | return ({ filePath, parsed, absolutePath, exists }); 85 | })); 86 | 87 | const existingPaths = all.filter(x => x.exists); 88 | if (existingPaths.length === 0) return []; 89 | 90 | project = project ?? new Project({ tsConfigFilePath: await fs.access(nodePath.join(process.cwd(), 'tsconfig.json')).then(() => true).catch(() => false) ? 'tsconfig.json' : undefined }); 91 | 92 | const resultFilePaths = existingPaths.map(e => e.filePath); 93 | for(const p of existingPaths) { 94 | const sourceFile = project.addSourceFileAtPath(p.absolutePath); 95 | 96 | const exportedClass = sourceFile.getClasses().find(cls => cls.isExported()); 97 | if (exportedClass === undefined) return []; 98 | 99 | const staticProperties = exportedClass?.getStaticProperties(); 100 | const staticMethods = exportedClass?.getStaticMethods(); 101 | 102 | //use dynamic import to evaluate selector property values 103 | const importPath = p.absolutePath.replaceAll('\\', '/'); // absolute path with extension 104 | const importResult = (await _state.evalScope(`(async function() { 105 | try { 106 | const temporaryEvalResult = await import('${importPath}'); 107 | return temporaryEvalResult; 108 | } catch (err) { 109 | console.error(err); 110 | } 111 | })()`)); 112 | const classInstance = Object.entries(importResult)[0][1] as Function; 113 | 114 | const selectorPropertyValues = _(Object.keys(classInstance).filter(key => _state.config.propertySelectorRegex.test(key))).keyBy(x => x).mapValues(key => (classInstance)[key]).value(); 115 | 116 | const nestedTypeProps = staticProperties 117 | .filter(prop => _state.config.propertyNestedTypeRegex.test(prop.getType().getSymbol()?.getName() ?? '')); 118 | 119 | let selectorProperties = staticProperties 120 | .filter(prop => _state.config.propertySelectorRegex.test(prop.getName())) 121 | .map(prop => { 122 | const name = prop.getName(); 123 | const selector = selectorPropertyValues[name]; 124 | const selectorMethodName = _state.config.propertySelectorRegex.exec(name)?.[1]; 125 | const selectorMethodNode = staticMethods.find(m => m.getName() === selectorMethodName); 126 | const selectorMethod = selectorMethodNode 127 | ? { name: selectorMethodNode.getName(), args: selectorMethodNode.getParameters().map(p => p.getName()), body: selectorMethodNode.getText() } 128 | : { name: selectorMethodName, args: [], body: ''}; 129 | return { name, selector: selector, selectorMethod }; 130 | }); 131 | 132 | const nestedTypeProperties = nestedTypeProps.map(prop => { 133 | const name = prop.getName(); 134 | //const selectorPropName = _state.config.propertySelectorRegex.exec(name)?.[1]!; 135 | const selectorProp = selectorProperties.find(p => pageObjectModel._state.config.propertySelectorRegex.exec(p.name)?.[1] == name)!; 136 | const _type = prop.getType().getSymbol()!; 137 | const fullFilePath = _type.getDeclarations()[0].getSourceFile().getFilePath(); 138 | const filePath = nodePath.relative(_state.config.path, fullFilePath); 139 | return { name, selectorPropertyName: selectorProp.name, selector: selectorProp.selector, filePath }; 140 | }); 141 | 142 | selectorProperties = selectorProperties.filter(p => !nestedTypeProperties.some(n => n.selectorPropertyName === p.name)); 143 | 144 | const helperMethods = staticMethods.filter(m => !selectorProperties.some(p => m.getName() === _state.config.propertySelectorRegex.exec(p.name)?.[1])) 145 | .map(method => ({name: method.getName(), args: method.getParameters().map(p => p.getName()), body: method.getText()})); 146 | 147 | const evalString = `if (!PW_pages) {PW_pages = {}; } PW_pages[\`${p.filePath}\`] = { className: '${exportedClass.getName()}', selectors: ${JSON.stringify(selectorProperties)}, methods: ${JSON.stringify(helperMethods)}, nestedPages: ${JSON.stringify(nestedTypeProperties)}}`; 148 | await page.evaluate(evalString); 149 | 150 | if (nestedTypeProperties.length > 0) resultFilePaths.push(...await _reload(page, nestedTypeProperties.map(n => n.filePath), project)); //! recursively reload all nested page objects 151 | } 152 | 153 | return resultFilePaths; 154 | } 155 | 156 | async function _appendToPageObjectModel(fullRelativePath: string, className: string, codeBlock: string, config: { generateClassTemplate: (className: string) => string}) { 157 | await _ensurePageObjectModelCreated(fullRelativePath, className, config); 158 | try { 159 | let content = await fs.readFile(fullRelativePath, 'utf-8'); 160 | const position_endOfClass = content.lastIndexOf('}'); 161 | const before = content.slice(0, position_endOfClass - 1); 162 | const after = content.slice(position_endOfClass - 1); 163 | content = before + codeBlock + after; 164 | await fs.writeFile(fullRelativePath, content); 165 | } catch (error) { 166 | console.error(error); 167 | } 168 | } 169 | 170 | async function _ensurePageObjectModelCreated(fullRelativePath: string, className: string, config: { generateClassTemplate: (className: string) => string}) { 171 | try { 172 | await fs.mkdir(nodePath.dirname(fullRelativePath), { recursive: true }); 173 | await fs.writeFile(fullRelativePath, config.generateClassTemplate(className), { flag: 'wx'}); //if file is non-existant emit the standard template 174 | } catch (error) { 175 | if ((error).code === 'EEXIST') return; 176 | console.error(error); 177 | } 178 | } 179 | 180 | function classNameFromPath(path: string) { return /([^/]+).ts/.exec(path)![1]; } 181 | function fullRelativePath(path: string, config: { path: string }) { return nodePath.normalize(nodePath.join(config.path, path)); } 182 | 183 | export async function reloadAll(configPath: string, page: Page) { 184 | if (!currentPageFilePath) return; 185 | await reload(page); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/recorder.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "@playwright/test"; 2 | import fs from "fs/promises"; 3 | import chokidar from "chokidar"; 4 | import { PlaywrightLiveRecorderConfig_recorder } from "./types"; 5 | 6 | //exposes selectorConventions pieces (load, watch and reload, prependRecordingRule method) 7 | export module recorder { 8 | export async function init(config: PlaywrightLiveRecorderConfig_recorder, page: Page) { 9 | await page.exposeFunction('PW_addRule', (matcherCode: string) => prependRecordingRule(config.path, matcherCode)); 10 | await page.addScriptTag({ path: './node_modules/@dnvgl/playwright-live-recorder/dist/browser/PW_selectorConventions.js' }); 11 | try { await page.addScriptTag({ path: config.basepath }); } catch(err) { if ((err).code='ENOENT') return; throw err;} 12 | try { await page.addScriptTag({ path: config.path }); } catch(err) { if ((err).code='ENOENT') return; throw err;} 13 | 14 | const watch = chokidar.watch(config.path); 15 | watch.on('change', async path => await page.addScriptTag({ path })); 16 | } 17 | 18 | async function prependRecordingRule(config_recorder_path: string, matcherCode: string) { 19 | //todo: this code is ugly and cumbersome, find a more idomatic way to splice file content 20 | const matcherCodeLines = matcherCode.split(_NEWLINE).length; 21 | const selectorConventionsSrc = await fs.readFile(config_recorder_path, 'utf-8'); 22 | const lines = selectorConventionsSrc.split(_NEWLINE); 23 | const insertLineIndex = lines.indexOf('var PW_selectorConventions = [') + 1; 24 | lines.splice(insertLineIndex, 0, 25 | ` { 26 | match: (el) => ${matcherCodeLines == 1 ? matcherCode : '{\n ' + matcherCode.split('\n').join('\n ') + '\n }'}, 27 | output: (selector) => \`await page.locator('\${selector}').click();\` 28 | },`); 29 | 30 | await fs.writeFile(config_recorder_path, lines.join('\n')); 31 | } 32 | } 33 | const _NEWLINE = /\r\n|\n|\r/; -------------------------------------------------------------------------------- /src/testFileWriter.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "@playwright/test"; 2 | import fs from "fs/promises"; 3 | import { Project, ts } from "ts-morph"; 4 | import { TestCallingLocation } from "./types"; 5 | 6 | export module testFileWriter { 7 | export async function init(page: Page, testCallingLocation: TestCallingLocation) { 8 | await page.exposeFunction('PW_appendToTest', async (testEval: string, importStatement: string|undefined) => await _appendToTest(testCallingLocation, testEval, importStatement)); 9 | } 10 | 11 | export async function _appendToTest(t: TestCallingLocation, str: string, importStatement: string|undefined = undefined) { 12 | const indentation = /(\s*)/.exec(t.executingLine)![1]; 13 | const testFileSrcLines = (await fs.readFile(t.file, 'utf-8')).split(_NEWLINE); 14 | 15 | if (importStatement !== undefined && !testFileSrcLines.includes(importStatement)){ 16 | let proj = new Project({ compilerOptions: { target: ts.ScriptTarget.ESNext, strict: false, skipDefaultLibCheck: true } }); 17 | const ast = proj.addSourceFileAtPath(t.file); 18 | const imports = ast.getChildrenOfKind(ts.SyntaxKind.ImportDeclaration); 19 | //todo: parse importStatement, only add the line if no pre-existing import from the source file 20 | const lastImportLine = Math.max(...imports.map(i => i.getEndLineNumber())); 21 | testFileSrcLines.splice(lastImportLine, 0, importStatement); 22 | } 23 | 24 | const testLineNumber = testFileSrcLines.indexOf(t.testLine); 25 | const insertLineNumber = testFileSrcLines.indexOf(t.executingLine, testLineNumber); 26 | 27 | testFileSrcLines.splice(insertLineNumber, 0, `${indentation}${str}`); 28 | 29 | const newFileContent = testFileSrcLines.join('\n'); 30 | await fs.writeFile(t.file, newFileContent); 31 | } 32 | const _NEWLINE = /\r\n|\n|\r/; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "@playwright/test" 2 | 3 | export type PlaywrightLiveRecorderConfig = { 4 | recorder: PlaywrightLiveRecorderConfig_recorder, 5 | pageObjectModel: PlaywrightLiveRecorderConfig_pageObjectModel, 6 | diagnostic: PlaywrightLiveRecorderConfig_diagnostic, 7 | }; 8 | 9 | type RecursivePartial = { 10 | [P in keyof T]?: 11 | T[P] extends (infer U)[] ? RecursivePartial[] : 12 | T[P] extends object ? RecursivePartial : 13 | T[P]; 14 | }; 15 | 16 | 17 | export type PlaywrightLiveRecorderConfigFile = RecursivePartial; 18 | 19 | export type PlaywrightLiveRecorderConfig_pageObjectModel = { 20 | /** @default true */ 21 | enabled: boolean, 22 | /** @default './tests/' */ 23 | path: string, 24 | /** @default '**\/*_page.ts' */ 25 | filenameConvention: string, 26 | /** @default use.baseURL value from Playwright config */ 27 | baseUrl: string|undefined, 28 | /** @default 5000 */ 29 | actionTimeout: number, 30 | /** @default 'global_page.ts' */ 31 | globalPageFilePath: string, 32 | /** @default (url: string, aliases: {[key: string]: string}) => { 33 | let filePath = url 34 | .replace(new RegExp(`^${config.pageObjectModel.baseUrl}`), '') //cut out base url 35 | .replace(/[a-fA-F0-9]{8}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{12}/g, '') //cut out guids 36 | .replace(/\/\d+(?=\/)/g, '/') // cut out /###/ fragments 37 | .replace(/\d+\//g, '/') // cut out /###/ fragments if there were any left over 38 | .replace(/\/\d+$/g, '/') // cut out /### fragments at end 39 | .replace(/-/g, '_') //replace all hyphens with underscores, valid classname 40 | .replace(/\/\/+/g, '/') // if we end up with two // in a row, replace it with one 41 | .replace(/\/$/, '') // clear trailing / 42 | .replace(/^\//, ''); // clear leading / 43 | 44 | if (filePath in aliases) filePath = aliases[filePath]; //apply aliases 45 | return filePath + '_page.ts'; 46 | } 47 | */ 48 | urlToFilePath: (url: string, aliases: {[key: string]: string}) => string, 49 | /** 50 | * @remarks use to override/alias url fragments to page object model name 51 | * @example { '': 'home', 'login/corporate' : 'login', 'login/personal' : 'login' } //redirect from root address to 'home' pom. use same pom for login/corporate and login/personal 52 | */ aliases: {[key: string]: string}, 53 | /** @remarks Use this to find list of all selectors, and lookup method from selector @default /(.+)_selector\b/*/ 54 | propertySelectorRegex: RegExp, 55 | /** @remarks Use this to find list of nested page objects within a given page object model file @default /(.+)_page\b/*/ 56 | propertyNestedTypeRegex: RegExp, 57 | /** @remarks Use this to specify the text appended when LEFT clicked on in record mode @default [ ["input[type="text"]", 'fill()'], ["textarea", 'fill()'], ["/.*\/", "click()"] ] */ 58 | primaryActionByCssSelector: [string, string][], 59 | /** @remarks Use this to specify the text appended when RIGHT clicked on in record mode @default [ ["input[type="text"]", "await expect($1.innerText()).toContain('')"], ["textarea", "innerText().toContain('')"], ["/.*\/", ""]]*/ 60 | secondaryActionByCssSelector: [string, string][], 61 | /** @default (className) => 62 | `import { Page } from "@playwright/test"; 63 | 64 | export class ${className} { 65 | 66 | }`, 67 | */ 68 | generateClassTemplate: (className: string) => string, 69 | /** @default (name, selector) => 70 | ` private static ${name}_selector = \`${selector}\`;\r\n` + 71 | ` static ${name}(page: Page) { return page.locator(\`this.${name}_selector\`); }\r\n\r\n`, 72 | */ 73 | generatePropertyTemplate: (name: string, selector: string) => string, 74 | 75 | /** @default (name) => 76 | ` static async ${name}(page: Page) {\r\n \r\n }\r\n\r\n`, 77 | */ 78 | generateMethodTemplate: (name: string) => string, 79 | overlay: { 80 | /** @default 'salmon' */ 81 | color: string, 82 | /** @default (el, color) => { 83 | el.setAttribute('data-background', el.style.background); 84 | el.style.background = color; 85 | }, 86 | */ 87 | on: (el: HTMLElement, color: string) => void, 88 | /** @default (el) => el.style.background = el.getAttribute('data-background') ?? '', */ 89 | off: (el: HTMLElement) => void, 90 | }, 91 | importerCustomizationHooks: string, 92 | } 93 | 94 | export type PlaywrightLiveRecorderConfig_recorder = { 95 | /** @default './PW_selectorConventions.js' */ 96 | path: string, 97 | /** @default './node_modules/@dnvgl/playwright-live-recorder/dist/browser/PW_selectorConventions.js' */ 98 | basepath: string, 99 | } 100 | 101 | export type PlaywrightLiveRecorderConfig_diagnostic = { 102 | /** @default './node_modules/@dnvgl/playwright-live-recorder/dist/browser/PW_live.js' */ 103 | browserCodeJSPath: string, 104 | /** @default './node_modules/@dnvgl/playwright-live-recorder/dist/browser/PW_live.css' */ 105 | browserCodeCSSPath: string, 106 | /** @default false */ 107 | hotReloadBrowserLibFiles: boolean, 108 | } 109 | 110 | export type TestCallingLocation = { file: string, testLine: string, testLineNumber: number, executingLine: string }; -------------------------------------------------------------------------------- /src/utility.ts: -------------------------------------------------------------------------------- 1 | import { test } from "@playwright/test"; 2 | import ErrorStackParser from "error-stack-parser"; 3 | import fs from "fs/promises"; 4 | import path from "node:path"; 5 | import url from "node:url"; 6 | import { TestCallingLocation } from "./types"; 7 | 8 | export async function getTestCallingLocation() { 9 | const testInfo = test.info(); 10 | const testInfoFile = path.normalize(testInfo.file); 11 | const fileUrl = url.pathToFileURL(testInfoFile).toString(); 12 | const stack = ErrorStackParser.parse(new Error()).find(s => s.fileName === fileUrl || s.fileName === testInfoFile)!; /* different versions of node format the stack filename differently */ 13 | const testFileSrcLines = (await fs.readFile(testInfoFile, 'utf-8')).split(_NEWLINE); 14 | const testCallingLocation = { file: testInfoFile, testLine: testFileSrcLines[testInfo.line - 1], testLineNumber: testInfo.line, executingLine: testFileSrcLines[stack.lineNumber! - 1] }; 15 | return testCallingLocation; 16 | } 17 | 18 | export const _NEWLINE = /\r\n|\n|\r/; 19 | 20 | export function createQueuedRunner(asyncFn: (...args: any[]) => Promise) { 21 | let isRunning = false; 22 | let rerunRequested = false; 23 | 24 | async function runner(...args: any[]) { 25 | if (isRunning) { 26 | rerunRequested = true; 27 | return; 28 | } 29 | 30 | isRunning = true; 31 | do { 32 | rerunRequested = false; 33 | await asyncFn(...args); 34 | } while (rerunRequested); 35 | 36 | isRunning = false; 37 | } 38 | 39 | return runner; 40 | } -------------------------------------------------------------------------------- /tests/example-test-project/docs/intro_page.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "@playwright/test"; 2 | import { createGuid } from '../testHelpers'; 3 | 4 | const doc = "abc"; 5 | 6 | export class intro_page { 7 | private static title_selector = `h1:has-text("Installation")`; 8 | static title(page: Page) { return page.locator(this.title_selector); } 9 | 10 | private static home_selector = `b:has-text("Playwright")`; 11 | static home(page: Page) { 12 | const iAmGuid = createGuid(); 13 | return page.locator(this.home_selector); 14 | } 15 | 16 | 17 | } -------------------------------------------------------------------------------- /tests/example-test-project/example.spec.after.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test'; 2 | import { PlaywrightLiveRecorder } from '@dnvgl/playwright-live-recorder'; 3 | import { intro_page } from './docs/intro_page'; 4 | 5 | test.describe('describe block', () => { 6 | test('simple test', async ({ page }) => { 7 | await page.goto('www.google.com'); 8 | await expect(page).toHaveTitle('Google'); 9 | 10 | await PlaywrightLiveRecorder.start(page, s => eval(s)); 11 | }); 12 | }); -------------------------------------------------------------------------------- /tests/example-test-project/example.spec.before.ts: -------------------------------------------------------------------------------- 1 | import { test } from '@playwright/test'; 2 | import { PlaywrightLiveRecorder } from '@dnvgl/playwright-live-recorder'; 3 | 4 | test.describe('describe block', () => { 5 | test('simple test', async ({ page }) => { 6 | await page.goto('www.google.com'); 7 | 8 | await PlaywrightLiveRecorder.start(page, s => eval(s)); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /tests/example-test-project/testHelpers.ts: -------------------------------------------------------------------------------- 1 | const doc = "abc"; 2 | export function createGuid() { 3 | return 'b87e0a22-6172-4dab-9643-1c170df1b0cd'; 4 | } 5 | 6 | export async function fnPromise() { 7 | return await Promise.resolve(createGuid()); 8 | } -------------------------------------------------------------------------------- /tests/hotModuleReload.test.ts: -------------------------------------------------------------------------------- 1 | import { ts, Project, ScriptTarget } from 'ts-morph'; 2 | import { hotModuleReload } from '../src/hotModuleReload'; 3 | import nodePath from 'node:path'; 4 | import { TestCallingLocation } from '../src/types'; 5 | import { expect, test } from 'vitest'; 6 | 7 | test('typescript transpile performance profiling', async () => { 8 | /* 9 | const testFilename = nodePath.resolve(filename); 10 | 11 | let proj = new Project({compilerOptions: { target: ts.ScriptTarget.ESNext, strict: false }}); 12 | 13 | 14 | 15 | proj.addSourceFileAtPath(testFilename); 16 | proj.resolveSourceFileDependencies(); 17 | 18 | proj.getSourceFiles().map(f => f.getChildrenOfKind(ts.SyntaxKind.ImportDeclaration).forEach(x => x.remove())); //snip all interdependencies 19 | const r = proj.emitToMemory(); 20 | const files = r.getFiles(); 21 | 22 | const ambientCode = files 23 | .filter(f => nodePath.resolve(f.filePath).replace(/\.js$/, '.ts') !== testFilename) //exclude the test file from the ambient code 24 | .reverse() 25 | .map(f => `//${f.filePath} transpiled\n${f.text.replace(/^export\s?/gm, '')}`) 26 | .join('\n\n'); 27 | 28 | return ambientCode; 29 | */ 30 | const options = { compilerOptions: { target: ts.ScriptTarget.ESNext, strict: false, skipLibCheck: true } }; 31 | const testFilename = nodePath.resolve('./tests/example-test-project/example.spec.after.ts'); 32 | 33 | console.time('_emitInlinedDependencies'); 34 | let proj = new Project(options); 35 | proj.addSourceFileAtPath(testFilename); 36 | const allFiles = proj.emitToMemory().getFiles().map(f => f.filePath.replace(/\.js$/, '.ts')); //get dependency graph in dependency order 37 | proj = new Project(options); 38 | allFiles.forEach(path => proj.addSourceFileAtPath(path)); 39 | proj.getSourceFiles().map(f => f.getChildrenOfKind(ts.SyntaxKind.ImportDeclaration).forEach(x => x.remove())); //snip all interdependencies 40 | const files = proj.emitToMemory().getFiles(); 41 | 42 | const inlinedDependencies = files 43 | .filter(f => nodePath.resolve(f.filePath).replace(/\.js$/, '.ts') !== testFilename) //exclude the test file from the ambient code 44 | .map((f, index) => ({ path: f.filePath, src: `//${f.filePath} transpiled\n${f.text.replace(/^export\s?/gm, '')}`, index })) 45 | .reduce((obj, x) => (obj[x.path] = x, obj), <{[path: string]: {path: string, src: string, index: number}}>{}); 46 | 47 | console.timeEnd('_emitInlinedDependencies'); 48 | 49 | expect(allFiles).toEqual([ 50 | "C:/_dev/playwright-live-recorder/tests/example-test-project/testHelpers.ts", 51 | "C:/_dev/playwright-live-recorder/tests/example-test-project/docs/intro_page.ts", 52 | "C:/_dev/playwright-live-recorder/tests/example-test-project/example.spec.after.ts" 53 | ]); 54 | 55 | expect(Object.values(inlinedDependencies).map(x => x.src)).toEqual([ 56 | `//C:/_dev/playwright-live-recorder/tests/example-test-project/testHelpers.js transpiled 57 | const doc = "abc"; 58 | function createGuid() { 59 | return 'b87e0a22-6172-4dab-9643-1c170df1b0cd'; 60 | } 61 | async function fnPromise() { 62 | return await Promise.resolve(createGuid()); 63 | } 64 | `, 65 | `//C:/_dev/playwright-live-recorder/tests/example-test-project/docs/intro_page.js transpiled 66 | const doc = "abc"; 67 | class intro_page { 68 | static title_selector = \`h1:has-text("Installation")\`; 69 | static title(page) { return page.locator(this.title_selector); } 70 | static home_selector = \`b:has-text("Playwright")\`; 71 | static home(page) { 72 | const iAmGuid = createGuid(); 73 | return page.locator(this.home_selector); 74 | } 75 | } 76 | `, 77 | ]); 78 | }); 79 | 80 | 81 | test('typescript transpile performance profiling2', async () => { 82 | const options = { compilerOptions: { target: ts.ScriptTarget.ESNext, strict: false, skipLibCheck: true } }; 83 | const testFilename = nodePath.resolve('./tests/example-test-project/example.spec.after.ts'); 84 | 85 | console.time('_emitInlinedDependencies'); 86 | let proj = new Project(options); 87 | 88 | proj.addSourceFileAtPath(testFilename); 89 | proj.resolveSourceFileDependencies(); 90 | 91 | proj.getSourceFiles().map(f => f.getChildrenOfKind(ts.SyntaxKind.ImportDeclaration).forEach(x => x.remove())); //snip all interdependencies 92 | const r = proj.emitToMemory(); 93 | const files = r.getFiles(); 94 | const allFiles = files.map(x => x.filePath).reverse(); 95 | 96 | const inlinedDependencies = files 97 | .filter(f => nodePath.resolve(f.filePath).replace(/\.js$/, '.ts') !== testFilename) //exclude the test file from the ambient code 98 | .reverse() 99 | .map((f, index) => ({ path: f.filePath, src: `//${f.filePath} transpiled\n${f.text.replace(/^export\s?/gm, '')}`, index })) 100 | .reduce((obj, x) => (obj[x.path] = x, obj), <{[path: string]: {path: string, src: string, index: number}}>{}); 101 | 102 | console.timeEnd('_emitInlinedDependencies'); 103 | 104 | expect(allFiles).toEqual([ 105 | "C:/_dev/playwright-live-recorder/tests/example-test-project/testHelpers.js", 106 | "C:/_dev/playwright-live-recorder/tests/example-test-project/docs/intro_page.js", 107 | "C:/_dev/playwright-live-recorder/tests/example-test-project/example.spec.after.js" 108 | ]); 109 | 110 | expect(Object.values(inlinedDependencies).map(x => x.src)).toEqual([ 111 | `//C:/_dev/playwright-live-recorder/tests/example-test-project/testHelpers.js transpiled 112 | const doc = "abc"; 113 | function createGuid() { 114 | return 'b87e0a22-6172-4dab-9643-1c170df1b0cd'; 115 | } 116 | async function fnPromise() { 117 | return await Promise.resolve(createGuid()); 118 | } 119 | `, 120 | `//C:/_dev/playwright-live-recorder/tests/example-test-project/docs/intro_page.js transpiled 121 | const doc = "abc"; 122 | class intro_page { 123 | static title_selector = \`h1:has-text("Installation")\`; 124 | static title(page) { return page.locator(this.title_selector); } 125 | static home_selector = \`b:has-text("Playwright")\`; 126 | static home(page) { 127 | const iAmGuid = createGuid(); 128 | return page.locator(this.home_selector); 129 | } 130 | } 131 | `, 132 | ]); 133 | }); 134 | 135 | test('typescript compile performance', async () => { 136 | const options = { compilerOptions: { target: ts.ScriptTarget.ESNext, strict: false, skipLibCheck: true } }; 137 | 138 | 139 | /* 2.4s 140 | let proj = new Project(options); 141 | const f = proj.addSourceFileAtPath('C:/_dev/playwright-live-recorder/tests/example-test-project/docs/intro_page.ts'); 142 | f.getChildrenOfKind(ts.SyntaxKind.ImportDeclaration).forEach(x => x.remove()); 143 | const transpiled = proj.emitToMemory().getFiles()[0]; 144 | */ 145 | 146 | //const src = await fs.readFile('C:/_dev/playwright-live-recorder/tests/example-test-project/docs/intro_page.ts', 'utf-8'); //3ms 147 | //const result = typescript.transpileModule(src.replace(/^import.*/gm,''), options); //65ms 148 | 149 | console.time('extract imports'); 150 | let proj = new Project(options); 151 | const f = proj.addSourceFileAtPath('C:/_dev/playwright-live-recorder/tests/example-test-project/docs/intro_page.ts'); 152 | const imports = f.getChildrenOfKind(ts.SyntaxKind.ImportDeclaration); 153 | console.timeEnd('extract imports'); 154 | }); 155 | 156 | test('hotModuleReload reloadTestFile', async () => { 157 | const testCallingLocation: TestCallingLocation = { 158 | file: `./tests/example-test-project/example.spec.before.ts`, 159 | testLine: ` test('simple test', async ({ page }) => {`, 160 | testLineNumber: 6, 161 | executingLine: ` await PlaywrightLiveRecorder.start(page, s => eval(s));`, 162 | }; 163 | let evalText: string; 164 | await hotModuleReload.init(testCallingLocation, (str: string) => console.log(`pageEvaluate: ${str}`), (s: string) => evalText = s); 165 | const s = hotModuleReload._state; 166 | await hotModuleReload._initialTestFileLoad(s); 167 | 168 | s.t.file = `./tests/example-test-project/example.spec.after.ts`; 169 | await hotModuleReload._reloadTestFile(s); 170 | 171 | expect(evalText!.replace(/\r\n/g, "\n")).toEqual( 172 | `//######## C:\\_dev\\playwright-live-recorder\\tests\\example-test-project\\docs\\intro_page.ts ######## 173 | /*im { Page } from "@playwright/test";*/ 174 | /*im { createGuid } from '../testHelpers';*/ 175 | var doc = "abc"; 176 | /*ex*/ class intro_page { 177 | static title_selector = \`h1:has-text("Installation")\`; 178 | static title(page) { return page.locator(this.title_selector); } 179 | static home_selector = \`b:has-text("Playwright")\`; 180 | static home(page) { 181 | const iAmGuid = createGuid(); 182 | return page.locator(this.home_selector); 183 | } 184 | } 185 | 186 | 187 | (async function() { 188 | try { 189 | await expect(page).toHaveTitle('Google'); 190 | 191 | 192 | 193 | } catch (err) { 194 | console.error(err); 195 | } 196 | })()`); 197 | }); 198 | 199 | test('hotModuleReload _getBlockToExecute', async () => { 200 | const testDecl = `test('simple test', async ({ page }) => {`; 201 | 202 | const fnContents = (await hotModuleReload._extractFnContents('./tests/example-test-project/example.spec.before.ts', testDecl, 6, ' await PlaywrightLiveRecorder.start(page, s => eval(s));'))!; 203 | const newFnContents = (await hotModuleReload._extractFnContents('./tests/example-test-project/example.spec.after.ts', testDecl, 6, ' await PlaywrightLiveRecorder.start(page, s => eval(s));'))!; 204 | 205 | const blockToExecute = hotModuleReload._getBlockToExecute(fnContents, newFnContents); 206 | const expectedNewBlock = ` await expect(page).toHaveTitle('Google');`; 207 | 208 | expect(blockToExecute.trimEnd()).toEqual(expectedNewBlock); 209 | }); 210 | 211 | 212 | test('load dependency graph for test', async () => { 213 | const newLinesToExecute = 214 | ` await fnPromise(); 215 | var abc=123; 216 | await fnPromise(); 217 | ` 218 | 219 | 220 | const testFilename = nodePath.resolve('./tests/example-test-project/example.spec.after.ts'); 221 | 222 | let proj = new Project(); //todo: figure out options that make this faster... 223 | proj.addSourceFileAtPath(testFilename); 224 | const allFiles = proj.emitToMemory().getFiles().map(f => f.filePath); //get dependency graph in dependency order 225 | 226 | 227 | //create a fresh project with every individual dependency added (in order) 228 | proj = new Project({compilerOptions: { target: ScriptTarget.ESNext, strict: false }}); 229 | allFiles.forEach(path => proj.addSourceFileAtPath(/* nodePath.relative(nodePath.resolve('.'), path) */path.replace(/\.js$/, '.ts'))); 230 | 231 | proj.getSourceFiles().map(f => f.getChildrenOfKind(ts.SyntaxKind.ImportDeclaration).forEach(x => x.remove())); //snip all interdependencies 232 | const r = proj.emitToMemory(); 233 | const files = r.getFiles(); 234 | const testFilenameJs = testFilename.replace(/\\/g, '/').replace(/\.ts$/, '.js'); 235 | const ambientCode = files.filter(f => f.filePath !== testFilenameJs).map(f => `//${f.filePath}\n${f.text.replace(/^export\s?/gm, '').replaceAll(/const /gm, 'var ')}`).join('\n\n'); 236 | const testCode = ` 237 | //execute test lines here 238 | ${wrapAsyncAsPromise(newLinesToExecute, ['abc'])}`; 239 | 240 | //console.log(testCode); 241 | const awaitedEvalResult = await eval(ambientCode + testCode); 242 | console.log({ awaitedEvalResult }); 243 | 244 | Object.assign(globalThis, awaitedEvalResult); 245 | const oneTwoThreeOneTwoThree = await eval(`${ambientCode}\n${wrapAsyncAsPromise("var abc123 = abc + '123';", ['abc123'])}`); 246 | console.log({oneTwoThreeOneTwoThree}); 247 | }); 248 | 249 | function wrapAsyncAsPromise(codeBlock: string, variables: string[]) { 250 | return `(async function() { 251 | ${codeBlock} 252 | return { ${variables.join(', ')} }; 253 | })()`; 254 | } 255 | 256 | 257 | test('extract var statements', async () => { 258 | const variables = hotModuleReload._extractVariableListFrom( 259 | `var varABC = 123; 260 | let letABC = 123; 261 | const constABC = 123; 262 | const {abc, def} = {abc: 123, def: 456, xyz: 789};`); 263 | 264 | expect(variables).toEqual(['varABC', 'letABC', 'constABC', 'abc', 'def']); 265 | 266 | }); 267 | 268 | test('extract import statements', async() => { 269 | const testFilename = nodePath.resolve('./tests/example-test-project/example.spec.before.ts'); 270 | const imports = hotModuleReload._extractImports(testFilename); 271 | console.log({imports}); 272 | }); 273 | 274 | 275 | 276 | 277 | /* 278 | single watcher, can have set of files being watched be mutated 279 | 280 | 281 | initial load 282 | full dependency graph from test_file.ts 283 | add files to watcher list 284 | {[path: string]: {imports: ImportDeclaration[], transpiled: string}} 285 | 286 | Discovery pass - ts-morph.emitToMemory (slow ~4s) 287 | 288 | * [test_file.ts] 289 | / | \ 290 | * * * [intro_page.ts, home_page.ts] 291 | | 292 | * [gridUtil.ts requires lodash] 293 | 294 | transpile pass 295 | re evaluate imports (ts-morph 20ms) 296 | if imports list changed, perform discovery pass (on this file) 297 | if any new files, add to watcher list, and transpile them 298 | 299 | strip imports (replace with commented out line? string manipulation) 300 | typescript.transpileModule (fast 80ms/file) 301 | 302 | */ 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | -------------------------------------------------------------------------------- /tests/pageObjectModel.test.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'vitest'; 2 | import { pageObjectModel } from '../src/pageObjectModel'; 3 | import { PlaywrightLiveRecorderConfig_pageObjectModel } from '../src/types'; 4 | 5 | test('pageObjectModel _transpile', async () => { 6 | const normalizedFilePath = 'docs/intro_page.ts'; 7 | const className = 'intro_page'; 8 | 9 | pageObjectModel._state = (>{config: {path: 'tests/example-test-project/'}}); 10 | const pomEntry = await pageObjectModel._transpile2(normalizedFilePath, className); 11 | 12 | console.log(pomEntry.content); 13 | 14 | }); 15 | 16 | test('pageObjectModel _transpile with utlity class dep', async () => { 17 | pageObjectModel._state = (>{config: {path: 'tests/example-test-project/'}}); 18 | 19 | const pomEntry = await pageObjectModel._transpile2('docs/intro_page.ts', 'intro_page'); 20 | 21 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "target": "ESNext", 5 | "module": "CommonJS", 6 | "lib": ["esnext", "dom"], 7 | "allowJs": false, /* Allow javascript files to be compiled. */ 8 | //"checkJs": true, /* Report errors in .js files. */ 9 | "outDir": "./dist", /* Redirect output structure to the directory. */ 10 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 11 | "declaration": true, 12 | "esModuleInterop": true, 13 | 14 | "strict": true, /* Enable all strict type-checking options. */ 15 | "types": ["node", "vitest/globals"], 16 | "allowSyntheticDefaultImports": true, 17 | 18 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 19 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 20 | }, 21 | "include": [ "src/**/*.ts", "test/**/*.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "off", 3 | "jsRules": { 4 | }, 5 | "rules": { 6 | "no-floating-promises": { 7 | "severity": "error" 8 | }, 9 | "no-unbound-method": { 10 | "severity": "error" 11 | } 12 | }, 13 | "rulesDirectory": [] 14 | } -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: { 5 | globals: true, 6 | testTimeout: 20000, 7 | }, 8 | }) -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.18.6" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" 8 | integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== 9 | dependencies: 10 | "@babel/highlight" "^7.18.6" 11 | 12 | "@babel/helper-validator-identifier@^7.18.6": 13 | version "7.18.6" 14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" 15 | integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== 16 | 17 | "@babel/highlight@^7.18.6": 18 | version "7.18.6" 19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" 20 | integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== 21 | dependencies: 22 | "@babel/helper-validator-identifier" "^7.18.6" 23 | chalk "^2.0.0" 24 | js-tokens "^4.0.0" 25 | 26 | "@cspotcode/source-map-support@^0.8.0": 27 | version "0.8.1" 28 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" 29 | integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== 30 | dependencies: 31 | "@jridgewell/trace-mapping" "0.3.9" 32 | 33 | "@esbuild/aix-ppc64@0.21.5": 34 | version "0.21.5" 35 | resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" 36 | integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== 37 | 38 | "@esbuild/android-arm64@0.21.5": 39 | version "0.21.5" 40 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" 41 | integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== 42 | 43 | "@esbuild/android-arm@0.21.5": 44 | version "0.21.5" 45 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" 46 | integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== 47 | 48 | "@esbuild/android-x64@0.21.5": 49 | version "0.21.5" 50 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" 51 | integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== 52 | 53 | "@esbuild/darwin-arm64@0.21.5": 54 | version "0.21.5" 55 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" 56 | integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== 57 | 58 | "@esbuild/darwin-x64@0.21.5": 59 | version "0.21.5" 60 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" 61 | integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== 62 | 63 | "@esbuild/freebsd-arm64@0.21.5": 64 | version "0.21.5" 65 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" 66 | integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== 67 | 68 | "@esbuild/freebsd-x64@0.21.5": 69 | version "0.21.5" 70 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" 71 | integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== 72 | 73 | "@esbuild/linux-arm64@0.21.5": 74 | version "0.21.5" 75 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" 76 | integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== 77 | 78 | "@esbuild/linux-arm@0.21.5": 79 | version "0.21.5" 80 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" 81 | integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== 82 | 83 | "@esbuild/linux-ia32@0.21.5": 84 | version "0.21.5" 85 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" 86 | integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== 87 | 88 | "@esbuild/linux-loong64@0.21.5": 89 | version "0.21.5" 90 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" 91 | integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== 92 | 93 | "@esbuild/linux-mips64el@0.21.5": 94 | version "0.21.5" 95 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" 96 | integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== 97 | 98 | "@esbuild/linux-ppc64@0.21.5": 99 | version "0.21.5" 100 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" 101 | integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== 102 | 103 | "@esbuild/linux-riscv64@0.21.5": 104 | version "0.21.5" 105 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" 106 | integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== 107 | 108 | "@esbuild/linux-s390x@0.21.5": 109 | version "0.21.5" 110 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" 111 | integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== 112 | 113 | "@esbuild/linux-x64@0.21.5": 114 | version "0.21.5" 115 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" 116 | integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== 117 | 118 | "@esbuild/netbsd-x64@0.21.5": 119 | version "0.21.5" 120 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" 121 | integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== 122 | 123 | "@esbuild/openbsd-x64@0.21.5": 124 | version "0.21.5" 125 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" 126 | integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== 127 | 128 | "@esbuild/sunos-x64@0.21.5": 129 | version "0.21.5" 130 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" 131 | integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== 132 | 133 | "@esbuild/win32-arm64@0.21.5": 134 | version "0.21.5" 135 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" 136 | integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== 137 | 138 | "@esbuild/win32-ia32@0.21.5": 139 | version "0.21.5" 140 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" 141 | integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== 142 | 143 | "@esbuild/win32-x64@0.21.5": 144 | version "0.21.5" 145 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" 146 | integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== 147 | 148 | "@jridgewell/resolve-uri@^3.0.3": 149 | version "3.1.0" 150 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" 151 | integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== 152 | 153 | "@jridgewell/sourcemap-codec@^1.4.10": 154 | version "1.4.14" 155 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" 156 | integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== 157 | 158 | "@jridgewell/sourcemap-codec@^1.5.0": 159 | version "1.5.0" 160 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" 161 | integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== 162 | 163 | "@jridgewell/trace-mapping@0.3.9": 164 | version "0.3.9" 165 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" 166 | integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== 167 | dependencies: 168 | "@jridgewell/resolve-uri" "^3.0.3" 169 | "@jridgewell/sourcemap-codec" "^1.4.10" 170 | 171 | "@nodelib/fs.scandir@2.1.5": 172 | version "2.1.5" 173 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" 174 | integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== 175 | dependencies: 176 | "@nodelib/fs.stat" "2.0.5" 177 | run-parallel "^1.1.9" 178 | 179 | "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": 180 | version "2.0.5" 181 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" 182 | integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== 183 | 184 | "@nodelib/fs.walk@^1.2.3": 185 | version "1.2.8" 186 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" 187 | integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== 188 | dependencies: 189 | "@nodelib/fs.scandir" "2.1.5" 190 | fastq "^1.6.0" 191 | 192 | "@playwright/test@^1.0.0": 193 | version "1.25.2" 194 | resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.25.2.tgz#e726cf4844f096315c3954fdb3abf295cede43ba" 195 | integrity sha512-6qPznIR4Fw02OMbqXUPMG6bFFg1hDVNEdihKy0t9K0dmRbus1DyP5Q5XFQhGwEHQkLG5hrSfBuu9CW/foqhQHQ== 196 | dependencies: 197 | "@types/node" "*" 198 | playwright-core "1.25.2" 199 | 200 | "@rollup/rollup-android-arm-eabi@4.29.1": 201 | version "4.29.1" 202 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz#9bd38df6a29afb7f0336d988bc8112af0c8816c0" 203 | integrity sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw== 204 | 205 | "@rollup/rollup-android-arm64@4.29.1": 206 | version "4.29.1" 207 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.1.tgz#bd1a98390e15b76eeef907175a37c5f0f9e4d214" 208 | integrity sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew== 209 | 210 | "@rollup/rollup-darwin-arm64@4.29.1": 211 | version "4.29.1" 212 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.1.tgz#bc6fa8a2cc77b5f367424e5e994e3537524e6879" 213 | integrity sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw== 214 | 215 | "@rollup/rollup-darwin-x64@4.29.1": 216 | version "4.29.1" 217 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.1.tgz#76059c91f06b17406347b127df10f065283b2e61" 218 | integrity sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng== 219 | 220 | "@rollup/rollup-freebsd-arm64@4.29.1": 221 | version "4.29.1" 222 | resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.1.tgz#83178315c0be4b4c8c1fd835e1952d2dc1eb4e6e" 223 | integrity sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw== 224 | 225 | "@rollup/rollup-freebsd-x64@4.29.1": 226 | version "4.29.1" 227 | resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.1.tgz#1ef24fa0576bf7899a0a0a649156606dbd7a0d46" 228 | integrity sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w== 229 | 230 | "@rollup/rollup-linux-arm-gnueabihf@4.29.1": 231 | version "4.29.1" 232 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.1.tgz#443a6f5681bf4611caae42988994a6d8ee676216" 233 | integrity sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A== 234 | 235 | "@rollup/rollup-linux-arm-musleabihf@4.29.1": 236 | version "4.29.1" 237 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.1.tgz#9738b27184102228637a683e5f35b22ea352394f" 238 | integrity sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ== 239 | 240 | "@rollup/rollup-linux-arm64-gnu@4.29.1": 241 | version "4.29.1" 242 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.1.tgz#b5e9d5e30ff36a19bedd29c715ba18a1889ff269" 243 | integrity sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA== 244 | 245 | "@rollup/rollup-linux-arm64-musl@4.29.1": 246 | version "4.29.1" 247 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.1.tgz#1d8f68f0829b57f746ec03432ad046f1af014a98" 248 | integrity sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA== 249 | 250 | "@rollup/rollup-linux-loongarch64-gnu@4.29.1": 251 | version "4.29.1" 252 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.1.tgz#07027feb883408e74a3002c8e50caaedd288ae38" 253 | integrity sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw== 254 | 255 | "@rollup/rollup-linux-powerpc64le-gnu@4.29.1": 256 | version "4.29.1" 257 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.1.tgz#544ce1b0847a9c1240425e86f33daceac7ec4e12" 258 | integrity sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w== 259 | 260 | "@rollup/rollup-linux-riscv64-gnu@4.29.1": 261 | version "4.29.1" 262 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.1.tgz#64be13d51852ec1e2dfbd25d997ed5f42f35ea6d" 263 | integrity sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ== 264 | 265 | "@rollup/rollup-linux-s390x-gnu@4.29.1": 266 | version "4.29.1" 267 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.1.tgz#31f51e1e05c6264552d03875d9e2e673f0fd86e3" 268 | integrity sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g== 269 | 270 | "@rollup/rollup-linux-x64-gnu@4.29.1": 271 | version "4.29.1" 272 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz#f4c95b26f4ad69ebdb64b42f0ae4da2a0f617958" 273 | integrity sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ== 274 | 275 | "@rollup/rollup-linux-x64-musl@4.29.1": 276 | version "4.29.1" 277 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz#ab7be89192f72beb9ea6e2386186fefde4f69d82" 278 | integrity sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA== 279 | 280 | "@rollup/rollup-win32-arm64-msvc@4.29.1": 281 | version "4.29.1" 282 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.1.tgz#7f12efb8240b238346951559998802722944421e" 283 | integrity sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig== 284 | 285 | "@rollup/rollup-win32-ia32-msvc@4.29.1": 286 | version "4.29.1" 287 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.1.tgz#353d14d6eee943004d129796e4feddd3aa260921" 288 | integrity sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng== 289 | 290 | "@rollup/rollup-win32-x64-msvc@4.29.1": 291 | version "4.29.1" 292 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.1.tgz#c82f04a09ba481e13857d6f2516e072aaa51b7f4" 293 | integrity sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg== 294 | 295 | "@ts-morph/common@~0.17.0": 296 | version "0.17.0" 297 | resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.17.0.tgz#de0d405df10857907469fef8d9363893b4163fd1" 298 | integrity sha512-RMSSvSfs9kb0VzkvQ2NWobwnj7TxCA9vI/IjR9bDHqgAyVbu2T0DN4wiKVqomyDWqO7dPr/tErSfq7urQ1Q37g== 299 | dependencies: 300 | fast-glob "^3.2.11" 301 | minimatch "^5.1.0" 302 | mkdirp "^1.0.4" 303 | path-browserify "^1.0.1" 304 | 305 | "@tsconfig/node10@^1.0.7": 306 | version "1.0.9" 307 | resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" 308 | integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== 309 | 310 | "@tsconfig/node12@^1.0.7": 311 | version "1.0.11" 312 | resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" 313 | integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== 314 | 315 | "@tsconfig/node14@^1.0.0": 316 | version "1.0.3" 317 | resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" 318 | integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== 319 | 320 | "@tsconfig/node16@^1.0.2": 321 | version "1.0.3" 322 | resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" 323 | integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== 324 | 325 | "@types/async-lock@^1.3.0": 326 | version "1.3.0" 327 | resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.3.0.tgz#12d165b890935afbc553eb9db467c0b540658b8e" 328 | integrity sha512-Z93wDSYW9aMgPR5t+7ouwTvy91Vp3M0Snh4Pd3tf+caSAq5bXZaGnnH9CDbjrwgmfDkRIX0Dx8GvSDgwuoaxoA== 329 | 330 | "@types/estree@1.0.6", "@types/estree@^1.0.0": 331 | version "1.0.6" 332 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" 333 | integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== 334 | 335 | "@types/lodash@^4.14.185": 336 | version "4.14.185" 337 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.185.tgz#c9843f5a40703a8f5edfd53358a58ae729816908" 338 | integrity sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA== 339 | 340 | "@types/node@*": 341 | version "18.7.18" 342 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154" 343 | integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg== 344 | 345 | "@types/node@^22.10.5": 346 | version "22.10.5" 347 | resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.5.tgz#95af89a3fb74a2bb41ef9927f206e6472026e48b" 348 | integrity sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ== 349 | dependencies: 350 | undici-types "~6.20.0" 351 | 352 | "@vitest/expect@2.1.8": 353 | version "2.1.8" 354 | resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.1.8.tgz#13fad0e8d5a0bf0feb675dcf1d1f1a36a1773bc1" 355 | integrity sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw== 356 | dependencies: 357 | "@vitest/spy" "2.1.8" 358 | "@vitest/utils" "2.1.8" 359 | chai "^5.1.2" 360 | tinyrainbow "^1.2.0" 361 | 362 | "@vitest/mocker@2.1.8": 363 | version "2.1.8" 364 | resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-2.1.8.tgz#51dec42ac244e949d20009249e033e274e323f73" 365 | integrity sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA== 366 | dependencies: 367 | "@vitest/spy" "2.1.8" 368 | estree-walker "^3.0.3" 369 | magic-string "^0.30.12" 370 | 371 | "@vitest/pretty-format@2.1.8", "@vitest/pretty-format@^2.1.8": 372 | version "2.1.8" 373 | resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.8.tgz#88f47726e5d0cf4ba873d50c135b02e4395e2bca" 374 | integrity sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ== 375 | dependencies: 376 | tinyrainbow "^1.2.0" 377 | 378 | "@vitest/runner@2.1.8": 379 | version "2.1.8" 380 | resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.1.8.tgz#b0e2dd29ca49c25e9323ea2a45a5125d8729759f" 381 | integrity sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg== 382 | dependencies: 383 | "@vitest/utils" "2.1.8" 384 | pathe "^1.1.2" 385 | 386 | "@vitest/snapshot@2.1.8": 387 | version "2.1.8" 388 | resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.1.8.tgz#d5dc204f4b95dc8b5e468b455dfc99000047d2de" 389 | integrity sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg== 390 | dependencies: 391 | "@vitest/pretty-format" "2.1.8" 392 | magic-string "^0.30.12" 393 | pathe "^1.1.2" 394 | 395 | "@vitest/spy@2.1.8": 396 | version "2.1.8" 397 | resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.1.8.tgz#bc41af3e1e6a41ae3b67e51f09724136b88fa447" 398 | integrity sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg== 399 | dependencies: 400 | tinyspy "^3.0.2" 401 | 402 | "@vitest/utils@2.1.8": 403 | version "2.1.8" 404 | resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.8.tgz#f8ef85525f3362ebd37fd25d268745108d6ae388" 405 | integrity sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA== 406 | dependencies: 407 | "@vitest/pretty-format" "2.1.8" 408 | loupe "^3.1.2" 409 | tinyrainbow "^1.2.0" 410 | 411 | acorn-walk@^8.1.1: 412 | version "8.2.0" 413 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" 414 | integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== 415 | 416 | acorn@^8.4.1: 417 | version "8.8.0" 418 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" 419 | integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== 420 | 421 | ansi-styles@^3.2.1: 422 | version "3.2.1" 423 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 424 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 425 | dependencies: 426 | color-convert "^1.9.0" 427 | 428 | anymatch@^1.3.0: 429 | version "1.3.2" 430 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" 431 | integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== 432 | dependencies: 433 | micromatch "^2.1.5" 434 | normalize-path "^2.0.0" 435 | 436 | anymatch@~3.1.2: 437 | version "3.1.2" 438 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 439 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 440 | dependencies: 441 | normalize-path "^3.0.0" 442 | picomatch "^2.0.4" 443 | 444 | arg@^4.1.0: 445 | version "4.1.3" 446 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" 447 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 448 | 449 | argparse@^1.0.7: 450 | version "1.0.10" 451 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 452 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 453 | dependencies: 454 | sprintf-js "~1.0.2" 455 | 456 | arr-diff@^2.0.0: 457 | version "2.0.0" 458 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" 459 | integrity sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA== 460 | dependencies: 461 | arr-flatten "^1.0.1" 462 | 463 | arr-diff@^4.0.0: 464 | version "4.0.0" 465 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" 466 | integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== 467 | 468 | arr-flatten@^1.0.1, arr-flatten@^1.1.0: 469 | version "1.1.0" 470 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" 471 | integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== 472 | 473 | arr-union@^3.1.0: 474 | version "3.1.0" 475 | resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" 476 | integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== 477 | 478 | array-unique@^0.2.1: 479 | version "0.2.1" 480 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" 481 | integrity sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg== 482 | 483 | array-unique@^0.3.2: 484 | version "0.3.2" 485 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" 486 | integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== 487 | 488 | assertion-error@^2.0.1: 489 | version "2.0.1" 490 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" 491 | integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== 492 | 493 | assign-symbols@^1.0.0: 494 | version "1.0.0" 495 | resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" 496 | integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== 497 | 498 | async-each@^1.0.0: 499 | version "1.0.3" 500 | resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" 501 | integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== 502 | 503 | async-lock@^1.3.2: 504 | version "1.3.2" 505 | resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.3.2.tgz#56668613f91c1c55432b4db73e65c9ced664e789" 506 | integrity sha512-phnXdS3RP7PPcmP6NWWzWMU0sLTeyvtZCxBPpZdkYE3seGLKSQZs9FrmVO/qwypq98FUtWWUEYxziLkdGk5nnA== 507 | 508 | atob@^2.1.2: 509 | version "2.1.2" 510 | resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" 511 | integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== 512 | 513 | babel-runtime@^6.9.2: 514 | version "6.26.0" 515 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" 516 | integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== 517 | dependencies: 518 | core-js "^2.4.0" 519 | regenerator-runtime "^0.11.0" 520 | 521 | balanced-match@^1.0.0: 522 | version "1.0.2" 523 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 524 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 525 | 526 | base@^0.11.1: 527 | version "0.11.2" 528 | resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" 529 | integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== 530 | dependencies: 531 | cache-base "^1.0.1" 532 | class-utils "^0.3.5" 533 | component-emitter "^1.2.1" 534 | define-property "^1.0.0" 535 | isobject "^3.0.1" 536 | mixin-deep "^1.2.0" 537 | pascalcase "^0.1.1" 538 | 539 | binary-extensions@^1.0.0: 540 | version "1.13.1" 541 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" 542 | integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== 543 | 544 | binary-extensions@^2.0.0: 545 | version "2.2.0" 546 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 547 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 548 | 549 | bindings@^1.5.0: 550 | version "1.5.0" 551 | resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" 552 | integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== 553 | dependencies: 554 | file-uri-to-path "1.0.0" 555 | 556 | brace-expansion@^1.1.7: 557 | version "1.1.11" 558 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 559 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 560 | dependencies: 561 | balanced-match "^1.0.0" 562 | concat-map "0.0.1" 563 | 564 | brace-expansion@^2.0.1: 565 | version "2.0.1" 566 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 567 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 568 | dependencies: 569 | balanced-match "^1.0.0" 570 | 571 | braces@^1.8.2: 572 | version "1.8.5" 573 | resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" 574 | integrity sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw== 575 | dependencies: 576 | expand-range "^1.8.1" 577 | preserve "^0.2.0" 578 | repeat-element "^1.1.2" 579 | 580 | braces@^2.3.1: 581 | version "2.3.2" 582 | resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" 583 | integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== 584 | dependencies: 585 | arr-flatten "^1.1.0" 586 | array-unique "^0.3.2" 587 | extend-shallow "^2.0.1" 588 | fill-range "^4.0.0" 589 | isobject "^3.0.1" 590 | repeat-element "^1.1.2" 591 | snapdragon "^0.8.1" 592 | snapdragon-node "^2.0.1" 593 | split-string "^3.0.2" 594 | to-regex "^3.0.1" 595 | 596 | braces@^3.0.2, braces@~3.0.2: 597 | version "3.0.2" 598 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 599 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 600 | dependencies: 601 | fill-range "^7.0.1" 602 | 603 | builtin-modules@^1.1.1: 604 | version "1.1.1" 605 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 606 | integrity sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ== 607 | 608 | cac@^6.7.14: 609 | version "6.7.14" 610 | resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" 611 | integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== 612 | 613 | cache-base@^1.0.1: 614 | version "1.0.1" 615 | resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" 616 | integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== 617 | dependencies: 618 | collection-visit "^1.0.0" 619 | component-emitter "^1.2.1" 620 | get-value "^2.0.6" 621 | has-value "^1.0.0" 622 | isobject "^3.0.1" 623 | set-value "^2.0.0" 624 | to-object-path "^0.3.0" 625 | union-value "^1.0.0" 626 | unset-value "^1.0.0" 627 | 628 | chai@^5.1.2: 629 | version "5.1.2" 630 | resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.2.tgz#3afbc340b994ae3610ca519a6c70ace77ad4378d" 631 | integrity sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw== 632 | dependencies: 633 | assertion-error "^2.0.1" 634 | check-error "^2.1.1" 635 | deep-eql "^5.0.1" 636 | loupe "^3.1.0" 637 | pathval "^2.0.0" 638 | 639 | chalk@^2.0.0, chalk@^2.3.0: 640 | version "2.4.2" 641 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 642 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 643 | dependencies: 644 | ansi-styles "^3.2.1" 645 | escape-string-regexp "^1.0.5" 646 | supports-color "^5.3.0" 647 | 648 | check-error@^2.1.1: 649 | version "2.1.1" 650 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" 651 | integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== 652 | 653 | chokidar@^1.6.0: 654 | version "1.7.0" 655 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" 656 | integrity sha512-mk8fAWcRUOxY7btlLtitj3A45jOwSAxH4tOFOoEGbVsl6cL6pPMWUy7dwZ/canfj3QEdP6FHSnf/l1c6/WkzVg== 657 | dependencies: 658 | anymatch "^1.3.0" 659 | async-each "^1.0.0" 660 | glob-parent "^2.0.0" 661 | inherits "^2.0.1" 662 | is-binary-path "^1.0.0" 663 | is-glob "^2.0.0" 664 | path-is-absolute "^1.0.0" 665 | readdirp "^2.0.0" 666 | optionalDependencies: 667 | fsevents "^1.0.0" 668 | 669 | chokidar@^3.5.3: 670 | version "3.5.3" 671 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" 672 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== 673 | dependencies: 674 | anymatch "~3.1.2" 675 | braces "~3.0.2" 676 | glob-parent "~5.1.2" 677 | is-binary-path "~2.1.0" 678 | is-glob "~4.0.1" 679 | normalize-path "~3.0.0" 680 | readdirp "~3.6.0" 681 | optionalDependencies: 682 | fsevents "~2.3.2" 683 | 684 | class-utils@^0.3.5: 685 | version "0.3.6" 686 | resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" 687 | integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== 688 | dependencies: 689 | arr-union "^3.1.0" 690 | define-property "^0.2.5" 691 | isobject "^3.0.0" 692 | static-extend "^0.1.1" 693 | 694 | code-block-writer@^11.0.3: 695 | version "11.0.3" 696 | resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-11.0.3.tgz#9eec2993edfb79bfae845fbc093758c0a0b73b76" 697 | integrity sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw== 698 | 699 | collection-visit@^1.0.0: 700 | version "1.0.0" 701 | resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" 702 | integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== 703 | dependencies: 704 | map-visit "^1.0.0" 705 | object-visit "^1.0.0" 706 | 707 | color-convert@^1.9.0: 708 | version "1.9.3" 709 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 710 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 711 | dependencies: 712 | color-name "1.1.3" 713 | 714 | color-name@1.1.3: 715 | version "1.1.3" 716 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 717 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== 718 | 719 | commander@^2.12.1: 720 | version "2.20.3" 721 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 722 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 723 | 724 | component-emitter@^1.2.1: 725 | version "1.3.0" 726 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" 727 | integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== 728 | 729 | concat-map@0.0.1: 730 | version "0.0.1" 731 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 732 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 733 | 734 | copy-descriptor@^0.1.0: 735 | version "0.1.1" 736 | resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" 737 | integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== 738 | 739 | core-js@^2.4.0: 740 | version "2.6.12" 741 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" 742 | integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== 743 | 744 | core-util-is@~1.0.0: 745 | version "1.0.3" 746 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 747 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 748 | 749 | cpx@^1.5.0: 750 | version "1.5.0" 751 | resolved "https://registry.yarnpkg.com/cpx/-/cpx-1.5.0.tgz#185be018511d87270dedccc293171e37655ab88f" 752 | integrity sha512-jHTjZhsbg9xWgsP2vuNW2jnnzBX+p4T+vNI9Lbjzs1n4KhOfa22bQppiFYLsWQKd8TzmL5aSP/Me3yfsCwXbDA== 753 | dependencies: 754 | babel-runtime "^6.9.2" 755 | chokidar "^1.6.0" 756 | duplexer "^0.1.1" 757 | glob "^7.0.5" 758 | glob2base "^0.0.12" 759 | minimatch "^3.0.2" 760 | mkdirp "^0.5.1" 761 | resolve "^1.1.7" 762 | safe-buffer "^5.0.1" 763 | shell-quote "^1.6.1" 764 | subarg "^1.0.0" 765 | 766 | create-require@^1.1.0: 767 | version "1.1.1" 768 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" 769 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 770 | 771 | debug@^2.2.0, debug@^2.3.3: 772 | version "2.6.9" 773 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 774 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 775 | dependencies: 776 | ms "2.0.0" 777 | 778 | debug@^4.3.7: 779 | version "4.4.0" 780 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" 781 | integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== 782 | dependencies: 783 | ms "^2.1.3" 784 | 785 | decode-uri-component@^0.2.0: 786 | version "0.2.0" 787 | resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" 788 | integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== 789 | 790 | deep-eql@^5.0.1: 791 | version "5.0.2" 792 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" 793 | integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== 794 | 795 | define-property@^0.2.5: 796 | version "0.2.5" 797 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" 798 | integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== 799 | dependencies: 800 | is-descriptor "^0.1.0" 801 | 802 | define-property@^1.0.0: 803 | version "1.0.0" 804 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" 805 | integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== 806 | dependencies: 807 | is-descriptor "^1.0.0" 808 | 809 | define-property@^2.0.2: 810 | version "2.0.2" 811 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" 812 | integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== 813 | dependencies: 814 | is-descriptor "^1.0.2" 815 | isobject "^3.0.1" 816 | 817 | diff@^4.0.1: 818 | version "4.0.2" 819 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 820 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 821 | 822 | duplexer@^0.1.1: 823 | version "0.1.2" 824 | resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" 825 | integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== 826 | 827 | error-stack-parser@^2.1.4: 828 | version "2.1.4" 829 | resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" 830 | integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== 831 | dependencies: 832 | stackframe "^1.3.4" 833 | 834 | es-module-lexer@^1.5.4: 835 | version "1.6.0" 836 | resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.6.0.tgz#da49f587fd9e68ee2404fe4e256c0c7d3a81be21" 837 | integrity sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ== 838 | 839 | esbuild@^0.21.3: 840 | version "0.21.5" 841 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" 842 | integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== 843 | optionalDependencies: 844 | "@esbuild/aix-ppc64" "0.21.5" 845 | "@esbuild/android-arm" "0.21.5" 846 | "@esbuild/android-arm64" "0.21.5" 847 | "@esbuild/android-x64" "0.21.5" 848 | "@esbuild/darwin-arm64" "0.21.5" 849 | "@esbuild/darwin-x64" "0.21.5" 850 | "@esbuild/freebsd-arm64" "0.21.5" 851 | "@esbuild/freebsd-x64" "0.21.5" 852 | "@esbuild/linux-arm" "0.21.5" 853 | "@esbuild/linux-arm64" "0.21.5" 854 | "@esbuild/linux-ia32" "0.21.5" 855 | "@esbuild/linux-loong64" "0.21.5" 856 | "@esbuild/linux-mips64el" "0.21.5" 857 | "@esbuild/linux-ppc64" "0.21.5" 858 | "@esbuild/linux-riscv64" "0.21.5" 859 | "@esbuild/linux-s390x" "0.21.5" 860 | "@esbuild/linux-x64" "0.21.5" 861 | "@esbuild/netbsd-x64" "0.21.5" 862 | "@esbuild/openbsd-x64" "0.21.5" 863 | "@esbuild/sunos-x64" "0.21.5" 864 | "@esbuild/win32-arm64" "0.21.5" 865 | "@esbuild/win32-ia32" "0.21.5" 866 | "@esbuild/win32-x64" "0.21.5" 867 | 868 | escape-string-regexp@^1.0.5: 869 | version "1.0.5" 870 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 871 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== 872 | 873 | esprima@^4.0.0: 874 | version "4.0.1" 875 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 876 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 877 | 878 | estree-walker@^3.0.3: 879 | version "3.0.3" 880 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" 881 | integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== 882 | dependencies: 883 | "@types/estree" "^1.0.0" 884 | 885 | expand-brackets@^0.1.4: 886 | version "0.1.5" 887 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" 888 | integrity sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA== 889 | dependencies: 890 | is-posix-bracket "^0.1.0" 891 | 892 | expand-brackets@^2.1.4: 893 | version "2.1.4" 894 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" 895 | integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== 896 | dependencies: 897 | debug "^2.3.3" 898 | define-property "^0.2.5" 899 | extend-shallow "^2.0.1" 900 | posix-character-classes "^0.1.0" 901 | regex-not "^1.0.0" 902 | snapdragon "^0.8.1" 903 | to-regex "^3.0.1" 904 | 905 | expand-range@^1.8.1: 906 | version "1.8.2" 907 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 908 | integrity sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA== 909 | dependencies: 910 | fill-range "^2.1.0" 911 | 912 | expect-type@^1.1.0: 913 | version "1.1.0" 914 | resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.1.0.tgz#a146e414250d13dfc49eafcfd1344a4060fa4c75" 915 | integrity sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA== 916 | 917 | extend-shallow@^2.0.1: 918 | version "2.0.1" 919 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" 920 | integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== 921 | dependencies: 922 | is-extendable "^0.1.0" 923 | 924 | extend-shallow@^3.0.0, extend-shallow@^3.0.2: 925 | version "3.0.2" 926 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" 927 | integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== 928 | dependencies: 929 | assign-symbols "^1.0.0" 930 | is-extendable "^1.0.1" 931 | 932 | extglob@^0.3.1: 933 | version "0.3.2" 934 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" 935 | integrity sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg== 936 | dependencies: 937 | is-extglob "^1.0.0" 938 | 939 | extglob@^2.0.4: 940 | version "2.0.4" 941 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" 942 | integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== 943 | dependencies: 944 | array-unique "^0.3.2" 945 | define-property "^1.0.0" 946 | expand-brackets "^2.1.4" 947 | extend-shallow "^2.0.1" 948 | fragment-cache "^0.2.1" 949 | regex-not "^1.0.0" 950 | snapdragon "^0.8.1" 951 | to-regex "^3.0.1" 952 | 953 | fast-glob@^3.2.11: 954 | version "3.2.12" 955 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" 956 | integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== 957 | dependencies: 958 | "@nodelib/fs.stat" "^2.0.2" 959 | "@nodelib/fs.walk" "^1.2.3" 960 | glob-parent "^5.1.2" 961 | merge2 "^1.3.0" 962 | micromatch "^4.0.4" 963 | 964 | fastq@^1.6.0: 965 | version "1.13.0" 966 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" 967 | integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== 968 | dependencies: 969 | reusify "^1.0.4" 970 | 971 | file-uri-to-path@1.0.0: 972 | version "1.0.0" 973 | resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" 974 | integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== 975 | 976 | filename-regex@^2.0.0: 977 | version "2.0.1" 978 | resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" 979 | integrity sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ== 980 | 981 | fill-range@^2.1.0: 982 | version "2.2.4" 983 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" 984 | integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== 985 | dependencies: 986 | is-number "^2.1.0" 987 | isobject "^2.0.0" 988 | randomatic "^3.0.0" 989 | repeat-element "^1.1.2" 990 | repeat-string "^1.5.2" 991 | 992 | fill-range@^4.0.0: 993 | version "4.0.0" 994 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" 995 | integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== 996 | dependencies: 997 | extend-shallow "^2.0.1" 998 | is-number "^3.0.0" 999 | repeat-string "^1.6.1" 1000 | to-regex-range "^2.1.0" 1001 | 1002 | fill-range@^7.0.1: 1003 | version "7.0.1" 1004 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 1005 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 1006 | dependencies: 1007 | to-regex-range "^5.0.1" 1008 | 1009 | find-index@^0.1.1: 1010 | version "0.1.1" 1011 | resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" 1012 | integrity sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg== 1013 | 1014 | for-in@^1.0.1, for-in@^1.0.2: 1015 | version "1.0.2" 1016 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 1017 | integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== 1018 | 1019 | for-own@^0.1.4: 1020 | version "0.1.5" 1021 | resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" 1022 | integrity sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw== 1023 | dependencies: 1024 | for-in "^1.0.1" 1025 | 1026 | fragment-cache@^0.2.1: 1027 | version "0.2.1" 1028 | resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" 1029 | integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== 1030 | dependencies: 1031 | map-cache "^0.2.2" 1032 | 1033 | fs.realpath@^1.0.0: 1034 | version "1.0.0" 1035 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 1036 | integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== 1037 | 1038 | fsevents@^1.0.0: 1039 | version "1.2.13" 1040 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" 1041 | integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== 1042 | dependencies: 1043 | bindings "^1.5.0" 1044 | nan "^2.12.1" 1045 | 1046 | fsevents@~2.3.2: 1047 | version "2.3.2" 1048 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 1049 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 1050 | 1051 | fsevents@~2.3.3: 1052 | version "2.3.3" 1053 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 1054 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 1055 | 1056 | function-bind@^1.1.1: 1057 | version "1.1.1" 1058 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 1059 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 1060 | 1061 | get-value@^2.0.3, get-value@^2.0.6: 1062 | version "2.0.6" 1063 | resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" 1064 | integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== 1065 | 1066 | glob-base@^0.3.0: 1067 | version "0.3.0" 1068 | resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" 1069 | integrity sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA== 1070 | dependencies: 1071 | glob-parent "^2.0.0" 1072 | is-glob "^2.0.0" 1073 | 1074 | glob-parent@^2.0.0: 1075 | version "2.0.0" 1076 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" 1077 | integrity sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w== 1078 | dependencies: 1079 | is-glob "^2.0.0" 1080 | 1081 | glob-parent@^5.1.2, glob-parent@~5.1.2: 1082 | version "5.1.2" 1083 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 1084 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 1085 | dependencies: 1086 | is-glob "^4.0.1" 1087 | 1088 | glob2base@^0.0.12: 1089 | version "0.0.12" 1090 | resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" 1091 | integrity sha512-ZyqlgowMbfj2NPjxaZZ/EtsXlOch28FRXgMd64vqZWk1bT9+wvSRLYD1om9M7QfQru51zJPAT17qXm4/zd+9QA== 1092 | dependencies: 1093 | find-index "^0.1.1" 1094 | 1095 | glob@^7.0.5, glob@^7.1.1: 1096 | version "7.2.3" 1097 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 1098 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 1099 | dependencies: 1100 | fs.realpath "^1.0.0" 1101 | inflight "^1.0.4" 1102 | inherits "2" 1103 | minimatch "^3.1.1" 1104 | once "^1.3.0" 1105 | path-is-absolute "^1.0.0" 1106 | 1107 | graceful-fs@^4.1.11: 1108 | version "4.2.10" 1109 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" 1110 | integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== 1111 | 1112 | has-flag@^3.0.0: 1113 | version "3.0.0" 1114 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 1115 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 1116 | 1117 | has-value@^0.3.1: 1118 | version "0.3.1" 1119 | resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" 1120 | integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== 1121 | dependencies: 1122 | get-value "^2.0.3" 1123 | has-values "^0.1.4" 1124 | isobject "^2.0.0" 1125 | 1126 | has-value@^1.0.0: 1127 | version "1.0.0" 1128 | resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" 1129 | integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== 1130 | dependencies: 1131 | get-value "^2.0.6" 1132 | has-values "^1.0.0" 1133 | isobject "^3.0.0" 1134 | 1135 | has-values@^0.1.4: 1136 | version "0.1.4" 1137 | resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" 1138 | integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== 1139 | 1140 | has-values@^1.0.0: 1141 | version "1.0.0" 1142 | resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" 1143 | integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== 1144 | dependencies: 1145 | is-number "^3.0.0" 1146 | kind-of "^4.0.0" 1147 | 1148 | has@^1.0.3: 1149 | version "1.0.3" 1150 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 1151 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 1152 | dependencies: 1153 | function-bind "^1.1.1" 1154 | 1155 | inflight@^1.0.4: 1156 | version "1.0.6" 1157 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 1158 | integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== 1159 | dependencies: 1160 | once "^1.3.0" 1161 | wrappy "1" 1162 | 1163 | inherits@2, inherits@^2.0.1, inherits@~2.0.3: 1164 | version "2.0.4" 1165 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 1166 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 1167 | 1168 | is-accessor-descriptor@^0.1.6: 1169 | version "0.1.6" 1170 | resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" 1171 | integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== 1172 | dependencies: 1173 | kind-of "^3.0.2" 1174 | 1175 | is-accessor-descriptor@^1.0.0: 1176 | version "1.0.0" 1177 | resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" 1178 | integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== 1179 | dependencies: 1180 | kind-of "^6.0.0" 1181 | 1182 | is-binary-path@^1.0.0: 1183 | version "1.0.1" 1184 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" 1185 | integrity sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q== 1186 | dependencies: 1187 | binary-extensions "^1.0.0" 1188 | 1189 | is-binary-path@~2.1.0: 1190 | version "2.1.0" 1191 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 1192 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 1193 | dependencies: 1194 | binary-extensions "^2.0.0" 1195 | 1196 | is-buffer@^1.1.5: 1197 | version "1.1.6" 1198 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 1199 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== 1200 | 1201 | is-core-module@^2.9.0: 1202 | version "2.10.0" 1203 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" 1204 | integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== 1205 | dependencies: 1206 | has "^1.0.3" 1207 | 1208 | is-data-descriptor@^0.1.4: 1209 | version "0.1.4" 1210 | resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" 1211 | integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== 1212 | dependencies: 1213 | kind-of "^3.0.2" 1214 | 1215 | is-data-descriptor@^1.0.0: 1216 | version "1.0.0" 1217 | resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" 1218 | integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== 1219 | dependencies: 1220 | kind-of "^6.0.0" 1221 | 1222 | is-descriptor@^0.1.0: 1223 | version "0.1.6" 1224 | resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" 1225 | integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== 1226 | dependencies: 1227 | is-accessor-descriptor "^0.1.6" 1228 | is-data-descriptor "^0.1.4" 1229 | kind-of "^5.0.0" 1230 | 1231 | is-descriptor@^1.0.0, is-descriptor@^1.0.2: 1232 | version "1.0.2" 1233 | resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" 1234 | integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== 1235 | dependencies: 1236 | is-accessor-descriptor "^1.0.0" 1237 | is-data-descriptor "^1.0.0" 1238 | kind-of "^6.0.2" 1239 | 1240 | is-dotfile@^1.0.0: 1241 | version "1.0.3" 1242 | resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" 1243 | integrity sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg== 1244 | 1245 | is-equal-shallow@^0.1.3: 1246 | version "0.1.3" 1247 | resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" 1248 | integrity sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA== 1249 | dependencies: 1250 | is-primitive "^2.0.0" 1251 | 1252 | is-extendable@^0.1.0, is-extendable@^0.1.1: 1253 | version "0.1.1" 1254 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 1255 | integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== 1256 | 1257 | is-extendable@^1.0.1: 1258 | version "1.0.1" 1259 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" 1260 | integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== 1261 | dependencies: 1262 | is-plain-object "^2.0.4" 1263 | 1264 | is-extglob@^1.0.0: 1265 | version "1.0.0" 1266 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" 1267 | integrity sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww== 1268 | 1269 | is-extglob@^2.1.1: 1270 | version "2.1.1" 1271 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 1272 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 1273 | 1274 | is-glob@^2.0.0, is-glob@^2.0.1: 1275 | version "2.0.1" 1276 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" 1277 | integrity sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg== 1278 | dependencies: 1279 | is-extglob "^1.0.0" 1280 | 1281 | is-glob@^4.0.1, is-glob@~4.0.1: 1282 | version "4.0.3" 1283 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 1284 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 1285 | dependencies: 1286 | is-extglob "^2.1.1" 1287 | 1288 | is-number@^2.1.0: 1289 | version "2.1.0" 1290 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 1291 | integrity sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg== 1292 | dependencies: 1293 | kind-of "^3.0.2" 1294 | 1295 | is-number@^3.0.0: 1296 | version "3.0.0" 1297 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 1298 | integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== 1299 | dependencies: 1300 | kind-of "^3.0.2" 1301 | 1302 | is-number@^4.0.0: 1303 | version "4.0.0" 1304 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" 1305 | integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== 1306 | 1307 | is-number@^7.0.0: 1308 | version "7.0.0" 1309 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 1310 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 1311 | 1312 | is-plain-object@^2.0.3, is-plain-object@^2.0.4: 1313 | version "2.0.4" 1314 | resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" 1315 | integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== 1316 | dependencies: 1317 | isobject "^3.0.1" 1318 | 1319 | is-posix-bracket@^0.1.0: 1320 | version "0.1.1" 1321 | resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" 1322 | integrity sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ== 1323 | 1324 | is-primitive@^2.0.0: 1325 | version "2.0.0" 1326 | resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" 1327 | integrity sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q== 1328 | 1329 | is-windows@^1.0.2: 1330 | version "1.0.2" 1331 | resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" 1332 | integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== 1333 | 1334 | isarray@1.0.0, isarray@~1.0.0: 1335 | version "1.0.0" 1336 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 1337 | integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== 1338 | 1339 | isobject@^2.0.0: 1340 | version "2.1.0" 1341 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 1342 | integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== 1343 | dependencies: 1344 | isarray "1.0.0" 1345 | 1346 | isobject@^3.0.0, isobject@^3.0.1: 1347 | version "3.0.1" 1348 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" 1349 | integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== 1350 | 1351 | js-tokens@^4.0.0: 1352 | version "4.0.0" 1353 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 1354 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 1355 | 1356 | js-yaml@^3.13.1: 1357 | version "3.14.1" 1358 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" 1359 | integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== 1360 | dependencies: 1361 | argparse "^1.0.7" 1362 | esprima "^4.0.0" 1363 | 1364 | kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: 1365 | version "3.2.2" 1366 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 1367 | integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== 1368 | dependencies: 1369 | is-buffer "^1.1.5" 1370 | 1371 | kind-of@^4.0.0: 1372 | version "4.0.0" 1373 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" 1374 | integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== 1375 | dependencies: 1376 | is-buffer "^1.1.5" 1377 | 1378 | kind-of@^5.0.0: 1379 | version "5.1.0" 1380 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" 1381 | integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== 1382 | 1383 | kind-of@^6.0.0, kind-of@^6.0.2: 1384 | version "6.0.3" 1385 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" 1386 | integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== 1387 | 1388 | lodash@^4.17.21: 1389 | version "4.17.21" 1390 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 1391 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 1392 | 1393 | loupe@^3.1.0, loupe@^3.1.2: 1394 | version "3.1.2" 1395 | resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.2.tgz#c86e0696804a02218f2206124c45d8b15291a240" 1396 | integrity sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg== 1397 | 1398 | magic-string@^0.30.12: 1399 | version "0.30.17" 1400 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" 1401 | integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== 1402 | dependencies: 1403 | "@jridgewell/sourcemap-codec" "^1.5.0" 1404 | 1405 | make-error@^1.1.1: 1406 | version "1.3.6" 1407 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" 1408 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== 1409 | 1410 | map-cache@^0.2.2: 1411 | version "0.2.2" 1412 | resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" 1413 | integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== 1414 | 1415 | map-visit@^1.0.0: 1416 | version "1.0.0" 1417 | resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" 1418 | integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== 1419 | dependencies: 1420 | object-visit "^1.0.0" 1421 | 1422 | math-random@^1.0.1: 1423 | version "1.0.4" 1424 | resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" 1425 | integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== 1426 | 1427 | merge2@^1.3.0: 1428 | version "1.4.1" 1429 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 1430 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 1431 | 1432 | micromatch@^2.1.5: 1433 | version "2.3.11" 1434 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" 1435 | integrity sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA== 1436 | dependencies: 1437 | arr-diff "^2.0.0" 1438 | array-unique "^0.2.1" 1439 | braces "^1.8.2" 1440 | expand-brackets "^0.1.4" 1441 | extglob "^0.3.1" 1442 | filename-regex "^2.0.0" 1443 | is-extglob "^1.0.0" 1444 | is-glob "^2.0.1" 1445 | kind-of "^3.0.2" 1446 | normalize-path "^2.0.1" 1447 | object.omit "^2.0.0" 1448 | parse-glob "^3.0.4" 1449 | regex-cache "^0.4.2" 1450 | 1451 | micromatch@^3.1.10: 1452 | version "3.1.10" 1453 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" 1454 | integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== 1455 | dependencies: 1456 | arr-diff "^4.0.0" 1457 | array-unique "^0.3.2" 1458 | braces "^2.3.1" 1459 | define-property "^2.0.2" 1460 | extend-shallow "^3.0.2" 1461 | extglob "^2.0.4" 1462 | fragment-cache "^0.2.1" 1463 | kind-of "^6.0.2" 1464 | nanomatch "^1.2.9" 1465 | object.pick "^1.3.0" 1466 | regex-not "^1.0.0" 1467 | snapdragon "^0.8.1" 1468 | to-regex "^3.0.2" 1469 | 1470 | micromatch@^4.0.4: 1471 | version "4.0.5" 1472 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" 1473 | integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== 1474 | dependencies: 1475 | braces "^3.0.2" 1476 | picomatch "^2.3.1" 1477 | 1478 | minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: 1479 | version "3.1.2" 1480 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 1481 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 1482 | dependencies: 1483 | brace-expansion "^1.1.7" 1484 | 1485 | minimatch@^5.1.0: 1486 | version "5.1.0" 1487 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" 1488 | integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== 1489 | dependencies: 1490 | brace-expansion "^2.0.1" 1491 | 1492 | minimist@^1.1.0, minimist@^1.2.6: 1493 | version "1.2.6" 1494 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" 1495 | integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== 1496 | 1497 | mixin-deep@^1.2.0: 1498 | version "1.3.2" 1499 | resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" 1500 | integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== 1501 | dependencies: 1502 | for-in "^1.0.2" 1503 | is-extendable "^1.0.1" 1504 | 1505 | mkdirp@^0.5.1, mkdirp@^0.5.3: 1506 | version "0.5.6" 1507 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" 1508 | integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== 1509 | dependencies: 1510 | minimist "^1.2.6" 1511 | 1512 | mkdirp@^1.0.4: 1513 | version "1.0.4" 1514 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" 1515 | integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== 1516 | 1517 | ms@2.0.0: 1518 | version "2.0.0" 1519 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1520 | integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== 1521 | 1522 | ms@^2.1.3: 1523 | version "2.1.3" 1524 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 1525 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1526 | 1527 | nan@^2.12.1: 1528 | version "2.16.0" 1529 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916" 1530 | integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA== 1531 | 1532 | nanoid@^3.3.7: 1533 | version "3.3.8" 1534 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" 1535 | integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== 1536 | 1537 | nanomatch@^1.2.9: 1538 | version "1.2.13" 1539 | resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" 1540 | integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== 1541 | dependencies: 1542 | arr-diff "^4.0.0" 1543 | array-unique "^0.3.2" 1544 | define-property "^2.0.2" 1545 | extend-shallow "^3.0.2" 1546 | fragment-cache "^0.2.1" 1547 | is-windows "^1.0.2" 1548 | kind-of "^6.0.2" 1549 | object.pick "^1.3.0" 1550 | regex-not "^1.0.0" 1551 | snapdragon "^0.8.1" 1552 | to-regex "^3.0.1" 1553 | 1554 | normalize-path@^2.0.0, normalize-path@^2.0.1: 1555 | version "2.1.1" 1556 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" 1557 | integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== 1558 | dependencies: 1559 | remove-trailing-separator "^1.0.1" 1560 | 1561 | normalize-path@^3.0.0, normalize-path@~3.0.0: 1562 | version "3.0.0" 1563 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 1564 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 1565 | 1566 | object-copy@^0.1.0: 1567 | version "0.1.0" 1568 | resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" 1569 | integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== 1570 | dependencies: 1571 | copy-descriptor "^0.1.0" 1572 | define-property "^0.2.5" 1573 | kind-of "^3.0.3" 1574 | 1575 | object-visit@^1.0.0: 1576 | version "1.0.1" 1577 | resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" 1578 | integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== 1579 | dependencies: 1580 | isobject "^3.0.0" 1581 | 1582 | object.omit@^2.0.0: 1583 | version "2.0.1" 1584 | resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" 1585 | integrity sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA== 1586 | dependencies: 1587 | for-own "^0.1.4" 1588 | is-extendable "^0.1.1" 1589 | 1590 | object.pick@^1.3.0: 1591 | version "1.3.0" 1592 | resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" 1593 | integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== 1594 | dependencies: 1595 | isobject "^3.0.1" 1596 | 1597 | once@^1.3.0: 1598 | version "1.4.0" 1599 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1600 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== 1601 | dependencies: 1602 | wrappy "1" 1603 | 1604 | parse-glob@^3.0.4: 1605 | version "3.0.4" 1606 | resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" 1607 | integrity sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA== 1608 | dependencies: 1609 | glob-base "^0.3.0" 1610 | is-dotfile "^1.0.0" 1611 | is-extglob "^1.0.0" 1612 | is-glob "^2.0.0" 1613 | 1614 | pascalcase@^0.1.1: 1615 | version "0.1.1" 1616 | resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" 1617 | integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== 1618 | 1619 | path-browserify@^1.0.1: 1620 | version "1.0.1" 1621 | resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" 1622 | integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== 1623 | 1624 | path-is-absolute@^1.0.0: 1625 | version "1.0.1" 1626 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1627 | integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== 1628 | 1629 | path-parse@^1.0.7: 1630 | version "1.0.7" 1631 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 1632 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 1633 | 1634 | pathe@^1.1.2: 1635 | version "1.1.2" 1636 | resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" 1637 | integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== 1638 | 1639 | pathval@^2.0.0: 1640 | version "2.0.0" 1641 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" 1642 | integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== 1643 | 1644 | picocolors@^1.1.1: 1645 | version "1.1.1" 1646 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" 1647 | integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== 1648 | 1649 | picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: 1650 | version "2.3.1" 1651 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 1652 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 1653 | 1654 | playwright-core@1.25.2: 1655 | version "1.25.2" 1656 | resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.25.2.tgz#ea4baa398a4d45fcdfe48799482b599e3d0f033f" 1657 | integrity sha512-0yTbUE9lIddkEpLHL3u8PoCL+pWiZtj5A/j3U7YoNjcmKKDGBnCrgHJMzwd2J5vy6l28q4ki3JIuz7McLHhl1A== 1658 | 1659 | posix-character-classes@^0.1.0: 1660 | version "0.1.1" 1661 | resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" 1662 | integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== 1663 | 1664 | postcss@^8.4.43: 1665 | version "8.4.49" 1666 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19" 1667 | integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA== 1668 | dependencies: 1669 | nanoid "^3.3.7" 1670 | picocolors "^1.1.1" 1671 | source-map-js "^1.2.1" 1672 | 1673 | preserve@^0.2.0: 1674 | version "0.2.0" 1675 | resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" 1676 | integrity sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ== 1677 | 1678 | process-nextick-args@~2.0.0: 1679 | version "2.0.1" 1680 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 1681 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 1682 | 1683 | queue-microtask@^1.2.2: 1684 | version "1.2.3" 1685 | resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" 1686 | integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== 1687 | 1688 | randomatic@^3.0.0: 1689 | version "3.1.1" 1690 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" 1691 | integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== 1692 | dependencies: 1693 | is-number "^4.0.0" 1694 | kind-of "^6.0.0" 1695 | math-random "^1.0.1" 1696 | 1697 | readable-stream@^2.0.2: 1698 | version "2.3.7" 1699 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 1700 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 1701 | dependencies: 1702 | core-util-is "~1.0.0" 1703 | inherits "~2.0.3" 1704 | isarray "~1.0.0" 1705 | process-nextick-args "~2.0.0" 1706 | safe-buffer "~5.1.1" 1707 | string_decoder "~1.1.1" 1708 | util-deprecate "~1.0.1" 1709 | 1710 | readdirp@^2.0.0: 1711 | version "2.2.1" 1712 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" 1713 | integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== 1714 | dependencies: 1715 | graceful-fs "^4.1.11" 1716 | micromatch "^3.1.10" 1717 | readable-stream "^2.0.2" 1718 | 1719 | readdirp@~3.6.0: 1720 | version "3.6.0" 1721 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 1722 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 1723 | dependencies: 1724 | picomatch "^2.2.1" 1725 | 1726 | regenerator-runtime@^0.11.0: 1727 | version "0.11.1" 1728 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" 1729 | integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== 1730 | 1731 | regex-cache@^0.4.2: 1732 | version "0.4.4" 1733 | resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" 1734 | integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== 1735 | dependencies: 1736 | is-equal-shallow "^0.1.3" 1737 | 1738 | regex-not@^1.0.0, regex-not@^1.0.2: 1739 | version "1.0.2" 1740 | resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" 1741 | integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== 1742 | dependencies: 1743 | extend-shallow "^3.0.2" 1744 | safe-regex "^1.1.0" 1745 | 1746 | remove-trailing-separator@^1.0.1: 1747 | version "1.1.0" 1748 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" 1749 | integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== 1750 | 1751 | repeat-element@^1.1.2: 1752 | version "1.1.4" 1753 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" 1754 | integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== 1755 | 1756 | repeat-string@^1.5.2, repeat-string@^1.6.1: 1757 | version "1.6.1" 1758 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 1759 | integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== 1760 | 1761 | resolve-url@^0.2.1: 1762 | version "0.2.1" 1763 | resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" 1764 | integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== 1765 | 1766 | resolve@^1.1.7, resolve@^1.3.2: 1767 | version "1.22.1" 1768 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" 1769 | integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== 1770 | dependencies: 1771 | is-core-module "^2.9.0" 1772 | path-parse "^1.0.7" 1773 | supports-preserve-symlinks-flag "^1.0.0" 1774 | 1775 | ret@~0.1.10: 1776 | version "0.1.15" 1777 | resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" 1778 | integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== 1779 | 1780 | reusify@^1.0.4: 1781 | version "1.0.4" 1782 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" 1783 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== 1784 | 1785 | rollup@^4.20.0: 1786 | version "4.29.1" 1787 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.29.1.tgz#a9aaaece817e5f778489e5bf82e379cc8a5c05bc" 1788 | integrity sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw== 1789 | dependencies: 1790 | "@types/estree" "1.0.6" 1791 | optionalDependencies: 1792 | "@rollup/rollup-android-arm-eabi" "4.29.1" 1793 | "@rollup/rollup-android-arm64" "4.29.1" 1794 | "@rollup/rollup-darwin-arm64" "4.29.1" 1795 | "@rollup/rollup-darwin-x64" "4.29.1" 1796 | "@rollup/rollup-freebsd-arm64" "4.29.1" 1797 | "@rollup/rollup-freebsd-x64" "4.29.1" 1798 | "@rollup/rollup-linux-arm-gnueabihf" "4.29.1" 1799 | "@rollup/rollup-linux-arm-musleabihf" "4.29.1" 1800 | "@rollup/rollup-linux-arm64-gnu" "4.29.1" 1801 | "@rollup/rollup-linux-arm64-musl" "4.29.1" 1802 | "@rollup/rollup-linux-loongarch64-gnu" "4.29.1" 1803 | "@rollup/rollup-linux-powerpc64le-gnu" "4.29.1" 1804 | "@rollup/rollup-linux-riscv64-gnu" "4.29.1" 1805 | "@rollup/rollup-linux-s390x-gnu" "4.29.1" 1806 | "@rollup/rollup-linux-x64-gnu" "4.29.1" 1807 | "@rollup/rollup-linux-x64-musl" "4.29.1" 1808 | "@rollup/rollup-win32-arm64-msvc" "4.29.1" 1809 | "@rollup/rollup-win32-ia32-msvc" "4.29.1" 1810 | "@rollup/rollup-win32-x64-msvc" "4.29.1" 1811 | fsevents "~2.3.2" 1812 | 1813 | run-parallel@^1.1.9: 1814 | version "1.2.0" 1815 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" 1816 | integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== 1817 | dependencies: 1818 | queue-microtask "^1.2.2" 1819 | 1820 | safe-buffer@^5.0.1: 1821 | version "5.2.1" 1822 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1823 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1824 | 1825 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1826 | version "5.1.2" 1827 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1828 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1829 | 1830 | safe-regex@^1.1.0: 1831 | version "1.1.0" 1832 | resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" 1833 | integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== 1834 | dependencies: 1835 | ret "~0.1.10" 1836 | 1837 | semver@^5.3.0: 1838 | version "5.7.1" 1839 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1840 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1841 | 1842 | set-value@^2.0.0, set-value@^2.0.1: 1843 | version "2.0.1" 1844 | resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" 1845 | integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== 1846 | dependencies: 1847 | extend-shallow "^2.0.1" 1848 | is-extendable "^0.1.1" 1849 | is-plain-object "^2.0.3" 1850 | split-string "^3.0.1" 1851 | 1852 | shell-quote@^1.6.1: 1853 | version "1.7.3" 1854 | resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" 1855 | integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== 1856 | 1857 | siginfo@^2.0.0: 1858 | version "2.0.0" 1859 | resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" 1860 | integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== 1861 | 1862 | snapdragon-node@^2.0.1: 1863 | version "2.1.1" 1864 | resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" 1865 | integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== 1866 | dependencies: 1867 | define-property "^1.0.0" 1868 | isobject "^3.0.0" 1869 | snapdragon-util "^3.0.1" 1870 | 1871 | snapdragon-util@^3.0.1: 1872 | version "3.0.1" 1873 | resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" 1874 | integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== 1875 | dependencies: 1876 | kind-of "^3.2.0" 1877 | 1878 | snapdragon@^0.8.1: 1879 | version "0.8.2" 1880 | resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" 1881 | integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== 1882 | dependencies: 1883 | base "^0.11.1" 1884 | debug "^2.2.0" 1885 | define-property "^0.2.5" 1886 | extend-shallow "^2.0.1" 1887 | map-cache "^0.2.2" 1888 | source-map "^0.5.6" 1889 | source-map-resolve "^0.5.0" 1890 | use "^3.1.0" 1891 | 1892 | source-map-js@^1.2.1: 1893 | version "1.2.1" 1894 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" 1895 | integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== 1896 | 1897 | source-map-resolve@^0.5.0: 1898 | version "0.5.3" 1899 | resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" 1900 | integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== 1901 | dependencies: 1902 | atob "^2.1.2" 1903 | decode-uri-component "^0.2.0" 1904 | resolve-url "^0.2.1" 1905 | source-map-url "^0.4.0" 1906 | urix "^0.1.0" 1907 | 1908 | source-map-url@^0.4.0: 1909 | version "0.4.1" 1910 | resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" 1911 | integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== 1912 | 1913 | source-map@^0.5.6: 1914 | version "0.5.7" 1915 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 1916 | integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== 1917 | 1918 | split-string@^3.0.1, split-string@^3.0.2: 1919 | version "3.1.0" 1920 | resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" 1921 | integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== 1922 | dependencies: 1923 | extend-shallow "^3.0.0" 1924 | 1925 | sprintf-js@~1.0.2: 1926 | version "1.0.3" 1927 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1928 | integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== 1929 | 1930 | stackback@0.0.2: 1931 | version "0.0.2" 1932 | resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" 1933 | integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== 1934 | 1935 | stackframe@^1.3.4: 1936 | version "1.3.4" 1937 | resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" 1938 | integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== 1939 | 1940 | static-extend@^0.1.1: 1941 | version "0.1.2" 1942 | resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" 1943 | integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== 1944 | dependencies: 1945 | define-property "^0.2.5" 1946 | object-copy "^0.1.0" 1947 | 1948 | std-env@^3.8.0: 1949 | version "3.8.0" 1950 | resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" 1951 | integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== 1952 | 1953 | string_decoder@~1.1.1: 1954 | version "1.1.1" 1955 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1956 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1957 | dependencies: 1958 | safe-buffer "~5.1.0" 1959 | 1960 | subarg@^1.0.0: 1961 | version "1.0.0" 1962 | resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" 1963 | integrity sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg== 1964 | dependencies: 1965 | minimist "^1.1.0" 1966 | 1967 | supports-color@^5.3.0: 1968 | version "5.5.0" 1969 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1970 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1971 | dependencies: 1972 | has-flag "^3.0.0" 1973 | 1974 | supports-preserve-symlinks-flag@^1.0.0: 1975 | version "1.0.0" 1976 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 1977 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 1978 | 1979 | tinybench@^2.9.0: 1980 | version "2.9.0" 1981 | resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" 1982 | integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== 1983 | 1984 | tinyexec@^0.3.1: 1985 | version "0.3.2" 1986 | resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" 1987 | integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== 1988 | 1989 | tinypool@^1.0.1: 1990 | version "1.0.2" 1991 | resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.0.2.tgz#706193cc532f4c100f66aa00b01c42173d9051b2" 1992 | integrity sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA== 1993 | 1994 | tinyrainbow@^1.2.0: 1995 | version "1.2.0" 1996 | resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-1.2.0.tgz#5c57d2fc0fb3d1afd78465c33ca885d04f02abb5" 1997 | integrity sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ== 1998 | 1999 | tinyspy@^3.0.2: 2000 | version "3.0.2" 2001 | resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" 2002 | integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== 2003 | 2004 | to-object-path@^0.3.0: 2005 | version "0.3.0" 2006 | resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" 2007 | integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== 2008 | dependencies: 2009 | kind-of "^3.0.2" 2010 | 2011 | to-regex-range@^2.1.0: 2012 | version "2.1.1" 2013 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" 2014 | integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== 2015 | dependencies: 2016 | is-number "^3.0.0" 2017 | repeat-string "^1.6.1" 2018 | 2019 | to-regex-range@^5.0.1: 2020 | version "5.0.1" 2021 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 2022 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 2023 | dependencies: 2024 | is-number "^7.0.0" 2025 | 2026 | to-regex@^3.0.1, to-regex@^3.0.2: 2027 | version "3.0.2" 2028 | resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" 2029 | integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== 2030 | dependencies: 2031 | define-property "^2.0.2" 2032 | extend-shallow "^3.0.2" 2033 | regex-not "^1.0.2" 2034 | safe-regex "^1.1.0" 2035 | 2036 | ts-morph@^16.0.0: 2037 | version "16.0.0" 2038 | resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-16.0.0.tgz#35caca7c286dd70e09e5f72af47536bf3b6a27af" 2039 | integrity sha512-jGNF0GVpFj0orFw55LTsQxVYEUOCWBAbR5Ls7fTYE5pQsbW18ssTb/6UXx/GYAEjS+DQTp8VoTw0vqYMiaaQuw== 2040 | dependencies: 2041 | "@ts-morph/common" "~0.17.0" 2042 | code-block-writer "^11.0.3" 2043 | 2044 | ts-node@^10.9.2: 2045 | version "10.9.2" 2046 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" 2047 | integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== 2048 | dependencies: 2049 | "@cspotcode/source-map-support" "^0.8.0" 2050 | "@tsconfig/node10" "^1.0.7" 2051 | "@tsconfig/node12" "^1.0.7" 2052 | "@tsconfig/node14" "^1.0.0" 2053 | "@tsconfig/node16" "^1.0.2" 2054 | acorn "^8.4.1" 2055 | acorn-walk "^8.1.1" 2056 | arg "^4.1.0" 2057 | create-require "^1.1.0" 2058 | diff "^4.0.1" 2059 | make-error "^1.1.1" 2060 | v8-compile-cache-lib "^3.0.1" 2061 | yn "3.1.1" 2062 | 2063 | tslib@^1.13.0, tslib@^1.8.1: 2064 | version "1.14.1" 2065 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" 2066 | integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== 2067 | 2068 | tslint@^6.1.3: 2069 | version "6.1.3" 2070 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904" 2071 | integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg== 2072 | dependencies: 2073 | "@babel/code-frame" "^7.0.0" 2074 | builtin-modules "^1.1.1" 2075 | chalk "^2.3.0" 2076 | commander "^2.12.1" 2077 | diff "^4.0.1" 2078 | glob "^7.1.1" 2079 | js-yaml "^3.13.1" 2080 | minimatch "^3.0.4" 2081 | mkdirp "^0.5.3" 2082 | resolve "^1.3.2" 2083 | semver "^5.3.0" 2084 | tslib "^1.13.0" 2085 | tsutils "^2.29.0" 2086 | 2087 | tsutils@^2.29.0: 2088 | version "2.29.0" 2089 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" 2090 | integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== 2091 | dependencies: 2092 | tslib "^1.8.1" 2093 | 2094 | typescript@^4.8.2: 2095 | version "4.8.2" 2096 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" 2097 | integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== 2098 | 2099 | undici-types@~6.20.0: 2100 | version "6.20.0" 2101 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" 2102 | integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== 2103 | 2104 | union-value@^1.0.0: 2105 | version "1.0.1" 2106 | resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" 2107 | integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== 2108 | dependencies: 2109 | arr-union "^3.1.0" 2110 | get-value "^2.0.6" 2111 | is-extendable "^0.1.1" 2112 | set-value "^2.0.1" 2113 | 2114 | unset-value@^1.0.0: 2115 | version "1.0.0" 2116 | resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" 2117 | integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== 2118 | dependencies: 2119 | has-value "^0.3.1" 2120 | isobject "^3.0.0" 2121 | 2122 | urix@^0.1.0: 2123 | version "0.1.0" 2124 | resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" 2125 | integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== 2126 | 2127 | use@^3.1.0: 2128 | version "3.1.1" 2129 | resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" 2130 | integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== 2131 | 2132 | util-deprecate@~1.0.1: 2133 | version "1.0.2" 2134 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 2135 | integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 2136 | 2137 | v8-compile-cache-lib@^3.0.1: 2138 | version "3.0.1" 2139 | resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" 2140 | integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== 2141 | 2142 | vite-node@2.1.8: 2143 | version "2.1.8" 2144 | resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.1.8.tgz#9495ca17652f6f7f95ca7c4b568a235e0c8dbac5" 2145 | integrity sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg== 2146 | dependencies: 2147 | cac "^6.7.14" 2148 | debug "^4.3.7" 2149 | es-module-lexer "^1.5.4" 2150 | pathe "^1.1.2" 2151 | vite "^5.0.0" 2152 | 2153 | vite@^5.0.0: 2154 | version "5.4.11" 2155 | resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.11.tgz#3b415cd4aed781a356c1de5a9ebafb837715f6e5" 2156 | integrity sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q== 2157 | dependencies: 2158 | esbuild "^0.21.3" 2159 | postcss "^8.4.43" 2160 | rollup "^4.20.0" 2161 | optionalDependencies: 2162 | fsevents "~2.3.3" 2163 | 2164 | vitest@^2.1.8: 2165 | version "2.1.8" 2166 | resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.1.8.tgz#2e6a00bc24833574d535c96d6602fb64163092fa" 2167 | integrity sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ== 2168 | dependencies: 2169 | "@vitest/expect" "2.1.8" 2170 | "@vitest/mocker" "2.1.8" 2171 | "@vitest/pretty-format" "^2.1.8" 2172 | "@vitest/runner" "2.1.8" 2173 | "@vitest/snapshot" "2.1.8" 2174 | "@vitest/spy" "2.1.8" 2175 | "@vitest/utils" "2.1.8" 2176 | chai "^5.1.2" 2177 | debug "^4.3.7" 2178 | expect-type "^1.1.0" 2179 | magic-string "^0.30.12" 2180 | pathe "^1.1.2" 2181 | std-env "^3.8.0" 2182 | tinybench "^2.9.0" 2183 | tinyexec "^0.3.1" 2184 | tinypool "^1.0.1" 2185 | tinyrainbow "^1.2.0" 2186 | vite "^5.0.0" 2187 | vite-node "2.1.8" 2188 | why-is-node-running "^2.3.0" 2189 | 2190 | why-is-node-running@^2.3.0: 2191 | version "2.3.0" 2192 | resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" 2193 | integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== 2194 | dependencies: 2195 | siginfo "^2.0.0" 2196 | stackback "0.0.2" 2197 | 2198 | wrappy@1: 2199 | version "1.0.2" 2200 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 2201 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== 2202 | 2203 | yn@3.1.1: 2204 | version "3.1.1" 2205 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 2206 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 2207 | --------------------------------------------------------------------------------