diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 204faf12a..0f8385894 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Use Node.js 22.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v5 with: node-version: 22.x cache: 'npm' @@ -69,7 +69,7 @@ jobs: ./addons/addon-webgl/out/* \ ./addons/addon-webgl/out-*st/* - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: build-artifacts path: compressed-build.zip @@ -79,9 +79,9 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Use Node.js 22.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v5 with: node-version: 22.x cache: 'npm' @@ -100,16 +100,16 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Use Node.js 22.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v5 with: node-version: 22.x cache: 'npm' - name: Install dependencies run: | npm ci - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v7 with: name: build-artifacts - name: Unzip artifacts @@ -129,6 +129,7 @@ jobs: exit $EXIT_CODE test-unit: + needs: build timeout-minutes: 20 strategy: matrix: @@ -136,21 +137,16 @@ jobs: runs-on: [ubuntu, macos, windows] runs-on: ${{ matrix.runs-on }}-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Use Node.js ${{ matrix.node-version }}.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v5 with: node-version: ${{ matrix.node-version }}.x cache: 'npm' - name: Install dependencies run: | npm ci - - name: Wait for build job - uses: NathanFirmo/wait-for-other-job@v1.1.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - job: build - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v7 with: name: build-artifacts - name: Unzip artifacts @@ -166,6 +162,7 @@ jobs: run: npm run test-unit --forbid-only test-integration: + needs: build timeout-minutes: 20 strategy: matrix: @@ -174,9 +171,9 @@ jobs: browser: [chromium, firefox, webkit] runs-on: ${{ matrix.runs-on }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Use Node.js ${{ matrix.node-version }}.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v5 with: node-version: ${{ matrix.node-version }}.x cache: 'npm' @@ -185,12 +182,7 @@ jobs: npm ci - name: Install playwright run: npx playwright install --with-deps ${{ matrix.browser }} - - name: Wait for build job - uses: NathanFirmo/wait-for-other-job@v1.1.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - job: build - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v7 with: name: build-artifacts - name: Unzip artifacts @@ -240,9 +232,9 @@ jobs: matrix: node-version: [22] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Use Node.js ${{ matrix.node-version }}.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v5 with: node-version: ${{ matrix.node-version }}.x cache: 'npm' @@ -251,7 +243,7 @@ jobs: npm ci - name: Install playwright run: npx playwright install - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v7 with: name: build-artifacts - name: Unzip artifacts diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3ba91f7e9..f0d27975c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,12 +24,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index f4854bd28..79e0fc306 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -18,9 +18,9 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Use Node.js 22.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v5 with: node-version: 22.x cache: 'npm' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e1e659ecf..3dacee1d6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,9 +10,9 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Use Node.js 22.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v5 with: node-version: 22.x cache: 'npm' diff --git a/.gitignore b/.gitignore index 81fe7a147..4ba4c5fee 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ docs/ npm-debug.log /.idea/ .env +mise.toml build/ .DS_Store yarn.lock @@ -24,6 +25,7 @@ test-results/ # Tracing/debug files .cursor/nal-trace/ +.cursor/*.log # Keep bundled code out of Git dist/ diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 000000000..237e00028 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,374 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": [ + "import", + "typescript" + ], + "categories": { + "correctness": "off" + }, + "options": { + "typeAware": true, + "maxWarnings": 0 + }, + "env": { + "builtin": true + }, + "ignorePatterns": [ + "addons/*/src/third-party/*.ts", + "**/out/*", + "**/out-test/*", + "**/out-esbuild/*", + "**/out-esbuild-test/*", + "**/inwasm-sdks/*", + "**/typings/*.d.ts", + "**/node_modules", + "**/*.js", + "**/*.mjs" + ], + "rules": { + "constructor-super": "error", + "for-direction": "error", + "getter-return": "error", + "no-async-promise-executor": "error", + "no-case-declarations": "error", + "no-class-assign": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-const-assign": "error", + "no-constant-binary-expression": "error", + "no-constant-condition": "error", + "no-control-regex": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-dupe-class-members": "error", + "no-dupe-else-if": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-empty": "error", + "no-empty-character-class": "error", + "no-empty-pattern": "error", + "no-empty-static-block": "error", + "no-ex-assign": "error", + "no-extra-boolean-cast": "error", + "no-fallthrough": "error", + "no-func-assign": "error", + "no-global-assign": "error", + "no-import-assign": "error", + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-loss-of-precision": "error", + "no-misleading-character-class": "error", + "no-new-native-nonconstructor": "error", + "no-nonoctal-decimal-escape": "error", + "no-obj-calls": "error", + "no-prototype-builtins": "error", + "no-redeclare": "error", + "no-regex-spaces": "error", + "no-self-assign": "error", + "no-setter-return": "error", + "no-shadow-restricted-names": "error", + "no-sparse-arrays": "error", + "no-this-before-super": "error", + "no-unassigned-vars": "error", + "no-unexpected-multiline": "error", + "no-unreachable": "error", + "no-unsafe-finally": "error", + "no-unsafe-negation": "error", + "no-unsafe-optional-chaining": "error", + "no-unused-labels": "error", + "no-unused-private-class-members": "error", + "no-unused-vars": "error", + "no-useless-backreference": "error", + "no-useless-catch": "error", + "no-useless-escape": "error", + "no-with": "error", + "preserve-caught-error": "error", + "require-yield": "error", + "use-isnan": "error", + "valid-typeof": "error", + "no-array-constructor": "error", + "no-unused-expressions": "error", + "typescript/ban-ts-comment": "error", + "typescript/no-duplicate-enum-values": "error", + "typescript/no-empty-object-type": "error", + "typescript/no-explicit-any": "error", + "typescript/no-extra-non-null-assertion": "error", + "typescript/no-misused-new": "error", + "typescript/no-namespace": "error", + "typescript/no-non-null-asserted-optional-chain": "error", + "typescript/no-require-imports": "error", + "typescript/no-this-alias": "error", + "typescript/no-unnecessary-type-constraint": "error", + "typescript/no-unsafe-declaration-merging": "error", + "typescript/no-unsafe-function-type": "error", + "typescript/no-wrapper-object-types": "error", + "typescript/prefer-as-const": "error", + "typescript/prefer-namespace-keyword": "error", + "typescript/triple-slash-reference": "error", + "import/no-cycle": "error" + }, + "overrides": [ + { + "files": [ + "**/*.ts", + "**/*.tsx", + "**/*.mts", + "**/*.cts" + ], + "rules": { + "constructor-super": "off", + "getter-return": "off", + "no-class-assign": "off", + "no-const-assign": "off", + "no-dupe-class-members": "off", + "no-dupe-keys": "off", + "no-func-assign": "off", + "no-import-assign": "off", + "no-new-native-nonconstructor": "off", + "no-obj-calls": "off", + "no-redeclare": "off", + "no-setter-return": "off", + "no-this-before-super": "off", + "no-unreachable": "off", + "no-unsafe-negation": "off", + "no-var": "error", + "no-with": "off", + "prefer-const": "error", + "prefer-rest-params": "error", + "prefer-spread": "error" + } + }, + { + "files": [ + "**/*.ts" + ], + "jsPlugins": [ + "@stylistic/eslint-plugin", + { + "name": "jsdoc-js", + "specifier": "eslint-plugin-jsdoc" + }, + "oxlint-plugin-eslint" + ], + "rules": { + "@stylistic/comma-spacing": [ + "warn", + { + "before": false, + "after": true + } + ], + "@stylistic/indent": [ + "warn", + 2 + ], + "@stylistic/semi": [ + "warn", + "always" + ], + "@stylistic/quotes": [ + "warn", + "single", + { + "allowTemplateLiterals": "always" + } + ], + "@stylistic/member-delimiter-style": [ + "warn", + { + "multiline": { + "delimiter": "semi", + "requireLast": true + }, + "singleline": { + "delimiter": "comma", + "requireLast": false + } + } + ], + "@stylistic/type-annotation-spacing": "warn", + "@stylistic/space-unary-ops": "warn", + "@stylistic/keyword-spacing": "warn", + "@stylistic/max-len": [ + "warn", + { + "code": 1000, + "comments": 100, + "ignoreTrailingComments": true, + "ignoreUrls": true, + "ignorePattern": "^ *((?(//|\\*) @vt)|(?\\* \\| )|(?// ))" + } + ], + "@stylistic/new-parens": "warn", + "@stylistic/no-extra-semi": "error", + "@stylistic/no-trailing-spaces": "warn", + "eslint-js/object-curly-spacing": [ + "warn", + "always" + ], + "@stylistic/spaced-comment": [ + "warn", + "always", + { + "markers": [ + "/" + ], + "exceptions": [ + "-" + ] + } + ], + "jsdoc-js/check-alignment": "warn", + "jsdoc-js/check-param-names": "warn", + "jsdoc-js/multiline-blocks": "warn", + "jsdoc-js/no-multi-asterisks": "warn", + "eslint-js/one-var": [ + "warn", + "never" + ], + "eslint-js/no-restricted-syntax": [ + "warn", + { + "selector": "CallExpression[callee.name='requestAnimationFrame']", + "message": "The global requestAnimationFrame() should be avoided, call it on the parent window from ICoreBrowserService." + }, + { + "selector": "CallExpression[callee.name='cancelAnimationFrame']", + "message": "The global cancelAnimationFrame() should be avoided, call it on the parent window from ICoreBrowserService." + }, + { + "selector": "CallExpression > MemberExpression[object.name='window'][property.name='requestAnimationFrame']", + "message": "window.requestAnimationFrame() should be avoided, call it on the parent window from ICoreBrowserService." + }, + { + "selector": "CallExpression > MemberExpression[object.name='window'][property.name='cancelAnimationFrame']", + "message": "window.cancelAnimationFrame() should be avoided, call it on the parent window from ICoreBrowserService." + }, + { + "selector": "MemberExpression[object.name='window'][property.name='devicePixelRatio']", + "message": "window.devicePixelRatio should be avoided, get it from ICoreBrowserService." + } + ], + "curly": [ + "warn", + "multi-line" + ], + "eqeqeq": [ + "warn", + "always" + ], + "no-duplicate-imports": "warn", + "no-else-return": [ + "warn", + { + "allowElseIf": false + } + ], + "no-eval": "warn", + "no-irregular-whitespace": "warn", + "no-restricted-imports": [ + "warn", + { + "patterns": [ + ".*\\/out\\/.*" + ] + } + ], + "no-unsafe-finally": "warn", + "no-unused-vars": "off", + "no-var": "warn", + "no-empty": "off", + "no-empty-pattern": "off", + "no-cond-assign": "off", + "no-case-declarations": "off", + "for-direction": "off", + "no-prototype-builtins": "off", + "no-useless-escape": "off", + "no-self-assign": "off", + "no-async-promise-executor": "off", + "prefer-rest-params": "off", + "no-control-regex": "off", + "no-fallthrough": "off", + "prefer-spread": "off", + "prefer-const": "warn", + "no-unused-expressions": "off", + "typescript/array-type": [ + "warn", + { + "default": "array", + "readonly": "generic" + } + ], + "typescript/consistent-type-assertions": "warn", + "typescript/consistent-type-definitions": "warn", + "typescript/explicit-function-return-type": [ + "warn", + { + "allowExpressions": true + } + ], + "typescript/explicit-member-accessibility": [ + "warn", + { + "accessibility": "explicit", + "overrides": { + "constructors": "off" + } + } + ], + "typescript/no-confusing-void-expression": [ + "warn", + { + "ignoreArrowShorthand": true + } + ], + "typescript/no-useless-constructor": "warn", + "typescript/prefer-nullish-coalescing": [ + "warn", + { + "ignorePrimitives": true + } + ], + "typescript/prefer-namespace-keyword": "warn", + "typescript/no-unused-vars": [ + "warn", + { + "vars": "all", + "args": "none" + } + ], + "typescript/no-require-imports": "off", + "typescript/no-explicit-any": "off", + "typescript/no-wrapper-object-types": "off", + "typescript/no-empty-object-type": "off", + "typescript/no-unsafe-function-type": "off", + "typescript/no-this-alias": "off", + "typescript/no-namespace": "off", + "typescript/no-duplicate-enum-values": "off" + } + }, + { + "files": [ + "**/*.api.ts", + "**/*.test.ts" + ], + "rules": { + "eslint-js/object-curly-spacing": "off", + "@stylistic/max-len": "off", + "typescript/no-unused-vars": "off", + "typescript/explicit-function-return-type": "off", + "typescript/explicit-member-accessibility": "off" + } + }, + { + "files": [ + "demo/**/*.ts", + "**/*.benchmark.ts" + ], + "rules": { + "typescript/prefer-nullish-coalescing": "off" + } + } + ] +} diff --git a/.oxlintrc.typings.json b/.oxlintrc.typings.json new file mode 100644 index 000000000..d3dd28e01 --- /dev/null +++ b/.oxlintrc.typings.json @@ -0,0 +1,120 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "options": { + "maxWarnings": 0 + }, + "env": { + "builtin": true + }, + "overrides": [ + { + "files": [ + "typings/**/*.d.ts" + ], + "plugins": [ + "typescript" + ], + "jsPlugins": [ + "@stylistic/eslint-plugin", + { + "name": "jsdoc-js", + "specifier": "eslint-plugin-jsdoc" + }, + "oxlint-plugin-eslint" + ], + "rules": { + "@stylistic/indent": [ + "warn", + 2 + ], + "@stylistic/semi": [ + "warn", + "always" + ], + "@stylistic/quotes": [ + "warn", + "single", + { + "allowTemplateLiterals": "always" + } + ], + "@stylistic/member-delimiter-style": [ + "warn", + { + "multiline": { + "delimiter": "semi", + "requireLast": true + }, + "singleline": { + "delimiter": "comma", + "requireLast": false + } + } + ], + "@stylistic/type-annotation-spacing": "warn", + "@stylistic/keyword-spacing": "warn", + "@stylistic/max-len": [ + "warn", + { + "code": 1000, + "comments": 80, + "ignoreUrls": true, + "ignorePattern": "^ *(?\\* Ps=)" + } + ], + "@stylistic/no-extra-semi": "error", + "@stylistic/no-trailing-spaces": "warn", + "eslint-js/object-curly-spacing": [ + "warn", + "always" + ], + "@stylistic/spaced-comment": [ + "warn", + "always", + { + "markers": [ + "/" + ], + "exceptions": [ + "-" + ] + } + ], + "@stylistic/comma-dangle": [ + "warn", + { + "objects": "never", + "arrays": "never", + "functions": "never" + } + ], + "@stylistic/eol-last": "warn", + "curly": [ + "warn", + "multi-line" + ], + "eqeqeq": [ + "warn", + "always" + ], + "jsdoc-js/check-alignment": "warn", + "jsdoc-js/check-param-names": "warn", + "no-irregular-whitespace": "warn", + "typescript/array-type": [ + "warn", + { + "default": "array", + "readonly": "generic" + } + ], + "typescript/explicit-function-return-type": [ + "warn", + { + "allowExpressions": true + } + ], + "typescript/prefer-namespace-keyword": "warn" + } + } + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json index 07c424e5d..facfa4f4d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,9 +15,6 @@ "--recursive", "${workspaceRoot}/out/**/*.test.js" ], - "env": { - "NODE_PATH": "${workspaceRoot}/out" - }, "sourceMaps": true, "outFiles": [ "${workspaceRoot}/out/**/*.js" ], "internalConsoleOptions": "openOnSessionStart" diff --git a/AGENTS.md b/AGENTS.md index 0d5d03588..e32bae54c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,6 +26,7 @@ npm run build && npm run esbuild # Build all TypeScript and bundle - Integration tests: `npm run test-integration` (Playwright across Chrome/Firefox/WebKit) - Integration tests by file: `npm run test-integration -- test/playwright/InputHandler.test.ts`. Never use grep to filter tests, it doesn't work - Integration tests by addon: `npm run test-integration -- --suite=addon-search`. Suites always follow the format `addon-` +- Lint: `npm run lint` (oxlint with type-aware rules, then ESLint for `naming-convention` only), `npm run lint-api` for `typings/`, `npm run lint-fix` for oxlint auto-fix - Lint changes: `npm run lint-changes` to lint only changed files, `npm run lint-changes-fix` to fix them ## Addon Development Pattern @@ -98,3 +99,15 @@ const cell = line?.getCell(0); ## Writing unit tests - Unit tests live alongside the source code file of the thing it's testing with a .test.ts suffix. + +## Cursor Cloud specific instructions + +**Demo server**: Start with `npm start` (port 3000). The demo server uses node-pty to spawn real shell sessions over WebSocket. Integration tests auto-start it via Playwright's `webServer` config, so you don't need to start it manually for `npm run test-integration`. + +**Build before testing**: Always run `npm run build && npm run esbuild` before `npm run test-unit`. Integration tests also need `npm run esbuild-demo-client` and `npm run esbuild-demo-server`. The update script handles this automatically on session start. + +**No external services**: This project has zero external dependencies (no databases, Docker, or APIs). Everything runs locally with Node.js. + +**TypeScript compiler**: The project uses `tsgo` (native TypeScript compiler preview) rather than standard `tsc`. It's installed via the `@typescript/native-preview` package. + +**Lint only changed files**: Prefer `npm run lint-changes` over `npm run lint` when iterating on code changes — it's significantly faster. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fe61ad265..b20229f1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ The preferred way to report bugs or request features is to use It's pretty common for maintainers of large open source projects to suffer from burnout, especially when needing to triage a large number of incoming issues instead of actually building things. Here are some of the steps we take to try mitigate this: -- Support questions live in [GH discussions](https://github.com/xtermjs/xterm.js/discussions), issues may be transfered there without further comment and core maintainers may or may not participate in discussions. +- Support questions live in [GH discussions](https://github.com/xtermjs/xterm.js/discussions), issues may be transferred there without further comment and core maintainers may or may not participate in discussions. - Issues are strictly for well defined features or bugs that are _actionable_. - Sometimes features are out of scope. A common example of this is a niche feature that the pricipal implementation ([VS Code](https://code.visualstudio.com/)) won't leverage and therefore would be difficult to maintain and likely suffer from bitrot. The reporter may not agree with this, but you could always create an addon if that works or maintain your own fork if it comes to that. - If a feature does not have a clear way forward or needs more discussion it may be closed ro moved to a discussion. diff --git a/addons/addon-attach/test/AttachAddon.test.ts b/addons/addon-attach/test/AttachAddon.test.ts index b49d9f337..ee9b22c2e 100644 --- a/addons/addon-attach/test/AttachAddon.test.ts +++ b/addons/addon-attach/test/AttachAddon.test.ts @@ -15,7 +15,7 @@ test.beforeAll(async ({ browser }) => { }); test.afterAll(async () => await ctx.page.close()); -test.describe('Search Tests', () => { +test.describe('AttachAddon', () => { test.beforeEach(async () => { await ctx.proxy.reset(); diff --git a/addons/addon-clipboard/src/ClipboardAddon.ts b/addons/addon-clipboard/src/ClipboardAddon.ts index 5e194880c..535c450be 100644 --- a/addons/addon-clipboard/src/ClipboardAddon.ts +++ b/addons/addon-clipboard/src/ClipboardAddon.ts @@ -78,13 +78,43 @@ export class BrowserClipboardProvider implements IClipboardProvider { } } +/** + * TODO: Once the base64 handling on Uint8Arrays is more common, + * remove the btoa/atob fallbacks below. + */ +interface IUint8ArrayB64 extends Uint8Array { + toBase64(): string; +} +interface IUint8ArrayB64Ctor extends Uint8ArrayConstructor { + fromBase64(s: string): IUint8ArrayB64; +} + export class Base64 implements IBase64 { public encodeText(data: string): string { - return btoa(data); + const bytes = new TextEncoder().encode(data) as IUint8ArrayB64; + if (bytes.toBase64 !== undefined) { + return bytes.toBase64(); + } + let bin = ''; + for (let i = 0; i < bytes.length; i++) { + bin += String.fromCharCode(bytes[i]); + } + return btoa(bin); } public decodeText(data: string): string { + if ((Uint8Array as IUint8ArrayB64Ctor).fromBase64 !== undefined) { + try { + return new TextDecoder().decode((Uint8Array as IUint8ArrayB64Ctor).fromBase64(data)); + } catch {} + return ''; + } try { - return atob(data); + const bin = atob(data); + const bytes = new Uint8Array(bin.length); + for (let i = 0; i < bin.length; ++i) { + bytes[i] = bin.charCodeAt(i); + } + return new TextDecoder().decode(bytes); } catch {} return ''; } diff --git a/addons/addon-clipboard/test/ClipboardAddon.test.ts b/addons/addon-clipboard/test/ClipboardAddon.test.ts index 2c04e619b..6995850d4 100644 --- a/addons/addon-clipboard/test/ClipboardAddon.test.ts +++ b/addons/addon-clipboard/test/ClipboardAddon.test.ts @@ -29,7 +29,7 @@ test.describe('ClipboardAddon', () => { await ctx.page.context().grantPermissions(['clipboard-read', 'clipboard-write']); } await ctx.page.evaluate(` - window.term.reset() + window.term.reset(); window.clipboard?.dispose(); window.clipboard = new ClipboardAddon(); window.term.loadAddon(window.clipboard); @@ -92,4 +92,22 @@ test.describe('ClipboardAddon', () => { deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), ''); }); }); + + test.describe('non-ASCII', () => { + const testDataEncoded = '4oKsbWzDpMO8dMOf'; + const testDataDecoded = '€mläütß'; + test('write simple string', async () => { + await ctx.proxy.write(`\x1b]52;c;${testDataEncoded}\x07`); + deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), testDataDecoded); + }); + test('read simple string', async () => { + await ctx.page.evaluate(` + window.data2 = []; + window.term.onData(e => data2.push(e)); + `); + await ctx.page.evaluate((d) => window.navigator.clipboard.writeText(d), testDataDecoded); + await ctx.proxy.write(`\x1b]52;c;?\x07`); + deepEqual(await ctx.page.evaluate('window.data2'), [`\x1b]52;c;${testDataEncoded}\x07`]); + }); + }); }); diff --git a/addons/addon-clipboard/typings/addon-clipboard.d.ts b/addons/addon-clipboard/typings/addon-clipboard.d.ts index f8e024ac3..f5a892e21 100644 --- a/addons/addon-clipboard/typings/addon-clipboard.d.ts +++ b/addons/addon-clipboard/typings/addon-clipboard.d.ts @@ -82,7 +82,7 @@ declare module '@xterm/addon-clipboard' { /** * The clipboard provider interface that enables xterm.js to access the browser clipboard. * - * Note this this clipboard provider does not implement own cut buffers as xterm does, + * Note that this clipboard provider does not implement own cut buffers as xterm does, * but redirect the selection parameter always to navigator.clipboard. */ export class BrowserClipboardProvider implements IClipboardProvider{ diff --git a/addons/addon-fit/src/FitAddon.ts b/addons/addon-fit/src/FitAddon.ts index 3db988acd..75bbe9caa 100644 --- a/addons/addon-fit/src/FitAddon.ts +++ b/addons/addon-fit/src/FitAddon.ts @@ -74,14 +74,14 @@ export class FitAddon implements ITerminalAddon, IFitApi { : (this._terminal.options.scrollbar?.width ?? ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH)); const parentElementStyle = _getComputedStyle(this._terminal.element.parentElement); - const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')); - const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width'))); + const parentElementHeight = Math.max(0, parseInt(parentElementStyle.getPropertyValue('height'), 10) || 0); + const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width'), 10) || 0); const elementStyle = _getComputedStyle(this._terminal.element); const elementPadding = { - top: parseInt(elementStyle.getPropertyValue('padding-top')), - bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')), - right: parseInt(elementStyle.getPropertyValue('padding-right')), - left: parseInt(elementStyle.getPropertyValue('padding-left')) + top: parseInt(elementStyle.getPropertyValue('padding-top'), 10) || 0, + bottom: parseInt(elementStyle.getPropertyValue('padding-bottom'), 10) || 0, + right: parseInt(elementStyle.getPropertyValue('padding-right'), 10) || 0, + left: parseInt(elementStyle.getPropertyValue('padding-left'), 10) || 0 }; const elementPaddingVer = elementPadding.top + elementPadding.bottom; const elementPaddingHor = elementPadding.right + elementPadding.left; diff --git a/addons/addon-image/README.md b/addons/addon-image/README.md index a18ce18bb..3b636d922 100644 --- a/addons/addon-image/README.md +++ b/addons/addon-image/README.md @@ -1,6 +1,7 @@ ## @xterm/addon-image -Inline image output in xterm.js. Supports SIXEL and iTerm's inline image protocol (IIP). +Inline image output in xterm.js. Supports SIXEL, iTerm's inline image protocol (IIP) +and partially Kitty's terminal graphics prtocol (TGP). ![](fixture/example.png) @@ -43,9 +44,6 @@ terminal.loadAddon(imageAddon); ### General Notes -- *IMPORTANT:* The worker approach as done in previous releases got removed. - The addon contructor no longer expects a worker path as first argument. - - By default the addon will activate these `windowOptions` reports on the terminal: - getWinSizePixels (CSI 14 t) - getCellSizePixels (CSI 16 t) @@ -73,7 +71,7 @@ terminal.loadAddon(imageAddon); - **Cursor Positioning** If scrolling is set, the cursor will be placed at the first image column of the last image row (VT340 mode). - Other cursor positioning modes as used by xterm or mintty are not supported. + Other cursor positioning modes as used by xterm or mintty are not supported for sixel. - **SIXEL Palette Handling** By default the addon limits the palette size to 256 registers (as demanded by the DEC specification). @@ -92,7 +90,7 @@ terminal.loadAddon(imageAddon); therefore palette animations cannot be used. - **SIXEL Raster Attributes Handling** - If raster attributes were found in the SIXEL data (level 2), the image will always be truncated to the given height/width extend. We deviate here from the specification on purpose, as it allows several processing optimizations. For level 1 SIXEL data without any raster attributes the image can freely grow in width and height up to the last data byte, which has a much higher processing penalty. In general encoding libraries should not create level 1 data anymore and should not produce pixel information beyond the announced height/width extend. Both is discouraged by the >30 years old specification. + If raster attributes were found in the SIXEL data (level 2), the image will always be truncated to the given height/width extent. We deviate here from the specification on purpose, as it allows several processing optimizations. For level 1 SIXEL data without any raster attributes the image can freely grow in width and height up to the last data byte, which has a much higher processing penalty. In general encoding libraries should not create level 1 data anymore and should not produce pixel information beyond the announced height/width extent. Both is discouraged by the >30 years old specification. Currently the SIXEL implementation of the addon does not take custom pixel sizes into account, a SIXEL pixel will map 1:1 to a screen pixel. @@ -100,17 +98,24 @@ terminal.loadAddon(imageAddon); Set by default, change it with `{iipSupport: true}`. The IIP implementation has the following features / restrictions (sequence will silently fail for unmet conditions): - - Supported formats: PNG, JPEG and GIF + - Supported formats: PNG, JPEG, GIF and QOI - No animation support. - Image type hinting is not supported (always deducted from data header). - File download is not supported. - Filename gets parsed but not used. - Strict base64 handling as of RFC4648 §4 (standard alphabet, optional padding, no separator bytes allowed). - - Payload size may not exceed CEIL(sizeParameter * 4 / 3). - Image scaling beyond terminal viewport size is allowed (e.g. `width=200%`). - Image pixel size is restricted by `pixelLimit` (pre- and post resizing). - - Size parameter is restricted by `iipSizeLimit`. - - Cursor positioning behaves the same as for sixel (see above). + - Playload size is restricted by `iipSizeLimit`. + - size parameter is not mandatory anymore. + - Cursor gets positioned at the next cell of the last image line. + - ReportCellSize sequence is supported. + - Hi-res display support is currently limited (image gets blurred). + +- **Kitty Graphics Support (TGP)** + Set by default, change it with `{kittySupport: true}`. + + Note that the kitty graphics support is still WIP. ### Storage and Drawing Settings @@ -127,6 +132,7 @@ The addon exposes two properties to interact with the storage limits at runtime: By default the addon will show a placeholder pattern for evicted images that are still part of the terminal (e.g. in the scrollback). The pattern can be deactivated by toggling `showPlaceholder`. + ### Image Data Retrieval The addon provides the following API endpoints to retrieve raw image data as canvas: @@ -140,11 +146,12 @@ The addon provides the following API endpoints to retrieve raw image data as can The buffer position is the 0-based absolute index (including scrollback at top). Note that the canvas gets created and data copied over for every call, thus it is not suitable for performance critical actions. + ### Memory Usage -The addon does most image processing in Javascript and therefore can occupy a rather big amount of memory. To get an idea where the memory gets eaten, lets look at the data flow and processing steps: -- Incomming image data chunk at `term.write` (terminal) - `term.write` might stock up incoming chunks. To circumvent this, you will need proper flow control (see xterm.js docs). Note that with image output it is more likely to run into this issue, as it can create lots of MBs in very short time. +The addon does most image processing in JavaScript and therefore can occupy a rather big amount of memory. To get an idea where the memory gets eaten, let's look at the data flow and processing steps: +- Incoming image data chunk at `term.write` (terminal) + `term.write` might stack up incoming chunks. To circumvent this, you will need proper flow control (see xterm.js docs). Note that with image output it is more likely to run into this issue, as it can create lots of MBs in very short time. - Sequence Parser (terminal) The parser operates on a buffer containing up to 2^17 codepoints (~0.5 MB). - Sequence Handler - Chunk Decoding (addon) @@ -170,18 +177,18 @@ const totalActive = storageBytes + decodingBytes; ``` Note that browsers have offloading tricks for rarely touched memory segments, esp. `storageBytes` might not directly translate into real memory usage. Usage peaks will happen during active decoding of multiple big images due to the need of 2 full pixel buffers at the same time, which cannot be offloaded. Thus you may want to keep an eye on `pixelLimit` under limited memory conditions. -Further note that the formulas above do not respect the Javascript object's overhead. Compared to the raw buffer needs the book keeping by these objects is rather small (<<5%). +Further note that the formulas above do not respect the JavaScript object's overhead. Compared to the raw buffer needs the bookkeeping by these objects is rather small (<<5%). _Why should I care about memory usage at all?_ -Well you don't have to, and it probably will just work fine with the addon defaults. But for bigger integrations, where much more data is held in the Javascript context (like multiple terminals on one page), it is likely to hit the engine's memory limit sooner or later under decoding and/or storage pressure. +Well you don't have to, and it probably will just work fine with the addon defaults. But for bigger integrations, where much more data is held in the JavaScript context (like multiple terminals on one page), it is likely to hit the engine's memory limit sooner or later under decoding and/or storage pressure. _How can I adjust the memory usage?_ - `pixelLimit` - A constructor setting, thus you would have to anticipate, whether (multiple) terminals in your page gonna do lots of concurrent decoding. Since this is normally not the case and the memory usage is only temporarily peaking, a rather high value should work even with multiple terminals in one page. + A constructor setting, thus you would have to anticipate, whether (multiple) terminals in your page gonna do lots of concurrent decoding. Since this is normally not the case and the memory usage only peaks temporarily, a rather high value should work even with multiple terminals in one page. - `storageLimit` - A constructor and a runtime setting. In conjunction with `storageUsage` you can do runtime checks and adjust the limit to your needs. If you have to lower the limit below the current usage, images will be removed in FIFO order and may turn into a placeholder in the terminal's scrollback (if `showPlaceholder` is set). When adjusting keep in mind to leave enough room for memory peaking for decoding. -- `sixelSizeLimit` - A constructor setting. This has only a small impact on peaking memory during decoding. It is meant to avoid processing of overly big or broken SIXEL sequences at an earlier phase, thus may stop the decoder from entering its memory intensive task for potentially invalid data. + A constructor and a runtime setting. In conjunction with `storageUsage` you can do runtime checks and adjust the limit to your needs. If you have to lower the limit below the current usage, images will be removed in FIFO order and may turn into a placeholder in the terminal's scrollback (if `showPlaceholder` is set). When adjusting keep in mind to leave enough room for peak memory use during decoding. +- `sixelSizeLimit | iipSizeLimit | kittySizeLimit` + Constructor settings. This has only a small impact on peak memory during decoding. It is meant to avoid processing of overly big or broken image sequences at an earlier phase, thus may stop the invoked decoders from entering memory intensive tasks for potentially invalid data. ### Terminal Interaction @@ -211,23 +218,5 @@ _How can I adjust the memory usage?_ ### Status -- Sixel support and image handling in xterm.js is considered beta quality. -- IIP support is in alpha stage. Please file a bug for any awkwardities. - - -### Changelog - -- 0.5.0 integrate with xtermjs base repo (at v0.4.3) -- 0.4.3 defer canvas creation -- 0.4.2 fix image canvas resize -- 0.4.1 compat release for xterm.js 5.2.0 -- 0.4.0 IIP support -- 0.3.1 compat release for xterm.js 5.1.0 -- 0.3.0 important change: worker removed from addon -- 0.2.0 compat release for xterm.js 5.0.0 -- 0.1.3 bugfix: avoid striping -- 0.1.2 bugfix: reset clear flag -- 0.1.1 bugfixes: - - clear sticky image tiles on render - - create folder from bootstrap.sh - - fix peer dependency in package.json +- Sixel and IIP support and image handling in xterm.js is considered beta quality. +- Kitty support is in alpha stage. Please file a bug for any awkwardities or missing features. diff --git a/addons/addon-image/fixture/testimages/dice.qoi b/addons/addon-image/fixture/testimages/dice.qoi new file mode 100644 index 000000000..bbc8154fc Binary files /dev/null and b/addons/addon-image/fixture/testimages/dice.qoi differ diff --git a/addons/addon-image/src/IIPHandler.ts b/addons/addon-image/src/IIPHandler.ts index 6f94ef8ed..56f5cdf35 100644 --- a/addons/addon-image/src/IIPHandler.ts +++ b/addons/addon-image/src/IIPHandler.ts @@ -8,7 +8,7 @@ import { IIPImageStorage } from './IIPImageStorage'; import { CELL_SIZE_DEFAULT } from './ImageStorage'; import Base64Decoder from 'xterm-wasm-parts/lib/base64/Base64Decoder.wasm'; import QoiDecoder from 'xterm-wasm-parts/lib/qoi/QoiDecoder.wasm'; -import { HeaderParser, IHeaderFields, HeaderState } from './IIPHeaderParser'; +import { HeaderParser, IHeaderFields, HeaderState, SequenceType } from './IIPHeaderParser'; import { imageType, UNSUPPORTED_TYPE } from './IIPMetrics'; // Local const enum mirror - esbuild can't inline const enums from external packages @@ -23,6 +23,7 @@ const enum DecoderConst { // default IIP header values const DEFAULT_HEADER: IHeaderFields = { + type: SequenceType.INVALID, name: 'Unnamed file', size: 0, width: 'auto', @@ -39,6 +40,8 @@ export class IIPHandler implements IOscHandler, IResetHandler { private _dec: Base64Decoder; private _qoiDec: QoiDecoder; private _metrics = UNSUPPORTED_TYPE; + private _isMultipart = false; + private _abortMulti = false; constructor( private readonly _opts: IImageAddonOptions, @@ -52,11 +55,14 @@ export class IIPHandler implements IOscHandler, IResetHandler { this._qoiDec = new QoiDecoder(DecoderConst.KEEP_DATA); } - public reset(): void {} + public reset(): void { + this._hp.reset(); + this._dec.release(); + this._qoiDec.release(); + } public start(): void { this._aborted = false; - this._header = DEFAULT_HEADER; this._metrics = UNSUPPORTED_TYPE; this._hp.reset(); } @@ -76,15 +82,27 @@ export class IIPHandler implements IOscHandler, IResetHandler { return; } if (dataPos > 0) { - this._header = Object.assign({}, DEFAULT_HEADER, this._hp.fields); - if (!this._header.inline || !this._header.size || this._header.size > this._opts.iipSizeLimit) { + const seqType = this._hp.fields.type; + if (seqType === SequenceType.FILE) { + if (this._isMultipart) { + this._isMultipart = false; + this._abortMulti = false; + this._dec.release(); + } + this._header = Object.assign({}, DEFAULT_HEADER, this._hp.fields); + if (!this._header.inline) { + this._aborted = true; + return; + } + this._dec.init(); + } else if (this._abortMulti) { this._aborted = true; return; } - this._dec.init(); if ((this._dec.put(data.subarray(dataPos, end)) as number) !== DecoderConst.OK) { this._dec.release(); this._aborted = true; + if (this._isMultipart) this._abortMulti = true; } } } @@ -93,22 +111,58 @@ export class IIPHandler implements IOscHandler, IResetHandler { public end(success: boolean): boolean | Promise { if (this._aborted) return true; + if (this._hp.state !== HeaderState.END) { + if (this._hp.end()) return true; + } + const seqType = this._hp.fields.type; + + if (seqType === SequenceType.FILEPART) return true; + + if (seqType === SequenceType.REPORTCELLSIZE) { + // OSC 1337 ; ReportCellSize=[height];[width];[scale] ST + let width = CELL_SIZE_DEFAULT.width; + let height = CELL_SIZE_DEFAULT.height; + if (this._renderer.dimensions) { + width = this._renderer.dimensions.css.canvas.width / this._coreTerminal.cols; + height = this._renderer.dimensions.css.canvas.height / this._coreTerminal.rows; + } + const scale = this._coreTerminal._core._coreBrowserService?.dpr ?? 1; + const report = `\x1b]1337;ReportCellSize=${height.toFixed(3)};${width.toFixed(3)};${scale.toFixed(3)}\x1b\\`; + this._coreTerminal.input(report, false); + return true; + } + + if (seqType === SequenceType.MULTIPARTFILE) { + this._header = Object.assign({}, DEFAULT_HEADER, this._hp.fields); + this._isMultipart = true; + this._abortMulti = false; + this._dec.release(); + this._dec.init(); + return true; + } + + if (seqType === SequenceType.FILEEND) { + if (!this._isMultipart) return true; + this._isMultipart = false; + if (this._abortMulti || this._header.type !== SequenceType.MULTIPARTFILE) return true; + } + + // fallthrough for SequenceType.FILE & SequenceType.FILEEND + let w = 0; let h = 0; // early exit condition chain - let cond: number | boolean = true; + let cond: number | boolean; if (cond = success) { if (cond = !this._dec.end()) { - if (cond = this._dec.data8.length === this._header.size) { - this._metrics = imageType(this._dec.data8); - if (cond = this._metrics.mime !== 'unsupported') { - w = this._metrics.width; - h = this._metrics.height; - if (cond = w && h && w * h < this._opts.pixelLimit) { - [w, h] = this._resize(w, h).map(Math.floor); - cond = w && h && w * h < this._opts.pixelLimit; - } + this._metrics = imageType(this._dec.data8); + if (cond = this._metrics.mime !== 'unsupported') { + w = this._metrics.width; + h = this._metrics.height; + if (cond = w && h && w * h < this._opts.pixelLimit) { + [w, h] = this._resize(w, h).map(Math.floor); + cond = w && h && w * h < this._opts.pixelLimit; } } } @@ -168,8 +222,8 @@ export class IIPHandler implements IOscHandler, IResetHandler { private _dim(s: string, total: number, cdim: number): number { if (s === 'auto') return 0; - if (s.endsWith('%')) return parseInt(s.slice(0, -1)) * total / 100; - if (s.endsWith('px')) return parseInt(s.slice(0, -2)); - return parseInt(s) * cdim; + if (s.endsWith('%')) return parseInt(s.slice(0, -1), 10) * total / 100; + if (s.endsWith('px')) return parseInt(s.slice(0, -2), 10); + return parseInt(s, 10) * cdim; } } diff --git a/addons/addon-image/src/IIPHeaderParser.test.ts b/addons/addon-image/src/IIPHeaderParser.test.ts index e42782c14..ba6d5f052 100644 --- a/addons/addon-image/src/IIPHeaderParser.test.ts +++ b/addons/addon-image/src/IIPHeaderParser.test.ts @@ -4,19 +4,20 @@ */ import { assert } from 'chai'; -import { HeaderParser, HeaderState, IHeaderFields } from './IIPHeaderParser'; +import { HeaderParser, HeaderState, IHeaderFields, SequenceType } from './IIPHeaderParser'; const CASES: [string, IHeaderFields][] = [ - ['File=size=123456;name=dGVzdA==:', {name: 'test', size: 123456}], - ['File=size=123456;name=dGVzdA:', {name: 'test', size: 123456}], + ['File=size=123456;name=dGVzdA==:', {type: SequenceType.FILE, name: 'test', size: 123456}], + ['File=size=123456;name=dGVzdA:', {type: SequenceType.FILE, name: 'test', size: 123456}], // utf-8 encoding in name - ['File=size=123456;name=w7xtbMOkdXTDnw==:', {name: 'ümläutß', size: 123456}], - ['File=size=123456;name=w7xtbMOkdXTDnw:', {name: 'ümläutß', size: 123456}], + ['File=size=123456;name=w7xtbMOkdXTDnw==:', {type: SequenceType.FILE, name: 'ümläutß', size: 123456}], + ['File=size=123456;name=w7xtbMOkdXTDnw:', {type: SequenceType.FILE, name: 'ümläutß', size: 123456}], // full header spec [ 'File=inline=1;width=10px;height=20%;preserveAspectRatio=1;size=123456;name=w7xtbMOkdXTDnw:', { + type: SequenceType.FILE, inline: 1, width: '10px', height: '20%', @@ -28,6 +29,7 @@ const CASES: [string, IHeaderFields][] = [ [ 'File=inline=1;width=auto;height=20;preserveAspectRatio=1;size=123456;name=w7xtbMOkdXTDnw:', { + type: SequenceType.FILE, inline: 1, width: 'auto', height: '20', @@ -101,7 +103,7 @@ describe('IIPHeaderParser', () => { let res = hp.parse(inp, 0, inp.length); assert.strictEqual(res, inp.length); assert.strictEqual(hp.state, HeaderState.END); - assert.deepEqual(hp.fields, {name: 'test', size: 0}); + assert.deepEqual(hp.fields, {type: SequenceType.FILE, name: 'test', size: 0}); hp.reset(); inp = fromBs(CASES[0][0]); res = hp.parse(inp, 0, inp.length); @@ -115,7 +117,7 @@ describe('IIPHeaderParser', () => { let res = hp.parse(inp, 0, inp.length); assert.strictEqual(res, inp.length); assert.strictEqual(hp.state, HeaderState.END); - assert.deepEqual(hp.fields, {name: '', size: 123456}); + assert.deepEqual(hp.fields, {type: SequenceType.FILE, name: '', size: 123456}); hp.reset(); inp = fromBs(CASES[0][0]); res = hp.parse(inp, 0, inp.length); @@ -135,4 +137,124 @@ describe('IIPHeaderParser', () => { assert.strictEqual(hp.state, HeaderState.END); assert.deepEqual(hp.fields, CASES[0][1]); }); + it('FilePart sequence', () => { + const hp = new HeaderParser(); + const inp = fromBs('FilePart=w7xtbMOkdXTDnw'); + const res = hp.parse(inp, 0, inp.length); + assert.strictEqual(res, 9); + assert.strictEqual(hp.state, HeaderState.END); + assert.deepEqual(hp.fields.type, SequenceType.FILEPART); + }); + it('FilePart sequence - bytewise', () => { + const hp = new HeaderParser(); + const inp = fromBs('FilePart=w7xtbMOkdXTDnw'); + let res = -2; + let pos = 0; + while (res === -2 && pos < inp.length) { + res = hp.parse(new Uint32Array([inp[pos++]]), 0, 1); + } + assert.strictEqual(res, 1); + assert.strictEqual(hp.state, HeaderState.END); + assert.deepEqual(hp.fields.type, SequenceType.FILEPART); + }); + it('MultipartFile sequence', () => { + const hp = new HeaderParser(); + const inp = fromBs('MultipartFile=inline=1;width=10px;height=20%;preserveAspectRatio=1;size=123456;name=w7xtbMOkdXTDnw'); + let res = hp.parse(inp, 0, inp.length); + assert.strictEqual(res, -2); + assert.strictEqual(hp.state, HeaderState.VALUE); + res = hp.end(); + assert.strictEqual(res, 0); + assert.strictEqual(hp.state, HeaderState.END); + assert.deepEqual( + hp.fields, + { + type: SequenceType.MULTIPARTFILE, + inline: 1, + width: '10px', + height: '20%', + preserveAspectRatio: 1, + size: 123456, + name: 'ümläutß' + } + ); + }); + it('MultipartFile sequence - bytewise', () => { + const hp = new HeaderParser(); + const inp = fromBs('MultipartFile=inline=1;width=10px;height=20%;preserveAspectRatio=1;size=123456;name=w7xtbMOkdXTDnw'); + let res = -2; + let pos = 0; + while (res === -2 && pos < inp.length) { + res = hp.parse(new Uint32Array([inp[pos++]]), 0, 1); + } + assert.strictEqual(res, -2); + assert.strictEqual(hp.state, HeaderState.VALUE); + res = hp.end(); + assert.strictEqual(res, 0); + assert.strictEqual(hp.state, HeaderState.END); + assert.deepEqual( + hp.fields, + { + type: SequenceType.MULTIPARTFILE, + inline: 1, + width: '10px', + height: '20%', + preserveAspectRatio: 1, + size: 123456, + name: 'ümläutß' + } + ); + }); + it('FileEnd sequence', () => { + const hp = new HeaderParser(); + const inp = fromBs('FileEnd'); + let res = hp.parse(inp, 0, inp.length); + assert.strictEqual(res, -2); + assert.strictEqual(hp.state, HeaderState.START); + res = hp.end(); + assert.strictEqual(res, 0); + assert.strictEqual(hp.state, HeaderState.END); + assert.deepEqual(hp.fields.type, SequenceType.FILEEND); + }); + it('FileEnd sequence - bytewise', () => { + const hp = new HeaderParser(); + const inp = fromBs('FileEnd'); + let res = -2; + let pos = 0; + while (res === -2 && pos < inp.length) { + res = hp.parse(new Uint32Array([inp[pos++]]), 0, 1); + } + assert.strictEqual(res, -2); + assert.strictEqual(hp.state, HeaderState.START); + res = hp.end(); + assert.strictEqual(res, 0); + assert.strictEqual(hp.state, HeaderState.END); + assert.deepEqual(hp.fields.type, SequenceType.FILEEND); + }); + it('ReportCellSize sequence', () => { + const hp = new HeaderParser(); + const inp = fromBs('ReportCellSize'); + let res = hp.parse(inp, 0, inp.length); + assert.strictEqual(res, -2); + assert.strictEqual(hp.state, HeaderState.START); + res = hp.end(); + assert.strictEqual(res, 0); + assert.strictEqual(hp.state, HeaderState.END); + assert.deepEqual(hp.fields, { type: SequenceType.REPORTCELLSIZE }); + }); + it('ReportCellSize sequence - bytewise', () => { + const hp = new HeaderParser(); + const inp = fromBs('ReportCellSize'); + let res = -2; + let pos = 0; + while (res === -2 && pos < inp.length) { + res = hp.parse(new Uint32Array([inp[pos++]]), 0, 1); + } + assert.strictEqual(res, -2); + assert.strictEqual(hp.state, HeaderState.START); + res = hp.end(); + assert.strictEqual(res, 0); + assert.strictEqual(hp.state, HeaderState.END); + assert.deepEqual(hp.fields, { type: SequenceType.REPORTCELLSIZE }); + }); }); diff --git a/addons/addon-image/src/IIPHeaderParser.ts b/addons/addon-image/src/IIPHeaderParser.ts index af4e9a68d..9c20262b1 100644 --- a/addons/addon-image/src/IIPHeaderParser.ts +++ b/addons/addon-image/src/IIPHeaderParser.ts @@ -6,9 +6,27 @@ // eslint-disable-next-line declare const Buffer: any; +export const enum HeaderState { + START = 0, + ABORT = 1, + KEY = 2, + VALUE = 3, + END = 4 +} + +export const enum SequenceType { + INVALID = 0, + FILE = 1, + MULTIPARTFILE = 2, + FILEPART = 3, + FILEEND = 4, + REPORTCELLSIZE = 5 +} export interface IHeaderFields { [key: string]: number | string | Uint32Array | null | undefined; + // sequence type + type: SequenceType; // base-64 encoded filename. Defaults to "Unnamed file". name: string; // File size in bytes. The file transfer will be canceled if this size is exceeded. @@ -29,14 +47,6 @@ export interface IHeaderFields { inline?: number; } -export const enum HeaderState { - START = 0, - ABORT = 1, - KEY = 2, - VALUE = 3, - END = 4 -} - // field value decoders // ASCII bytes to string @@ -92,7 +102,19 @@ const DECODERS: {[key: string]: (v: Uint32Array) => number | string} = { }; +// sequence type markers +// File const FILE_MARKER = [70, 105, 108, 101]; +// MultipartFile +const MULTIPARTFILE_MARKER = [77, 117, 108, 116, 105, 112, 97, 114, 116, 70, 105, 108, 101]; +// FilePart +const FILEPART_MARKER = [70, 105, 108, 101, 80, 97, 114, 116]; +// FileEnd +const FILEEND_MARKER = [70, 105, 108, 101, 69, 110, 100]; +// ReportCellSize +const REPORTCELLSIZE_MARKER = [82, 101, 112, 111, 114, 116, 67, 101, 108, 108, 83, 105, 122, 101]; + +// max allowed chars for sequence header const MAX_FIELDCHARS = 1024; @@ -111,12 +133,43 @@ export class HeaderParser { this._key = ''; } + public end(): number { + if (this.state === HeaderState.START) { + if (this._position === FILEEND_MARKER.length) { + for (let k = 0; k < FILEEND_MARKER.length; ++k) { + if (this._buffer[k] !== FILEEND_MARKER[k]) return this._a(); + } + this.fields['type'] = SequenceType.FILEEND; + this.state = HeaderState.END; + return 0; + } + if (this._position === REPORTCELLSIZE_MARKER.length) { + for (let k = 0; k < REPORTCELLSIZE_MARKER.length; ++k) { + if (this._buffer[k] !== REPORTCELLSIZE_MARKER[k]) return this._a(); + } + this.fields['type'] = SequenceType.REPORTCELLSIZE; + this.state = HeaderState.END; + return 0; + } + return this._a(); + } + if (this.state === HeaderState.END) return 0; + if (this.state === HeaderState.VALUE + && this.fields.type === SequenceType.MULTIPARTFILE + ) { + if (!this._storeValue(this._position)) return this._a(); + this.state = HeaderState.END; + return 0; + } + return this._a(); + } + public parse(data: Uint32Array, start: number, end: number): number { let state = this.state; let pos = this._position; const buffer = this._buffer; if (state === HeaderState.ABORT || state === HeaderState.END) return -1; - if (state === HeaderState.START && pos > 6) return -1; + if (state === HeaderState.START && pos > 14) return -1; for (let i = start; i < end; ++i) { const c = data[i]; switch (c) { @@ -127,8 +180,29 @@ export class HeaderParser { break; case 61: // = if (state === HeaderState.START) { - for (let k = 0; k < FILE_MARKER.length; ++k) { - if (buffer[k] !== FILE_MARKER[k]) return this._a(); + if (buffer[0] === 70) { + // 'File' or 'FilePart' + let k = 0; + for (; k < FILE_MARKER.length; ++k) { + if (buffer[k] !== FILE_MARKER[k]) return this._a(); + } + this.fields['type'] = SequenceType.FILE; + if (pos === FILEPART_MARKER.length) { + for (; k < FILEPART_MARKER.length; ++k) { + if (buffer[k] !== FILEPART_MARKER[k]) return this._a(); + } + this.fields['type'] = SequenceType.FILEPART; + this.state = HeaderState.END; + return i + 1; + } + } else if (buffer[0] === 77) { + // 'MultipartFile' + for (let k = 0; k < MULTIPARTFILE_MARKER.length; ++k) { + if (buffer[k] !== MULTIPARTFILE_MARKER[k]) return this._a(); + } + this.fields['type'] = SequenceType.MULTIPARTFILE; + } else { + return this._a(); } state = HeaderState.KEY; pos = 0; @@ -158,6 +232,7 @@ export class HeaderParser { } private _a(): number { + this.fields.type = SequenceType.INVALID; this.state = HeaderState.ABORT; return -1; } diff --git a/addons/addon-image/src/IIPImageStorage.ts b/addons/addon-image/src/IIPImageStorage.ts index 0da91607f..28037a897 100644 --- a/addons/addon-image/src/IIPImageStorage.ts +++ b/addons/addon-image/src/IIPImageStorage.ts @@ -3,6 +3,7 @@ * @license MIT */ +import { IAddImageOpts } from './Types'; import { ImageStorage } from './ImageStorage'; /** @@ -12,6 +13,7 @@ import { ImageStorage } from './ImageStorage'; * - Always uses scrolling mode (cursor advances with image) */ export class IIPImageStorage { + private _addImageOpts: IAddImageOpts = { scrolling: true, layer: 'top', zIndex: 0, cursorPos: 'iip' }; constructor( private readonly _storage: ImageStorage ) {} @@ -21,6 +23,6 @@ export class IIPImageStorage { * Always uses scrolling mode — cursor advances past the image. */ public addImage(img: HTMLCanvasElement | ImageBitmap): void { - this._storage.addImage(img, true); + this._storage.addImage(img, this._addImageOpts); } } diff --git a/addons/addon-image/src/IIPMetrics.test.ts b/addons/addon-image/src/IIPMetrics.test.ts index 9fa476bf6..cc381e5cb 100644 --- a/addons/addon-image/src/IIPMetrics.test.ts +++ b/addons/addon-image/src/IIPMetrics.test.ts @@ -30,7 +30,8 @@ const TEST_IMAGES: [string, IMetrics][] = [ ['iphone_hdr_YES.jpg', { mime: 'image/jpeg', width: 3264, height: 2448 }], ['nikon-e950.jpg', { mime: 'image/jpeg', width: 800, height: 600 }], ['agfa-makernotes.jpg', { mime: 'image/jpeg', width: 8, height: 8 }], - ['sony-alpha-6000.jpg', { mime: 'image/jpeg', width: 6000, height: 4000 }] + ['sony-alpha-6000.jpg', { mime: 'image/jpeg', width: 6000, height: 4000 }], + ['dice.qoi', { mime: 'image/qoi', width: 800, height: 600 }], ]; diff --git a/addons/addon-image/src/ImageAddon.ts b/addons/addon-image/src/ImageAddon.ts index 7e0f29d3f..8fd395431 100644 --- a/addons/addon-image/src/ImageAddon.ts +++ b/addons/addon-image/src/ImageAddon.ts @@ -137,11 +137,6 @@ export class ImageAddon implements ITerminalAddon, IImageApi { // enable size reports if (this._opts.enableSizeReports) { - // const windowOptions = terminal.getOption('windowOptions'); - // windowOptions.getWinSizePixels = true; - // windowOptions.getCellSizePixels = true; - // windowOptions.getWinSizeChars = true; - // terminal.setOption('windowOptions', windowOptions); const windowOps = terminal.options.windowOptions ?? {}; windowOps.getWinSizePixels = true; windowOps.getCellSizePixels = true; @@ -260,7 +255,7 @@ export class ImageAddon implements ITerminalAddon, IImageApi { } private _report(s: string): void { - this._terminal?._core.coreService.triggerDataEvent(s); + this._terminal?._core.input(s, false); } private _decset(params: (number | number[])[]): boolean { diff --git a/addons/addon-image/src/ImageRenderer.ts b/addons/addon-image/src/ImageRenderer.ts index b36cdd004..5854efaec 100644 --- a/addons/addon-image/src/ImageRenderer.ts +++ b/addons/addon-image/src/ImageRenderer.ts @@ -146,7 +146,7 @@ export class ImageRenderer extends Disposable implements IDisposable { public clearLines(start: number, end: number, layer?: ImageLayer): void { const y = start * (this.dimensions?.css.cell.height || 0); const w = this.dimensions?.css.canvas.width || 0; - const h = (++end - start) * (this.dimensions?.css.cell.height || 0); + const h = (end + 1 - start) * (this.dimensions?.css.cell.height || 0); if (!layer || layer === 'top') { this._layers.get('top')?.clearRect(0, y, w, h); } diff --git a/addons/addon-image/src/ImageStorage.ts b/addons/addon-image/src/ImageStorage.ts index e22c24753..ac91958da 100644 --- a/addons/addon-image/src/ImageStorage.ts +++ b/addons/addon-image/src/ImageStorage.ts @@ -5,12 +5,13 @@ import { IDisposable } from '@xterm/xterm'; import { ImageRenderer } from './ImageRenderer'; -import type { ITerminalExt, IImageAddonOptions, IImageSpec, ICellSize, ImageLayer } from './Types'; -import type { IBufferLine } from 'common/Types'; +import type { + ITerminalExt, IImageAddonOptions, IImageSpec, ICellSize, IAddImageOpts +} from './Types'; +import type { IBufferLine } from 'common/buffer/Types'; import { CellData } from 'common/buffer/CellData'; - // fallback default cell size export const CELL_SIZE_DEFAULT: ICellSize = { width: 7, @@ -158,13 +159,15 @@ export class ImageStorage implements IDisposable { /** * Method to add an image to the storage. * @param img - The image to add (canvas or bitmap). - * @param scrolling - When true, cursor advances with the image (lineFeed per row). - * When false, image is placed at (0,0) and cursor is restored (DECSET 80 / sixel origin mode). - * @param layer - Which canvas layer to render on ('top' or 'bottom'). - * @param zIndex - Z-index for image layering within the same layer. + * @param opts - Options for addImage: + * - scrolling: When true, cursor advances with the image. + * When false, image is placed at ORIGIN and cursor does not move. + * - layer: Which canvas layer to render on ('top' or 'bottom'). + * - zIndex: Z-index for image layering within the same layer. + * - cursorPos: 'vt340' for bottom-left, 'iip' for bottom.right. * @returns The internal image ID assigned to the stored image. */ - public addImage(img: HTMLCanvasElement | ImageBitmap, scrolling: boolean, layer: ImageLayer = 'top', zIndex: number = 0): number { + public addImage(img: HTMLCanvasElement | ImageBitmap, opts: IAddImageOpts): number { // never allow storage to exceed memory limit this._evictOldest(img.width * img.height); @@ -186,7 +189,7 @@ export class ImageStorage implements IDisposable { let offset = originX; let tileCount = 0; - if (!scrolling) { + if (!opts.scrolling) { buffer.x = 0; buffer.y = 0; offset = 0; @@ -200,7 +203,7 @@ export class ImageStorage implements IDisposable { this._writeToCell(line, offset + col, imageId, row * cols + col); tileCount++; } - if (scrolling) { + if (opts.scrolling) { if (row < rows - 1) this._terminal._core._inputHandler.lineFeed(); } else { if (++buffer.y >= termRows) break; @@ -210,8 +213,12 @@ export class ImageStorage implements IDisposable { this._terminal._core._inputHandler._dirtyRowTracker.markDirty(buffer.y); // cursor positioning modes - if (scrolling) { - buffer.x = offset; + if (opts.scrolling) { + if (opts.cursorPos === 'iip') { + buffer.x = Math.min(offset + cols, termCols); + } else { + buffer.x = offset; + } } else { buffer.x = originX; buffer.y = originY; @@ -254,8 +261,8 @@ export class ImageStorage implements IDisposable { marker: endMarker || undefined, tileCount, bufferType: this._terminal.buffer.active.type, - layer, - zIndex + layer: opts.layer, + zIndex: opts.zIndex }; // finally add the image @@ -349,8 +356,8 @@ export class ImageStorage implements IDisposable { const workCell = this._workCell; for (let col = 0; col < cols; ++col) { line.loadCell(col, workCell); - let e = workCell.hasExtendedAttrs() && workCell.extended.payload; - if (! (e instanceof ImageTileInfo)) { + const e = workCell.hasExtendedAttrs() && workCell.extended.payload; + if (!(e instanceof ImageTileInfo)) { continue; } const imageId = e.imageId; @@ -372,10 +379,9 @@ export class ImageStorage implements IDisposable { while (++col < cols) { line.loadCell(col, workCell); const nextE = workCell.hasExtendedAttrs() && workCell.extended.payload; - if (! (nextE instanceof ImageTileInfo) || !nextE || nextE.imageId !== imageId || nextE.tileId !== startTile + count) { + if (!(nextE instanceof ImageTileInfo) || !nextE || nextE.imageId !== imageId || nextE.tileId !== startTile + count) { break; } - e = nextE; count++; } col--; @@ -425,11 +431,11 @@ export class ImageStorage implements IDisposable { const oldCol = this._viewportMetrics.cols - 1; const workCell = this._workCell; for (let row = 0; row < rows; ++row) { - const line = buffer.lines.get(row) !; + const line = buffer.lines.get(row)!; line.loadCell(oldCol, workCell); if (workCell.hasExtendedAttrs()) { const e = workCell.extended.payload; - if (! (e instanceof ImageTileInfo)) { + if (!(e instanceof ImageTileInfo)) { continue; } const imageId = e.imageId; diff --git a/addons/addon-image/src/SixelHandler.ts b/addons/addon-image/src/SixelHandler.ts index 2f12fbe19..1af2d85bc 100644 --- a/addons/addon-image/src/SixelHandler.ts +++ b/addons/addon-image/src/SixelHandler.ts @@ -91,7 +91,7 @@ export class SixelHandler implements IDcsHandler, IResetHandler { const height = this._dec.height; // partial fix for https://github.com/jerch/xterm-addon-image/issues/37 - if (!width || ! height) { + if (!width || !height) { if (height) { this._storage.advanceCursor(height); } diff --git a/addons/addon-image/src/SixelImageStorage.ts b/addons/addon-image/src/SixelImageStorage.ts index 4c5f555bb..c2376a68a 100644 --- a/addons/addon-image/src/SixelImageStorage.ts +++ b/addons/addon-image/src/SixelImageStorage.ts @@ -4,7 +4,7 @@ */ import { ImageStorage, CELL_SIZE_DEFAULT } from './ImageStorage'; -import { IImageAddonOptions, ITerminalExt } from './Types'; +import { IImageAddonOptions, ITerminalExt, IAddImageOpts } from './Types'; import { ImageRenderer } from './ImageRenderer'; /** @@ -15,6 +15,7 @@ import { ImageRenderer } from './ImageRenderer'; * - advanceCursor for empty sixels carrying only height */ export class SixelImageStorage { + private _addImageOpts: IAddImageOpts = { scrolling: true, layer: 'top', zIndex: 0, cursorPos: 'vt340' }; constructor( private readonly _storage: ImageStorage, private readonly _opts: IImageAddonOptions, @@ -27,7 +28,8 @@ export class SixelImageStorage { * Cursor behavior depends on the sixelScrolling option (DECSET 80). */ public addImage(img: HTMLCanvasElement | ImageBitmap): void { - this._storage.addImage(img, this._opts.sixelScrolling); + this._addImageOpts.scrolling = this._opts.sixelScrolling; + this._storage.addImage(img, this._addImageOpts); } /** diff --git a/addons/addon-image/src/Types.ts b/addons/addon-image/src/Types.ts index 675c9fdd6..04328420c 100644 --- a/addons/addon-image/src/Types.ts +++ b/addons/addon-image/src/Types.ts @@ -87,6 +87,14 @@ export interface ICellSize { } export type ImageLayer = 'top' | 'bottom'; +export type CursorPos = 'vt340' | 'iip'; + +export interface IAddImageOpts { + scrolling: boolean; + layer: ImageLayer; + zIndex: number; + cursorPos: CursorPos; +} export interface IImageSpec { orig: HTMLCanvasElement | ImageBitmap | undefined; diff --git a/addons/addon-image/src/kitty/KittyGraphicsTypes.ts b/addons/addon-image/src/kitty/KittyGraphicsTypes.ts index 448ebcc05..4288dd0a4 100644 --- a/addons/addon-image/src/kitty/KittyGraphicsTypes.ts +++ b/addons/addon-image/src/kitty/KittyGraphicsTypes.ts @@ -168,7 +168,7 @@ export function parseKittyCommand(data: string): IKittyCommand { cmd.deleteSelector = value; continue; } - const numValue = parseInt(value); + const numValue = parseInt(value, 10); switch (key) { case KittyKey.FORMAT: cmd.format = numValue; break; case KittyKey.ID: cmd.id = numValue; break; diff --git a/addons/addon-image/src/kitty/KittyImageStorage.ts b/addons/addon-image/src/kitty/KittyImageStorage.ts index 95ea594c7..1f5c09ec9 100644 --- a/addons/addon-image/src/kitty/KittyImageStorage.ts +++ b/addons/addon-image/src/kitty/KittyImageStorage.ts @@ -5,7 +5,7 @@ import { IDisposable } from '@xterm/xterm'; import { ImageStorage } from '../ImageStorage'; -import { ImageLayer } from '../Types'; +import { ImageLayer, IAddImageOpts } from '../Types'; import { IKittyImageData } from './KittyGraphicsTypes'; // Kitty-specific image storage controller. @@ -42,6 +42,7 @@ export class KittyImageStorage implements IDisposable { this._images.delete(kittyId); } }; + private _addImageOpts: IAddImageOpts = { scrolling: true, layer: 'top', zIndex: 0, cursorPos: 'iip' }; constructor( private readonly _storage: ImageStorage @@ -98,7 +99,10 @@ export class KittyImageStorage implements IDisposable { if (oldStorageId !== undefined) { this._storageIdToKittyId.delete(oldStorageId); } - const storageId = this._storage.addImage(image, scrolling, layer, zIndex); + this._addImageOpts.scrolling = scrolling; + this._addImageOpts.layer = layer; + this._addImageOpts.zIndex = zIndex; + const storageId = this._storage.addImage(image, this._addImageOpts); this._kittyIdToStorageId.set(kittyId, storageId); this._storageIdToKittyId.set(storageId, kittyId); } diff --git a/addons/addon-image/test/ImageAddon.test.ts b/addons/addon-image/test/ImageAddon.test.ts index dc729ec63..f3cde06a8 100644 --- a/addons/addon-image/test/ImageAddon.test.ts +++ b/addons/addon-image/test/ImageAddon.test.ts @@ -290,6 +290,67 @@ test.describe('ImageAddon', () => { }); }); + test.describe('IIP support', () => { + test('size params is optional/informative', async () => { + // too small size param + await ctx.proxy.write(`\x1b]1337;File=inline=1;size=5:${PALETTE_PNG_BASE64}\x07`); + deepStrictEqual(await getOrigSize(1), [640, 80]); + // no size aparm at all + await ctx.proxy.write(`\x1b[10H\x1b]1337;File=inline=1:${PALETTE_QOI_BASE64}\x07`); + deepStrictEqual(await getOrigSize(2), [640, 80]); + }); + test.skip('FilePart support - bytewise', async () => { + // opener + await ctx.proxy.write(`\x1b]1337;MultipartFile=inline=1\x07`); + // byte-wise + for (let i = 0; i < PALETTE_PNG_BASE64.length; ++i) { + await ctx.proxy.write(`\x1b]1337;FilePart=${PALETTE_PNG_BASE64[i]}\x07`); + } + // finalizer + await ctx.proxy.write(`\x1b]1337;FileEnd\x07`); + deepStrictEqual(await getOrigSize(1), [640, 80]); + }); + test('FilePart support - chunks', async () => { + // opener + await ctx.proxy.write(`\x1b]1337;MultipartFile=inline=1\x07`); + // chunks + for (let i = 0; i < PALETTE_PNG_BASE64.length; i += 256) { + await ctx.proxy.write(`\x1b]1337;FilePart=${PALETTE_PNG_BASE64.slice(i, i + 256)}\x07`); + } + // finalizer + await ctx.proxy.write(`\x1b]1337;FileEnd\x07`); + deepStrictEqual(await getOrigSize(1), [640, 80]); + }); + test('FilePart support - edgecases', async () => { + // multiple opener do not harm + for (let i = 0; i < 10; ++i) { + await ctx.proxy.write(`\x1b]1337;MultipartFile=inline=1\x07`); + } + // multiple finalizer do not harm + for (let i = 0; i < 5; ++i) { + await ctx.proxy.write(`\x1b]1337;FileEnd\x07`); + } + // chunks w'o opener are ignored + for (let i = 0; i < PALETTE_PNG_BASE64.length; i += 256) { + await ctx.proxy.write(`\x1b]1337;FilePart=${PALETTE_PNG_BASE64.slice(i, i + 256)}\x07`); + } + await ctx.proxy.write(`\x1b]1337;FileEnd\x07`); + pollFor(ctx.page, 'window.imageAddon._storage._images.size', 0); + }); + test('FilePart support - other IIP sequence cancels chunked image', async () => { + // opener + await ctx.proxy.write(`\x1b]1337;MultipartFile=inline=1\x07`); + // chunks + for (let i = 0; i < PALETTE_PNG_BASE64.length; i += 256) { + await ctx.proxy.write(`\x1b]1337;FilePart=${PALETTE_PNG_BASE64.slice(i, i + 256)}\x07`); + } + // finalizer skipped + // write spinfox.png + await ctx.proxy.write(TESTDATA_IIP[1][0]); + deepStrictEqual(await getOrigSize(1), TESTDATA_IIP[1][1]); + }); + }); + test.describe('IIP support - testimages', () => { test('palette.png', async () => { await ctx.proxy.write(TESTDATA_IIP[0][0]); diff --git a/addons/addon-image/test/KittyGraphics.test.ts b/addons/addon-image/test/KittyGraphics.test.ts index a9b5d6845..a7c8e60c1 100644 --- a/addons/addon-image/test/KittyGraphics.test.ts +++ b/addons/addon-image/test/KittyGraphics.test.ts @@ -539,7 +539,6 @@ test.describe('Kitty Graphics Protocol', () => { test.describe('Query support (a=q)', () => { test('responds with OK for capability query without payload', async () => { - let response = ''; await ctx.page.evaluate(() => { (window as any).kittyResponse = ''; (window as any).term.onData((data: string) => { (window as any).kittyResponse = data; }); @@ -548,12 +547,11 @@ test.describe('Kitty Graphics Protocol', () => { await ctx.proxy.write('\x1b_Gi=31,a=q;\x1b\\'); await timeout(100); - response = await ctx.page.evaluate('window.kittyResponse'); + const response = await ctx.page.evaluate('window.kittyResponse'); strictEqual(response, '\x1b_Gi=31;OK\x1b\\'); }); test('responds with OK for valid PNG query', async () => { - let response = ''; await ctx.page.evaluate(() => { (window as any).kittyResponse = ''; (window as any).term.onData((data: string) => { (window as any).kittyResponse = data; }); @@ -562,7 +560,7 @@ test.describe('Kitty Graphics Protocol', () => { await ctx.proxy.write(`\x1b_Gi=42,a=q,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`); await timeout(100); - response = await ctx.page.evaluate('window.kittyResponse'); + const response = await ctx.page.evaluate('window.kittyResponse'); strictEqual(response, '\x1b_Gi=42;OK\x1b\\'); }); @@ -578,7 +576,6 @@ test.describe('Kitty Graphics Protocol', () => { }); test('responds with error for invalid base64', async () => { - let response = ''; await ctx.page.evaluate(() => { (window as any).kittyResponse = ''; (window as any).term.onData((data: string) => { (window as any).kittyResponse = data; }); @@ -587,12 +584,11 @@ test.describe('Kitty Graphics Protocol', () => { await ctx.proxy.write('\x1b_Gi=60,a=q,f=100;!!!invalid!!!\x1b\\'); await timeout(100); - response = await ctx.page.evaluate('window.kittyResponse'); + const response: string = await ctx.page.evaluate('window.kittyResponse'); strictEqual(response.startsWith('\x1b_Gi=60;EINVAL:'), true); }); test('responds with error for RGB data without dimensions', async () => { - let response = ''; await ctx.page.evaluate(() => { (window as any).kittyResponse = ''; (window as any).term.onData((data: string) => { (window as any).kittyResponse = data; }); @@ -601,7 +597,7 @@ test.describe('Kitty Graphics Protocol', () => { await ctx.proxy.write('\x1b_Gi=70,a=q,f=24;AAAA\x1b\\'); await timeout(100); - response = await ctx.page.evaluate('window.kittyResponse'); + const response = await ctx.page.evaluate('window.kittyResponse'); strictEqual(response, '\x1b_Gi=70;EINVAL:width and height required for raw pixel data\x1b\\'); }); @@ -642,7 +638,6 @@ test.describe('Kitty Graphics Protocol', () => { }); test('responds with EINVAL when both i and I keys are specified', async () => { - let response = ''; await ctx.page.evaluate(() => { (window as any).kittyResponse = ''; (window as any).term.onData((data: string) => { (window as any).kittyResponse = data; }); @@ -652,12 +647,11 @@ test.describe('Kitty Graphics Protocol', () => { await ctx.proxy.write(`\x1b_Gi=100,I=200,a=q,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`); await timeout(100); - response = await ctx.page.evaluate('window.kittyResponse'); + const response = await ctx.page.evaluate('window.kittyResponse'); strictEqual(response, '\x1b_Gi=100;EINVAL:cannot specify both i and I keys\x1b\\'); }); test('responds with EINVAL for i+I conflict even without payload', async () => { - let response = ''; await ctx.page.evaluate(() => { (window as any).kittyResponse = ''; (window as any).term.onData((data: string) => { (window as any).kittyResponse = data; }); @@ -667,7 +661,7 @@ test.describe('Kitty Graphics Protocol', () => { await ctx.proxy.write('\x1b_Gi=101,I=201,a=d\x1b\\'); await timeout(100); - response = await ctx.page.evaluate('window.kittyResponse'); + const response = await ctx.page.evaluate('window.kittyResponse'); strictEqual(response, '\x1b_Gi=101;EINVAL:cannot specify both i and I keys\x1b\\'); }); }); diff --git a/addons/addon-ligatures/package.json b/addons/addon-ligatures/package.json index fc7a433de..024ebaf4c 100644 --- a/addons/addon-ligatures/package.json +++ b/addons/addon-ligatures/package.json @@ -20,7 +20,7 @@ "package": "webpack", "pretest": "npm run build", "test": "nyc mocha out/**/*.test.js", - "prepublish": "npm run package" + "prepublishOnly": "npm run package" }, "keywords": [ "font", @@ -31,15 +31,11 @@ ], "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0", - "opentype.js": "^0.8.0" + "lru-cache": "^11.3.6", + "opentype.js": "^2.0.0" }, "devDependencies": { - "@types/lru-cache": "^5.1.0", - "@types/opentype.js": "^0.7.0", - "axios": "^1.15.0", - "font-finder": "^1.1.0", - "mkdirp": "0.5.5", - "yauzl": "^3.2.1" + "@types/opentype.js": "^1.3.9", + "font-finder": "^1.1.0" } } diff --git a/addons/addon-ligatures/src/fontLigatures/index.ts b/addons/addon-ligatures/src/fontLigatures/index.ts index d65e73bc4..d3a515c71 100644 --- a/addons/addon-ligatures/src/fontLigatures/index.ts +++ b/addons/addon-ligatures/src/fontLigatures/index.ts @@ -1,5 +1,5 @@ import * as opentype from 'opentype.js'; -import LRUCache = require('lru-cache'); +import { LRUCache } from 'lru-cache'; import { IFont, ILigatureData, IFlattenedLookupTree, ILookupTree, IOptions } from './types'; import mergeTrees from './merge'; @@ -23,8 +23,8 @@ class FontImpl implements IFont { if (options.cacheSize > 0) { this._cache = new LRUCache({ - max: options.cacheSize, - length: ((val: ILigatureData | [number, number][], key: string) => key.length) as any + maxSize: options.cacheSize, + sizeCalculation: ((val: ILigatureData | [number, number][], key: string) => key.length) as any }); } diff --git a/addons/addon-ligatures/src/fontLigatures/mergeRange.ts b/addons/addon-ligatures/src/fontLigatures/mergeRange.ts index ec5305083..5fcdf55cb 100644 --- a/addons/addon-ligatures/src/fontLigatures/mergeRange.ts +++ b/addons/addon-ligatures/src/fontLigatures/mergeRange.ts @@ -44,7 +44,6 @@ export default function mergeRange(ranges: [number, number][], newRangeStart: nu // current range ranges[i - 1][1] = Math.max(newRangeEnd, range[1]); ranges.splice(i, 1); - inRange = false; return ranges; } // Case 7: New range extends from previous range past the diff --git a/addons/addon-ligatures/src/index.ts b/addons/addon-ligatures/src/index.ts index fb8e85e73..2fc664f5b 100644 --- a/addons/addon-ligatures/src/index.ts +++ b/addons/addon-ligatures/src/index.ts @@ -21,7 +21,7 @@ const CACHE_SIZE = 100000; /** * Enable ligature support for the provided Terminal instance. To function - * properly, this must be called after `open()` is called on the therminal. If + * properly, this must be called after `open()` is called on the terminal. If * the font currently in use supports ligatures, the terminal will automatically * start to render them. * @param term Terminal instance from xterm.js diff --git a/addons/addon-progress/test/ProgressAddon.test.ts b/addons/addon-progress/test/ProgressAddon.test.ts index 792c0445d..12ff7a38f 100644 --- a/addons/addon-progress/test/ProgressAddon.test.ts +++ b/addons/addon-progress/test/ProgressAddon.test.ts @@ -9,15 +9,18 @@ import { ITestContext, createTestContext, openTerminal } from '../../../test/pla let ctx: ITestContext; -test.beforeAll(async ({ browser }) => { - ctx = await createTestContext(browser); - ctx.page.setViewportSize({ width: 1024, height: 768 }); - await openTerminal(ctx); -}); -test.afterAll(async () => await ctx.page.close()); - test.describe('ProgressAddon', () => { + test.describe.configure({ mode: 'serial' }); + + test.beforeAll(async ({ browser }) => { + ctx = await createTestContext(browser); + await openTerminal(ctx); + }); + test.afterAll(async () => { + await ctx?.page?.close(); + }); + test.beforeEach(async function(): Promise { await ctx.page.evaluate(` window.progressStack = []; diff --git a/addons/addon-search/src/DecorationManager.test.ts b/addons/addon-search/src/DecorationManager.test.ts new file mode 100644 index 000000000..26e40dbc2 --- /dev/null +++ b/addons/addon-search/src/DecorationManager.test.ts @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { DecorationManager } from './DecorationManager'; +import { SearchEngine } from './SearchEngine'; +import { SearchLineCache } from './SearchLineCache'; +import { Terminal } from 'browser/public/Terminal'; +import type { ISearchDecorationOptions } from '@xterm/addon-search'; +import type { IDecorationOptions } from '@xterm/xterm'; +import { DisposableStore } from 'common/Lifecycle'; + +function writeP(terminal: Terminal, data: string): Promise { + return new Promise(r => terminal.write(data, r)); +} + +describe('DecorationManager', () => { + let store: DisposableStore; + let terminal: Terminal; + let decorationManager: DecorationManager; + + beforeEach(() => { + store = new DisposableStore(); + terminal = store.add(new Terminal({ cols: 10, rows: 5 })); + decorationManager = store.add(new DecorationManager(terminal)); + }); + + it('should split highlight decorations for a wrapped match', async () => { + await writeP(terminal, '0123456789abcde'); + const searchEngine = new SearchEngine(terminal, store.add(new SearchLineCache(terminal))); + const match = searchEngine.find('9abc', 0, 0); + assert.ok(match); + + const decorationOptions: IDecorationOptions[] = []; + const registerDecoration = terminal.registerDecoration.bind(terminal); + terminal.registerDecoration = (options: IDecorationOptions) => { + decorationOptions.push(options); + return registerDecoration(options); + }; + + const options: ISearchDecorationOptions = { + matchOverviewRuler: '#ff0000', + activeMatchColorOverviewRuler: '#00ff00' + }; + decorationManager.createHighlightDecorations([match], options); + + assert.strictEqual(decorationOptions.length, 2); + assert.strictEqual(decorationOptions[0].x, 9); + assert.strictEqual(decorationOptions[0].width, 1); + assert.strictEqual(decorationOptions[1].x, 0); + assert.strictEqual(decorationOptions[1].width, 3); + + const withOverviewRuler = decorationOptions.filter(o => o.overviewRulerOptions !== undefined); + assert.strictEqual(withOverviewRuler.length, 2); + }); + + it('should only add one overview ruler marker per buffer line', async () => { + await writeP(terminal, 'abcdefghij'); + const decorationOptions: IDecorationOptions[] = []; + const registerDecoration = terminal.registerDecoration.bind(terminal); + terminal.registerDecoration = (options: IDecorationOptions) => { + decorationOptions.push(options); + return registerDecoration(options); + }; + + const options: ISearchDecorationOptions = { + matchOverviewRuler: '#ff0000', + activeMatchColorOverviewRuler: '#00ff00' + }; + decorationManager.createHighlightDecorations([ + { term: 'a', col: 0, row: 0, size: 1 }, + { term: 'f', col: 5, row: 0, size: 1 } + ], options); + + const withOverviewRuler = decorationOptions.filter(o => o.overviewRulerOptions !== undefined); + assert.strictEqual(withOverviewRuler.length, 1); + assert.strictEqual(withOverviewRuler[0].x, 0); + }); +}); diff --git a/addons/addon-search/src/SearchAddon.ts b/addons/addon-search/src/SearchAddon.ts index cb4094743..e5fd31cfb 100644 --- a/addons/addon-search/src/SearchAddon.ts +++ b/addons/addon-search/src/SearchAddon.ts @@ -142,12 +142,14 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp } prevResult = result; results.push(prevResult); - result = this._engine.find( - term, - prevResult.col + prevResult.term.length >= this._terminal.cols ? prevResult.row + 1 : prevResult.row, - prevResult.col + prevResult.term.length >= this._terminal.cols ? 0 : prevResult.col + 1, - searchOptions - ); + const cols = this._terminal.cols; + let nextCol = prevResult.col + prevResult.size; + let nextRow = prevResult.row; + if (nextCol >= cols) { + nextRow += Math.floor(nextCol / cols); + nextCol = nextCol % cols; + } + result = this._engine.find(term, nextRow, nextCol, searchOptions); } this._resultTracker.updateResults(results, this._highlightLimit); diff --git a/addons/addon-search/src/SearchEngine.ts b/addons/addon-search/src/SearchEngine.ts index b9991974d..1760bc2bd 100644 --- a/addons/addon-search/src/SearchEngine.ts +++ b/addons/addon-search/src/SearchEngine.ts @@ -60,7 +60,7 @@ export class SearchEngine { this._terminal.clearSelection(); return undefined; } - if (startCol > this._terminal.cols) { + if (startCol >= this._terminal.cols) { throw new Error(`Invalid col: ${startCol} to search in terminal of ${this._terminal.cols} cols`); } @@ -174,7 +174,7 @@ export class SearchEngine { this._terminal.clearSelection(); let startRow = this._terminal.buffer.active.baseY + this._terminal.rows - 1; - let startCol = this._terminal.cols; + const startCol = this._terminal.cols; const isReverseSearch = true; this._lineCache.initLinesCache(); @@ -186,14 +186,14 @@ export class SearchEngine { let result: ISearchResult | undefined; if (prevSelectedPos) { searchPosition.startRow = startRow = prevSelectedPos.start.y; - searchPosition.startCol = startCol = prevSelectedPos.start.x; + searchPosition.startCol = prevSelectedPos.start.x; if (cachedSearchTerm !== term) { // Try to expand selection to right first. result = this._findInLine(term, searchPosition, searchOptions, false); if (!result) { // If selection was not able to be expanded to the right, then try reverse search searchPosition.startRow = startRow = prevSelectedPos.end.y; - searchPosition.startCol = startCol = prevSelectedPos.end.x; + searchPosition.startCol = prevSelectedPos.end.x; } } } diff --git a/addons/addon-search/test/SearchAddon.test.ts b/addons/addon-search/test/SearchAddon.test.ts index a4ccb6c0e..4a62aca7f 100644 --- a/addons/addon-search/test/SearchAddon.test.ts +++ b/addons/addon-search/test/SearchAddon.test.ts @@ -414,10 +414,24 @@ test.describe('Search Tests', () => { }); test.describe('Regression tests', () => { + test('should advance highlight-all scan by buffer match size for wide characters', async () => { + await ctx.page.evaluate(` + window.calls = []; + window.search.onDidChangeResults(e => window.calls.push(e)); + `); + await ctx.proxy.resize(3, 5); + await ctx.proxy.write('𝄞𝄞𝄞'); + strictEqual(await ctx.page.evaluate(`window.search.findNext('𝄞', { decorations: { activeMatchColorOverviewRuler: '#ff0000', matchOverviewRuler: '#ffff00' } })`), true); + deepStrictEqual(await ctx.page.evaluate('window.calls'), [ + { resultCount: 3, resultIndex: 0 } + ]); + await ctx.proxy.resize(80, 24); + }); + test.describe('#2444 wrapped line content not being found', () => { let fixture: string; test.beforeAll(async () => { - fixture = (await new Promise(r => readFile(resolve(__dirname, '../fixtures/issue-2444'), (err, data) => r(data)))).toString(); + fixture = (await new Promise((res, rej) => readFile(resolve(__dirname, '../fixtures/issue-2444'), (err, data) => err ? rej(err) : res(data)))).toString(); if (process.platform !== 'win32') { fixture = fixture.replace(/\n/g, '\n\r'); } @@ -501,7 +515,7 @@ test.describe('Search Tests', () => { window.search.onDidChangeResults(e => window.calls.push(e)); `); // Move cursor forward 1 time to create a null character, as opposed to regular whitespace - await ctx.proxy.write('\\x1b[CHi Hi'); + await ctx.proxy.write('\x1b[CHi Hi'); strictEqual(await ctx.page.evaluate(`window.search.findPrevious('h', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true); deepStrictEqual(await ctx.page.evaluate('window.calls'), [ { resultCount: 2, resultIndex: 1 } diff --git a/addons/addon-serialize/benchmark/tsconfig.json b/addons/addon-serialize/benchmark/tsconfig.json index afc3944a2..ad7ee6d04 100644 --- a/addons/addon-serialize/benchmark/tsconfig.json +++ b/addons/addon-serialize/benchmark/tsconfig.json @@ -7,10 +7,10 @@ "rootDir": "..", "outDir": "../out-benchmark", "types": ["../../../node_modules/@types/node"], - "moduleResolution": "node", + "moduleResolution": "nodenext", "strict": false, "target": "es2021", - "module": "commonjs", + "module": "nodenext", "paths": { "common/*": ["../../../src/common/*"], "browser/*": ["../../../src/browser/*"], diff --git a/addons/addon-serialize/package.json b/addons/addon-serialize/package.json index 6fa91ffee..3258043ef 100644 --- a/addons/addon-serialize/package.json +++ b/addons/addon-serialize/package.json @@ -21,8 +21,8 @@ "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", "start": "node ../../demo/start", - "benchmark": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json", - "benchmark-baseline": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js", - "benchmark-eval": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js" + "benchmark": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json", + "benchmark-baseline": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js", + "benchmark-eval": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js" } } diff --git a/addons/addon-serialize/src/SerializeAddon.ts b/addons/addon-serialize/src/SerializeAddon.ts index 4980c8eda..e1728feb2 100644 --- a/addons/addon-serialize/src/SerializeAddon.ts +++ b/addons/addon-serialize/src/SerializeAddon.ts @@ -7,7 +7,8 @@ import type { IBuffer, IBufferCell, IBufferRange, ITerminalAddon, Terminal } from '@xterm/xterm'; import type { IHTMLSerializeOptions, SerializeAddon as ISerializeApi, ISerializeOptions, ISerializeRange } from '@xterm/addon-serialize'; -import { IAttributeData, IColor } from 'common/Types'; +import { IColor } from 'common/Types'; +import { IAttributeData } from 'common/buffer/Types'; import { DEFAULT_ANSI_COLORS } from 'browser/Types'; import { UnderlineStyle } from 'common/buffer/Constants'; @@ -172,7 +173,7 @@ class StringSerializeHandler extends BaseSerializeHandler { private _thisRowLastSecondChar: IBufferCell = this._buffer.getNullCell(); private _nextRowFirstChar: IBufferCell = this._buffer.getNullCell(); protected _rowEnd(row: number, isLastRow: boolean): void { - // if there is colorful empty cell at line end, whe must pad it back, or the the color block + // if there is colorful empty cell at line end, we must pad it back, or the color block // will missing if (this._nullCellCount > 0 && !equalBg(this._cursorStyle, this._backgroundCell)) { // use clear right to set background. @@ -220,7 +221,7 @@ class StringSerializeHandler extends BaseSerializeHandler { // you can't use control sequence to move cursor to (x === row) (thisRowLastChar.getChars() || thisRowLastChar.getWidth() === 0) && // change background of the first wrapped cell also affects BCE - // so we mark it as invalid to simply the process to determine line separator + // so we mark it as invalid to simplify the process to determine line separator equalBg(thisRowLastChar, nextRowFirstChar) ) { isValid = true; @@ -232,7 +233,7 @@ class StringSerializeHandler extends BaseSerializeHandler { isNextRowFirstCharDoubleWidth && (thisRowLastSecondChar.getChars() || thisRowLastSecondChar.getWidth() === 0) && // change background of the first wrapped cell also affects BCE - // so we mark it as invalid to simply the process to determine line separator + // so we mark it as invalid to simplify the process to determine line separator equalBg(thisRowLastChar, nextRowFirstChar) && equalBg(thisRowLastSecondChar, nextRowFirstChar) ) { diff --git a/addons/addon-serialize/test/SerializeAddon.test.ts b/addons/addon-serialize/test/SerializeAddon.test.ts index fb42d807d..c8dba3039 100644 --- a/addons/addon-serialize/test/SerializeAddon.test.ts +++ b/addons/addon-serialize/test/SerializeAddon.test.ts @@ -192,7 +192,7 @@ test.describe('SerializeAddon', () => { const cols = 10; const line = '+'.repeat(cols); const lines: string[] = [ - sgr(FG_P16_GREEN) + line, // Workaround: If we clear all flags a the end, serialize will use \x1b[0m to clear instead of the sepcific disable sequence + sgr(FG_P16_GREEN) + line, // Workaround: If we clear all flags at the end, serialize will use \x1b[0m to clear instead of the specific disable sequence sgr(INVERSE) + line, sgr(BOLD) + line, sgr(UNDERLINED) + line, diff --git a/addons/addon-unicode-graphemes/benchmark/tsconfig.json b/addons/addon-unicode-graphemes/benchmark/tsconfig.json index 47e6b53a4..1781ca318 100644 --- a/addons/addon-unicode-graphemes/benchmark/tsconfig.json +++ b/addons/addon-unicode-graphemes/benchmark/tsconfig.json @@ -4,10 +4,10 @@ "rootDir": "..", "outDir": "../out-benchmark", "types": ["../../../node_modules/@types/node"], - "moduleResolution": "node", + "moduleResolution": "nodenext", "strict": false, "target": "es2015", - "module": "commonjs", + "module": "nodenext", "paths": { "common/*": ["../../../src/common/*"], "browser/*": ["../../../src/browser/*"], diff --git a/addons/addon-unicode-graphemes/package.json b/addons/addon-unicode-graphemes/package.json index 640a61a7d..1848bebfc 100644 --- a/addons/addon-unicode-graphemes/package.json +++ b/addons/addon-unicode-graphemes/package.json @@ -21,8 +21,8 @@ "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", "start": "node ../../demo/start", - "benchmark": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json out-benchmark/benchmark/*benchmark.js", - "benchmark-baseline": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js", - "benchmark-eval": "NODE_PATH=../../out:./out:./out-benchmark/ ../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js" + "benchmark": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json out-benchmark/benchmark/*benchmark.js", + "benchmark-baseline": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --baseline out-benchmark/benchmark/*benchmark.js", + "benchmark-eval": "../../node_modules/.bin/xterm-benchmark -r 5 -c benchmark/benchmark.json --eval out-benchmark/benchmark/*benchmark.js" } } diff --git a/addons/addon-unicode-graphemes/src/UnicodeGraphemesAddon.ts b/addons/addon-unicode-graphemes/src/UnicodeGraphemesAddon.ts index 574a36cc8..09a073571 100644 --- a/addons/addon-unicode-graphemes/src/UnicodeGraphemesAddon.ts +++ b/addons/addon-unicode-graphemes/src/UnicodeGraphemesAddon.ts @@ -2,7 +2,7 @@ * Copyright (c) 2023 The xterm.js authors. All rights reserved. * @license MIT * - * UnicodeVersionProvider for V15 with grapeme cluster handleing. + * UnicodeVersionProvider for V15 with grapheme cluster handling. */ import type { Terminal, ITerminalAddon, IUnicodeHandling } from '@xterm/xterm'; diff --git a/addons/addon-web-fonts/test/WebFontsAddon.test.ts b/addons/addon-web-fonts/test/WebFontsAddon.test.ts index c94bff84d..ce5f7a446 100644 --- a/addons/addon-web-fonts/test/WebFontsAddon.test.ts +++ b/addons/addon-web-fonts/test/WebFontsAddon.test.ts @@ -78,7 +78,22 @@ test.describe('WebFontsAddon', () => { const data = await ctx.page.evaluate(` document.styleSheets[0].insertRule("@font-face {font-family: Kongtext; src: url(/fonts/kongtext.regular.ttf) format('truetype'); unicode-range: U+00A0-00FF}", 0); `); - deepStrictEqual(await getDocumentFonts(), [{ family: 'Kongtext', status: 'unloaded' }]); + let fonts = await getDocumentFonts(); + // safari may have loaded the font, firefox & chrome never load it + if (browser.browserType().name() === 'webkit') { + try { + deepStrictEqual(fonts, [{ family: 'Kongtext', status: 'loading' }]); + } catch (e) { + try { + deepStrictEqual(fonts, [{ family: 'Kongtext', status: 'loaded' }]); + } catch (e) { + deepStrictEqual(fonts, [{ family: 'Kongtext', status: 'unloaded' }]); + } + } + } else { + deepStrictEqual(fonts, [{ family: 'Kongtext', status: 'unloaded' }]); + } + // broken case: webfont in ctor without addon usage await ctx.page.evaluate(` @@ -86,15 +101,20 @@ test.describe('WebFontsAddon', () => { window.helperTerm.open(term.element); `); - // safari loads the font, firefox & chrome dont + fonts = await getDocumentFonts(); + // safari might load the font, firefox & chrome dont if (browser.browserType().name() === 'webkit') { try { - deepStrictEqual(await getDocumentFonts(), [{ family: 'Kongtext', status: 'loading' }]); + deepStrictEqual(fonts, [{ family: 'Kongtext', status: 'loading' }]); } catch (e) { - deepStrictEqual(await getDocumentFonts(), [{ family: 'Kongtext', status: 'loaded' }]); + try { + deepStrictEqual(fonts, [{ family: 'Kongtext', status: 'loaded' }]); + } catch (e) { + deepStrictEqual(fonts, [{ family: 'Kongtext', status: 'unloaded' }]); + } } } else { - deepStrictEqual(await getDocumentFonts(), [{ family: 'Kongtext', status: 'unloaded' }]); + deepStrictEqual(fonts, [{ family: 'Kongtext', status: 'unloaded' }]); } // good case: addon fixes layout for webfont in ctor diff --git a/addons/addon-web-fonts/test/tsconfig.json b/addons/addon-web-fonts/test/tsconfig.json index 4151488a8..59664e32b 100644 --- a/addons/addon-web-fonts/test/tsconfig.json +++ b/addons/addon-web-fonts/test/tsconfig.json @@ -5,7 +5,6 @@ "lib": [ "es2021", ], - // "downlevelIteration": true, "rootDir": ".", "outDir": "../out-test", "sourceMap": true, diff --git a/addons/addon-web-links/src/WebLinkProvider.ts b/addons/addon-web-links/src/WebLinkProvider.ts index efaead5c4..5df5d268a 100644 --- a/addons/addon-web-links/src/WebLinkProvider.ts +++ b/addons/addon-web-links/src/WebLinkProvider.ts @@ -57,7 +57,8 @@ function isUrl(urlString: string): boolean { export class LinkComputer { public static computeLink(y: number, regex: RegExp, terminal: Terminal, activate: (event: MouseEvent, uri: string) => void): ILink[] { - const rex = new RegExp(regex.source, (regex.flags || '') + 'g'); + const flags = regex.flags.includes('g') ? regex.flags : `${regex.flags}g`; + const rex = new RegExp(regex.source, flags); const [lines, startLineIndex] = LinkComputer._getWindowedLineStrings(y - 1, terminal); const line = lines.join(''); @@ -113,8 +114,8 @@ export class LinkComputer { let line: IBufferLine | undefined; let topIdx = lineIndex; let bottomIdx = lineIndex; - let length = 0; - let content = ''; + let length; + let content; const lines: string[] = []; if ((line = terminal.buffer.active.getLine(lineIndex))) { diff --git a/addons/addon-web-links/src/WebLinksAddon.ts b/addons/addon-web-links/src/WebLinksAddon.ts index 3328a3c3f..6ea1bc8d9 100644 --- a/addons/addon-web-links/src/WebLinksAddon.ts +++ b/addons/addon-web-links/src/WebLinksAddon.ts @@ -7,13 +7,13 @@ import type { Terminal, ITerminalAddon, IDisposable } from '@xterm/xterm'; import type { WebLinksAddon as IWebLinksApi } from '@xterm/addon-web-links'; import { ILinkProviderOptions, WebLinkProvider } from './WebLinkProvider'; -// consider everthing starting with http:// or https:// +// consider everything starting with http:// or https:// // up to first whitespace, `"` or `'` as url // NOTE: The repeated end clause is needed to not match a dangling `:` // resembling the old (...)*([^:"\'\\s]) final path clause // additionally exclude early + final: // - unsafe from rfc3986: !*'() -// - unsafe chars from rfc1738: {}|\^~[]` (minus [] as we need them for ipv6 adresses, also allow ~) +// - unsafe chars from rfc1738: {}|\^~[]` (minus [] for ipv6 addresses, also allow ~) // also exclude as finals: // - final interpunction like ,.!? // - any sort of brackets <>()[]{} (not spec conform, but often used to enclose urls) diff --git a/addons/addon-web-links/test/tsconfig.json b/addons/addon-web-links/test/tsconfig.json index 4151488a8..59664e32b 100644 --- a/addons/addon-web-links/test/tsconfig.json +++ b/addons/addon-web-links/test/tsconfig.json @@ -5,7 +5,6 @@ "lib": [ "es2021", ], - // "downlevelIteration": true, "rootDir": ".", "outDir": "../out-test", "sourceMap": true, diff --git a/addons/addon-webgl/README.md b/addons/addon-webgl/README.md index 9d89863f3..47a03b72e 100644 --- a/addons/addon-webgl/README.md +++ b/addons/addon-webgl/README.md @@ -23,7 +23,7 @@ See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/addon- ### Handling Context Loss -The browser may drop WebGL contexts for various reasons like OOM or after the system has been suspended. There is an API exposed that fires the `webglcontextlost` event fired on the canvas so embedders can handle it however they wish. An easy, but suboptimal way, to handle this is by disposing of WebglAddon when the event fires: +The browser may drop WebGL contexts for various reasons like OOM or after the system has been suspended. There is an API exposed that fires the `webglcontextlost` event on the canvas so embedders can handle it however they wish. An easy, but suboptimal way, to handle this is by disposing of WebglAddon when the event fires: ```ts const terminal = new Terminal(); diff --git a/addons/addon-webgl/src/CellColorResolver.ts b/addons/addon-webgl/src/CellColorResolver.ts index 3a4661cc3..49fdf5b1b 100644 --- a/addons/addon-webgl/src/CellColorResolver.ts +++ b/addons/addon-webgl/src/CellColorResolver.ts @@ -3,7 +3,7 @@ import { ICoreBrowserService, IThemeService } from 'browser/services/Services'; import { ReadonlyColorSet } from 'browser/Types'; import { Attributes, BgFlags, ExtFlags, FgFlags, NULL_CELL_CODE, UnderlineStyle } from 'common/buffer/Constants'; import { IDecorationService, IOptionsService } from 'common/services/Services'; -import { ICellData } from 'common/Types'; +import { ICellData } from 'common/buffer/Types'; import { Terminal } from '@xterm/xterm'; import { rgba } from 'common/Color'; import { treatGlyphAsBackgroundColor } from 'browser/renderer/shared/RendererUtils'; diff --git a/addons/addon-webgl/src/CharAtlasUtils.test.ts b/addons/addon-webgl/src/CharAtlasUtils.test.ts new file mode 100644 index 000000000..0a135746e --- /dev/null +++ b/addons/addon-webgl/src/CharAtlasUtils.test.ts @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { configEquals } from './CharAtlasUtils'; +import { ICharAtlasConfig } from './Types'; +import { NULL_COLOR } from 'common/Color'; +import { IColor } from 'common/Types'; + +function createTestConfig(overrides: Partial = {}): ICharAtlasConfig { + const color: IColor = { css: '#ffffff', rgba: 0xffffffff }; + const contrastCache = { + clear: () => {}, + setCss: () => {}, + getCss: () => undefined, + setColor: () => {}, + getColor: () => undefined + }; + const colors = { + foreground: color, + background: color, + cursor: NULL_COLOR, + cursorAccent: NULL_COLOR, + selectionForeground: undefined, + selectionBackgroundTransparent: NULL_COLOR, + selectionBackgroundOpaque: NULL_COLOR, + selectionInactiveBackgroundTransparent: NULL_COLOR, + selectionInactiveBackgroundOpaque: NULL_COLOR, + overviewRulerBorder: NULL_COLOR, + scrollbarSliderBackground: NULL_COLOR, + scrollbarSliderHoverBackground: NULL_COLOR, + scrollbarSliderActiveBackground: NULL_COLOR, + ansi: new Array(256).fill(color), + contrastCache, + halfContrastCache: contrastCache + }; + return { + customGlyphs: true, + devicePixelRatio: 1, + deviceMaxTextureSize: 4096, + letterSpacing: 0, + lineHeight: 1, + fontSize: 15, + fontFamily: 'monospace', + fontWeight: 'normal', + fontWeightBold: 'bold', + deviceCellWidth: 10, + deviceCellHeight: 20, + deviceCharWidth: 8, + deviceCharHeight: 16, + allowTransparency: false, + drawBoldTextInBrightColors: true, + minimumContrastRatio: 1, + colors, + ...overrides + }; +} + +describe('CharAtlasUtils', () => { + describe('configEquals', () => { + it('should return true for identical configs', () => { + const a = createTestConfig(); + const b = createTestConfig(); + assert.ok(configEquals(a, b)); + }); + + it('should return false when deviceMaxTextureSize differs', () => { + const a = createTestConfig(); + const b = createTestConfig({ deviceMaxTextureSize: 8192 }); + assert.ok(!configEquals(a, b)); + }); + + it('should return false when deviceCellWidth differs', () => { + const a = createTestConfig(); + const b = createTestConfig({ deviceCellWidth: 11 }); + assert.ok(!configEquals(a, b)); + }); + + it('should return false when deviceCellHeight differs', () => { + const a = createTestConfig(); + const b = createTestConfig({ deviceCellHeight: 21 }); + assert.ok(!configEquals(a, b)); + }); + }); +}); diff --git a/addons/addon-webgl/src/CharAtlasUtils.ts b/addons/addon-webgl/src/CharAtlasUtils.ts index 4ce103e98..d9ca69b39 100644 --- a/addons/addon-webgl/src/CharAtlasUtils.ts +++ b/addons/addon-webgl/src/CharAtlasUtils.ts @@ -59,6 +59,7 @@ export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean } } return a.devicePixelRatio === b.devicePixelRatio && + a.deviceMaxTextureSize === b.deviceMaxTextureSize && a.customGlyphs === b.customGlyphs && a.lineHeight === b.lineHeight && a.letterSpacing === b.letterSpacing && @@ -67,6 +68,8 @@ export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean a.fontWeight === b.fontWeight && a.fontWeightBold === b.fontWeightBold && a.allowTransparency === b.allowTransparency && + a.deviceCellWidth === b.deviceCellWidth && + a.deviceCellHeight === b.deviceCellHeight && a.deviceCharWidth === b.deviceCharWidth && a.deviceCharHeight === b.deviceCharHeight && a.drawBoldTextInBrightColors === b.drawBoldTextInBrightColors && diff --git a/addons/addon-webgl/src/GlyphRenderer.ts b/addons/addon-webgl/src/GlyphRenderer.ts index 46b8efeb9..be1990c2a 100644 --- a/addons/addon-webgl/src/GlyphRenderer.ts +++ b/addons/addon-webgl/src/GlyphRenderer.ts @@ -9,7 +9,7 @@ import { Disposable, toDisposable } from 'common/Lifecycle'; import { Terminal } from '@xterm/xterm'; import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject, type IRasterizedGlyph, type ITextureAtlas } from './Types'; import { createProgram, GLTexture, PROJECTION_MATRIX } from './WebglUtils'; -import type { IOptionsService } from 'common/services/Services'; +import type { ILogService, IOptionsService } from 'common/services/Services'; import { allowRescaling, throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; interface IVertices { @@ -114,7 +114,8 @@ export class GlyphRenderer extends Disposable { private readonly _terminal: Terminal, private readonly _gl: IWebGL2RenderingContext, private _dimensions: IRenderDimensions, - private readonly _optionsService: IOptionsService + private readonly _optionsService: IOptionsService, + private readonly _logService: ILogService ) { super(); @@ -127,7 +128,7 @@ export class GlyphRenderer extends Disposable { TextureAtlas.maxTextureSize = throwIfFalsy(gl.getParameter(gl.MAX_TEXTURE_SIZE) as number | null); } - this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, createFragmentShaderSource(TextureAtlas.maxAtlasPages))); + this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, createFragmentShaderSource(TextureAtlas.maxAtlasPages), this._logService)); this._register(toDisposable(() => gl.deleteProgram(this._program))); // Uniform locations @@ -136,8 +137,9 @@ export class GlyphRenderer extends Disposable { this._textureLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_texture')); // Create and set the vertex array object - this._vertexArrayObject = gl.createVertexArray(); - gl.bindVertexArray(this._vertexArrayObject); + const vertexArrayObject = this._vertexArrayObject = gl.createVertexArray(); + this._register(toDisposable(() => gl.deleteVertexArray(vertexArrayObject))); + gl.bindVertexArray(vertexArrayObject); // Setup a_unitquad, this defines the 4 vertices of a rectangle const unitQuadVertices = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]); @@ -218,7 +220,7 @@ export class GlyphRenderer extends Disposable { public updateCell(x: number, y: number, code: number, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void { // Since this function is called for every cell (`rows*cols`), it must be very optimized. It // should not instantiate any variables unless a new glyph is drawn to the cache where the - // slight slowdown is acceptable for the developer ergonomics provided as it's a once of for + // slight slowdown is acceptable for the developer ergonomics provided as it's a one-off for // each glyph. this._updateCell(this._vertices.attributes, x, y, code, bg, fg, ext, chars, width, lastBg); } @@ -387,8 +389,9 @@ export class GlyphRenderer extends Disposable { gl.bindTexture(gl.TEXTURE_2D, this._atlasTextures[i].texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, atlas.pages[i].canvas); - gl.generateMipmap(gl.TEXTURE_2D); this._atlasTextures[i].version = atlas.pages[i].version; } diff --git a/addons/addon-webgl/src/RectangleRenderer.ts b/addons/addon-webgl/src/RectangleRenderer.ts index 81e129e5c..eebfda3b3 100644 --- a/addons/addon-webgl/src/RectangleRenderer.ts +++ b/addons/addon-webgl/src/RectangleRenderer.ts @@ -14,6 +14,7 @@ import { RenderModelConstants } from './RenderModel'; import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject } from './Types'; import { createProgram, expandFloat32Array, PROJECTION_MATRIX } from './WebglUtils'; import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; +import type { ILogService } from 'common/services/Services'; const enum VertexAttribLocations { POSITION = 0, @@ -89,21 +90,23 @@ export class RectangleRenderer extends Disposable { private _terminal: Terminal, private _gl: IWebGL2RenderingContext, private _dimensions: IRenderDimensions, - private readonly _themeService: IThemeService + private readonly _themeService: IThemeService, + private readonly _logService: ILogService ) { super(); const gl = this._gl; - this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, fragmentShaderSource)); + this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, fragmentShaderSource, this._logService)); this._register(toDisposable(() => gl.deleteProgram(this._program))); // Uniform locations this._projectionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_projection')); // Create and set the vertex array object - this._vertexArrayObject = gl.createVertexArray(); - gl.bindVertexArray(this._vertexArrayObject); + const vertexArrayObject = this._vertexArrayObject = gl.createVertexArray(); + this._register(toDisposable(() => gl.deleteVertexArray(vertexArrayObject))); + gl.bindVertexArray(vertexArrayObject); // Setup a_unitquad, this defines the 4 vertices of a rectangle const unitQuadVertices = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]); diff --git a/addons/addon-webgl/src/TextureAtlas.ts b/addons/addon-webgl/src/TextureAtlas.ts index 34188235c..1c3e08a1c 100644 --- a/addons/addon-webgl/src/TextureAtlas.ts +++ b/addons/addon-webgl/src/TextureAtlas.ts @@ -69,7 +69,7 @@ export class TextureAtlas implements ITextureAtlas { private _overflowSizePage: AtlasPage | undefined; private _tmpCanvas: HTMLCanvasElement; - // A temporary context that glyphs are drawn to before being transfered to the atlas. + // A temporary context that glyphs are drawn to before being transferred to the atlas. private _tmpCtx: CanvasRenderingContext2D; private _workBoundingBox: IBoundingBox = { top: 0, left: 0, bottom: 0, right: 0 }; @@ -109,6 +109,7 @@ export class TextureAtlas implements ITextureAtlas { page.canvas.remove(); } this._onAddTextureAtlasCanvas.dispose(); + this._onRemoveTextureAtlasCanvas.dispose(); } public warmUp(): void { @@ -151,7 +152,7 @@ export class TextureAtlas implements ITextureAtlas { } private _createNewPage(): AtlasPage { - // Try merge the set of the 4 most used pages of the largest size. This is is deferred to a + // Try merge the set of the 4 most used pages of the largest size. This is deferred to a // microtask to ensure it does not interrupt textures that will be rendered in the current // animation frame which would result in blank rendered areas. This is actually not that // expensive relative to drawing the glyphs, so there is no need to wait for an idle callback. @@ -190,7 +191,7 @@ export class TextureAtlas implements ITextureAtlas { return newPage; } - const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a > b ? 1 : -1); + const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a - b); const mergedPageIndex = this.pages.length - mergingPages.length; // Merge into the new page @@ -529,7 +530,7 @@ export class TextureAtlas implements ITextureAtlas { let customGlyph = false; if (this._config.customGlyphs !== false) { const variantOffset = this._workAttributeData.getUnderlineVariantOffset(); - customGlyph = tryDrawCustomGlyph(this._tmpCtx, chars, padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight, this._config.deviceCharWidth, this._config.deviceCharHeight, this._config.fontSize, this._config.devicePixelRatio, backgroundColor.css, variantOffset); + customGlyph = tryDrawCustomGlyph(this._tmpCtx, chars, padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight, this._config.deviceCharWidth, this._config.deviceCharHeight, this._config.fontSize, this._config.devicePixelRatio, this._logService, backgroundColor.css, variantOffset); } // Whether to clear pixels based on a threshold difference between the glyph color and the @@ -1079,17 +1080,33 @@ class AtlasPage { size: number, sourcePages?: AtlasPage[] ) { - if (sourcePages) { - for (const p of sourcePages) { - this._glyphs.push(...p.glyphs); - this._usedPixels += p._usedPixels; - } - } this.canvas = createCanvas(document, size, size); // The canvas needs alpha because we use clearColor to convert the background color to alpha. // It might also contain some characters with transparent backgrounds if allowTransparency is // set. this.ctx = throwIfFalsy(this.canvas.getContext('2d', { alpha: true })); + if (sourcePages) { + if (sourcePages.length === 4) { + // optimized for quadmerge + this._glyphs = this._glyphs.concat( + sourcePages[0].glyphs, + sourcePages[1].glyphs, + sourcePages[2].glyphs, + sourcePages[3].glyphs + ); + this._usedPixels = sourcePages[0]._usedPixels + + sourcePages[1]._usedPixels + + sourcePages[2]._usedPixels + + sourcePages[3]._usedPixels; + } else { + // fallback for non quadmerges (should never be used) + for (let i = 0; i < sourcePages.length; ++i) { + this._glyphs = this._glyphs.concat(sourcePages[i].glyphs); + this._usedPixels += sourcePages[i]._usedPixels; + } + + } + } } public clear(): void { @@ -1124,7 +1141,7 @@ function clearColor(imageData: ImageData, bg: IColor, fg: IColor, enableThreshol // were covered (fg=#8ae234, bg=#c4a000). const threshold = Math.floor((Math.abs(r - fgR) + Math.abs(g - fgG) + Math.abs(b - fgB)) / 12); - // Set alpha channel of relevent pixels to 0 + // Set alpha channel of relevant pixels to 0 let isEmpty = true; for (let offset = 0; offset < imageData.data.length; offset += 4) { // Check exact match diff --git a/addons/addon-webgl/src/Types.ts b/addons/addon-webgl/src/Types.ts index 67c9408d6..294582e37 100644 --- a/addons/addon-webgl/src/Types.ts +++ b/addons/addon-webgl/src/Types.ts @@ -28,6 +28,7 @@ export interface ICursorRenderModel { export interface IWebGL2RenderingContext extends WebGLRenderingContext { vertexAttribDivisor(index: number, divisor: number): void; createVertexArray(): IWebGLVertexArrayObject; + deleteVertexArray(vao: IWebGLVertexArrayObject): void; bindVertexArray(vao: IWebGLVertexArrayObject): void; drawElementsInstanced(mode: number, count: number, type: number, offset: number, instanceCount: number): void; } diff --git a/addons/addon-webgl/src/WebglAddon.ts b/addons/addon-webgl/src/WebglAddon.ts index f21fb704e..f61206b13 100644 --- a/addons/addon-webgl/src/WebglAddon.ts +++ b/addons/addon-webgl/src/WebglAddon.ts @@ -9,7 +9,7 @@ import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IRender import { ITerminal } from 'browser/Types'; import { Disposable, toDisposable } from 'common/Lifecycle'; import { getSafariVersion, isSafari } from 'common/Platform'; -import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services'; +import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services'; import { IWebGL2RenderingContext } from './Types'; import { WebglRenderer } from './WebglRenderer'; import { Emitter, EventUtils } from 'common/Event'; @@ -40,7 +40,7 @@ export class WebglAddon extends Disposable implements ITerminalAddon, IWebglApi }; const gl = document.createElement('canvas').getContext('webgl2', contextAttributes) as IWebGL2RenderingContext; if (!gl) { - throw new Error('Webgl2 is only supported on Safari 16 and above'); + throw new Error('WebGL2 is only supported on Safari 16 and above'); } } super(); @@ -65,6 +65,7 @@ export class WebglAddon extends Disposable implements ITerminalAddon, IWebglApi const charSizeService: ICharSizeService = unsafeCore._charSizeService; const coreBrowserService: ICoreBrowserService = unsafeCore._coreBrowserService; const decorationService: IDecorationService = unsafeCore._decorationService; + const logService: ILogService = unsafeCore._logService; const themeService: IThemeService = unsafeCore._themeService; this._renderer = this._register(new WebglRenderer( @@ -74,6 +75,7 @@ export class WebglAddon extends Disposable implements ITerminalAddon, IWebglApi coreBrowserService, coreService, decorationService, + logService, optionsService, themeService, this._customGlyphs, diff --git a/addons/addon-webgl/src/WebglRenderer.ts b/addons/addon-webgl/src/WebglRenderer.ts index 500308bd1..a951efba5 100644 --- a/addons/addon-webgl/src/WebglRenderer.ts +++ b/addons/addon-webgl/src/WebglRenderer.ts @@ -10,12 +10,12 @@ import { CursorBlinkStateManager } from './CursorBlinkStateManager'; import { observeDevicePixelDimensions } from './DevicePixelObserver'; import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types'; import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; -import { CharData, IBufferLine, ICellData } from 'common/Types'; +import { CharData, IBufferLine, ICellData } from 'common/buffer/Types'; import { AttributeData } from 'common/buffer/AttributeData'; import { CellData } from 'common/buffer/CellData'; import { Attributes, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants'; import { TextBlinkStateManager } from 'browser/renderer/shared/TextBlinkStateManager'; -import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services'; +import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services'; import { Terminal } from '@xterm/xterm'; import { GlyphRenderer } from './GlyphRenderer'; import { RectangleRenderer } from './RectangleRenderer'; @@ -77,6 +77,7 @@ export class WebglRenderer extends Disposable implements IRenderer { private readonly _coreBrowserService: ICoreBrowserService, private readonly _coreService: ICoreService, private readonly _decorationService: IDecorationService, + private readonly _logService: ILogService, private readonly _optionsService: IOptionsService, private readonly _themeService: IThemeService, private readonly _customGlyphs: boolean = true, @@ -122,19 +123,19 @@ export class WebglRenderer extends Disposable implements IRenderer { this._deviceMaxTextureSize = this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE); this._register(addDisposableListener(this._canvas, 'webglcontextlost', (e) => { - console.log('webglcontextlost event received'); + this._logService.debug('webglcontextlost event received'); // Prevent the default behavior in order to enable WebGL context restoration. e.preventDefault(); // Wait a few seconds to see if the 'webglcontextrestored' event is fired. // If not, dispatch the onContextLoss notification to observers. this._contextRestorationTimeout = setTimeout(() => { this._contextRestorationTimeout = undefined; - console.warn('webgl context not restored; firing onContextLoss'); + this._logService.warn('webgl context not restored; firing onContextLoss'); this._onContextLoss.fire(e); }, 3000 /* ms */); })); this._register(addDisposableListener(this._canvas, 'webglcontextrestored', (e) => { - console.warn('webglcontextrestored event received'); + this._logService.warn('webglcontextrestored event received'); clearTimeout(this._contextRestorationTimeout); this._contextRestorationTimeout = undefined; // The texture atlas and glyph renderer must be fully reinitialized @@ -158,6 +159,8 @@ export class WebglRenderer extends Disposable implements IRenderer { this._isAttached = this._core.screenElement!.isConnected; this._register(toDisposable(() => { + clearTimeout(this._contextRestorationTimeout); + this._contextRestorationTimeout = undefined; for (const l of this._renderLayers) { l.dispose(); } @@ -274,8 +277,8 @@ export class WebglRenderer extends Disposable implements IRenderer { * Initializes members dependent on WebGL context state. */ private _initializeWebGLState(): [RectangleRenderer, GlyphRenderer] { - this._rectangleRenderer.value = new RectangleRenderer(this._terminal, this._gl, this.dimensions, this._themeService); - this._glyphRenderer.value = new GlyphRenderer(this._terminal, this._gl, this.dimensions, this._optionsService); + this._rectangleRenderer.value = new RectangleRenderer(this._terminal, this._gl, this.dimensions, this._themeService, this._logService); + this._glyphRenderer.value = new GlyphRenderer(this._terminal, this._gl, this.dimensions, this._optionsService, this._logService); // Update dimensions and acquire char atlas this.handleCharSizeChanged(); @@ -424,8 +427,8 @@ export class WebglRenderer extends Disposable implements IRenderer { let line: IBufferLine; let joinedRanges: [number, number][]; let isJoined: boolean; - let skipJoinedCheckUntilX: number = 0; - let isValidJoinRange: boolean = true; + let skipJoinedCheckUntilX: number; + let isValidJoinRange: boolean; let lastCharX: number; let range: [number, number]; let isCursorRow: boolean; @@ -453,7 +456,18 @@ export class WebglRenderer extends Disposable implements IRenderer { for (y = start; y <= end; y++) { row = y + terminal.buffer.ydisp; - line = terminal.buffer.lines.get(row)!; + const bufferLine = terminal.buffer.lines.get(row); + if (!bufferLine) { + this._model.lineLengths[y] = 0; + for (x = 0; x < terminal.cols; x++) { + j = ((y * terminal.cols) + x) * RenderModelConstants.INDICIES_PER_CELL; + modelUpdated = true; + this._nullModelCell(x, y, j, 0, 0, 0); + } + this._setRowBlinkState(y, false); + continue; + } + line = bufferLine; let rowHasBlinkingCells = false; this._model.lineLengths[y] = 0; isCursorRow = cursorY === row; @@ -584,13 +598,9 @@ export class WebglRenderer extends Disposable implements IRenderer { // Null out non-first cells for (x++; x <= lastCharX; x++) { j = ((y * terminal.cols) + x) * RenderModelConstants.INDICIES_PER_CELL; - this._glyphRenderer.value!.updateCell(x, y, NULL_CELL_CODE, 0, 0, 0, NULL_CELL_CHAR, 0, 0); - this._model.cells[j] = NULL_CELL_CODE; // Don't re-resolve the cell color since multi-colored ligature backgrounds are not // supported - this._model.cells[j + RenderModelConstants.BG_OFFSET] = this._cellColorResolver.result.bg; - this._model.cells[j + RenderModelConstants.FG_OFFSET] = this._cellColorResolver.result.fg; - this._model.cells[j + RenderModelConstants.EXT_OFFSET] = this._cellColorResolver.result.ext; + this._nullModelCell(x, y, j, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext); } x--; // Go back to the previous update cell for next iteration } @@ -604,6 +614,14 @@ export class WebglRenderer extends Disposable implements IRenderer { this._updateTextBlinkState(); } + private _nullModelCell(x: number, y: number, cellIndex: number, bg: number, fg: number, ext: number): void { + this._glyphRenderer.value!.updateCell(x, y, NULL_CELL_CODE, bg, fg, ext, NULL_CELL_CHAR, 0, 0); + this._model.cells[cellIndex] = NULL_CELL_CODE; + this._model.cells[cellIndex + RenderModelConstants.BG_OFFSET] = bg; + this._model.cells[cellIndex + RenderModelConstants.FG_OFFSET] = fg; + this._model.cells[cellIndex + RenderModelConstants.EXT_OFFSET] = ext; + } + private _resetBlinkingRowState(): void { this._rowHasBlinkingCells = new Array(this._terminal.rows).fill(false); this._rowHasBlinkingCellsCount = 0; @@ -661,10 +679,10 @@ export class WebglRenderer extends Disposable implements IRenderer { this.dimensions.device.canvas.height = this._terminal.rows * this.dimensions.device.cell.height; this.dimensions.device.canvas.width = this._terminal.cols * this.dimensions.device.cell.width; - // The the size of the canvas on the page. It's important that this rounds to nearest integer + // The size of the canvas on the page. It's important that this rounds to nearest integer // and not ceils as browsers often have floating point precision issues where // `window.devicePixelRatio` ends up being something like `1.100000023841858` for example, when - // it's actually 1.1. Ceiling may causes blurriness as the backing canvas image is 1 pixel too + // it's actually 1.1. Ceiling may cause blurriness as the backing canvas image is 1 pixel too // large for the canvas element size. this.dimensions.css.canvas.height = Math.round(this.dimensions.device.canvas.height / this._devicePixelRatio); this.dimensions.css.canvas.width = Math.round(this.dimensions.device.canvas.width / this._devicePixelRatio); diff --git a/addons/addon-webgl/src/WebglUtils.ts b/addons/addon-webgl/src/WebglUtils.ts index da765c802..9944c6bd3 100644 --- a/addons/addon-webgl/src/WebglUtils.ts +++ b/addons/addon-webgl/src/WebglUtils.ts @@ -4,6 +4,7 @@ */ import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; +import type { ILogService } from 'common/services/Services'; /** * A matrix that when multiplies will translate 0-1 coordinates (left to right, @@ -16,21 +17,21 @@ export const PROJECTION_MATRIX = new Float32Array([ -1, 1, 0, 1 ]); -export function createProgram(gl: WebGLRenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram | undefined { +export function createProgram(gl: WebGLRenderingContext, vertexSource: string, fragmentSource: string, logService: ILogService): WebGLProgram | undefined { const program = throwIfFalsy(gl.createProgram()); - gl.attachShader(program, throwIfFalsy(createShader(gl, gl.VERTEX_SHADER, vertexSource))); - gl.attachShader(program, throwIfFalsy(createShader(gl, gl.FRAGMENT_SHADER, fragmentSource))); + gl.attachShader(program, throwIfFalsy(createShader(gl, gl.VERTEX_SHADER, vertexSource, logService))); + gl.attachShader(program, throwIfFalsy(createShader(gl, gl.FRAGMENT_SHADER, fragmentSource, logService))); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } - console.error(gl.getProgramInfoLog(program)); + logService.error(gl.getProgramInfoLog(program)); gl.deleteProgram(program); } -export function createShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader | undefined { +export function createShader(gl: WebGLRenderingContext, type: number, source: string, logService: ILogService): WebGLShader | undefined { const shader = throwIfFalsy(gl.createShader(type)); gl.shaderSource(shader, source); gl.compileShader(shader); @@ -39,7 +40,7 @@ export function createShader(gl: WebGLRenderingContext, type: number, source: st return shader; } - console.error(gl.getShaderInfoLog(shader)); + logService.error(gl.getShaderInfoLog(shader)); gl.deleteShader(shader); } diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts index c35299809..cf8dd2493 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts @@ -5,7 +5,7 @@ import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphCharacterDefinition, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition } from './Types'; -/* eslint-disable max-len */ +/* oxlint-disable @stylistic/max-len -- generated glyph path data */ const enum Shapes { /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts index ba8925727..137cca7e3 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts @@ -4,6 +4,7 @@ */ import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; +import type { ILogService } from 'common/services/Services'; import { customGlyphDefinitions } from './CustomGlyphDefinitions'; import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition, type CustomGlyphPatternDefinition, type ICustomGlyphSolidOctantBlockVector, type ICustomGlyphVectorShape } from './Types'; @@ -22,6 +23,7 @@ export function tryDrawCustomGlyph( deviceCharHeight: number, fontSize: number, devicePixelRatio: number, + logService: ILogService, backgroundColor?: string, variantOffset: number = 0 ): boolean { @@ -30,7 +32,7 @@ export function tryDrawCustomGlyph( // Normalize to array for uniform handling const parts = Array.isArray(unifiedCharDefinition) ? unifiedCharDefinition : [unifiedCharDefinition]; for (const part of parts) { - drawDefinitionPart(ctx, part, xOffset, yOffset, deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, fontSize, devicePixelRatio, backgroundColor, variantOffset); + drawDefinitionPart(ctx, part, xOffset, yOffset, deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, fontSize, devicePixelRatio, logService, backgroundColor, variantOffset); } return true; } @@ -49,6 +51,7 @@ function drawDefinitionPart( deviceCharHeight: number, fontSize: number, devicePixelRatio: number, + logService: ILogService, backgroundColor?: string, variantOffset: number = 0 ): void { @@ -79,7 +82,7 @@ function drawDefinitionPart( drawPatternChar(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, variantOffset); break; case CustomGlyphDefinitionType.PATH_FUNCTION: - drawPathFunctionCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, devicePixelRatio, part.strokeWidth); + drawPathFunctionCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, devicePixelRatio, logService, part.strokeWidth); break; case CustomGlyphDefinitionType.PATH: drawPathDefinitionCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, devicePixelRatio, part.strokeWidth); @@ -88,7 +91,7 @@ function drawDefinitionPart( drawPathNegativeDefinitionCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, devicePixelRatio, backgroundColor); break; case CustomGlyphDefinitionType.VECTOR_SHAPE: - drawVectorShape(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, fontSize, devicePixelRatio); + drawVectorShape(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, fontSize, devicePixelRatio, logService); break; case CustomGlyphDefinitionType.BRAILLE: drawBrailleCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight); @@ -218,8 +221,8 @@ function drawPathDefinitionCharacter( const rx = parseFloat(args[0]) * deviceCellWidth; const ry = parseFloat(args[1]) * deviceCellHeight; const xAxisRotation = parseFloat(args[2]) * Math.PI / 180; - const largeArcFlag = parseInt(args[3]); - const sweepFlag = parseInt(args[4]); + const largeArcFlag = parseInt(args[3], 10); + const sweepFlag = parseInt(args[4], 10); const x = xOffset + parseFloat(args[5]) * deviceCellWidth; const y = yOffset + parseFloat(args[6]) * deviceCellHeight; drawSvgArc(ctx, currentX, currentY, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y); @@ -510,6 +513,7 @@ function drawPathFunctionCharacter( deviceCellWidth: number, deviceCellHeight: number, devicePixelRatio: number, + logService: ILogService, strokeWidth?: number ): void { ctx.save(); @@ -536,7 +540,7 @@ function drawPathFunctionCharacter( } const f = svgToCanvasInstructionMap[type]; if (!f) { - console.error(`Could not find drawing instructions for "${type}"`); + logService.error(`Could not find drawing instructions for "${type}"`); continue; } const args: string[] = instruction.substring(1).split(','); @@ -598,7 +602,8 @@ function drawVectorShape( deviceCellWidth: number, deviceCellHeight: number, fontSize: number, - devicePixelRatio: number + devicePixelRatio: number, + logService: ILogService ): void { // Clip the cell to make sure drawing doesn't occur beyond bounds const clipRegion = new Path2D(); @@ -619,7 +624,7 @@ function drawVectorShape( } const f = svgToCanvasInstructionMap[type]; if (!f) { - console.error(`Could not find drawing instructions for "${type}"`); + logService.error(`Could not find drawing instructions for "${type}"`); continue; } const args: string[] = instruction.substring(1).split(','); diff --git a/addons/addon-webgl/src/tsconfig.json b/addons/addon-webgl/src/tsconfig.json index aeb42a1bf..7035daa86 100644 --- a/addons/addon-webgl/src/tsconfig.json +++ b/addons/addon-webgl/src/tsconfig.json @@ -25,7 +25,6 @@ ] }, "strict": true, - "downlevelIteration": true, "experimentalDecorators": true, "types": [ "../../../node_modules/@types/mocha" diff --git a/addons/addon-webgl/typings/addon-webgl.d.ts b/addons/addon-webgl/typings/addon-webgl.d.ts index 37b6b8a95..37acbb8a9 100644 --- a/addons/addon-webgl/typings/addon-webgl.d.ts +++ b/addons/addon-webgl/typings/addon-webgl.d.ts @@ -23,12 +23,12 @@ declare module '@xterm/addon-webgl' { public readonly onChangeTextureAtlas: IEvent; /** - * An event that is fired when the a new page is added to the texture atlas. + * An event that is fired when a new page is added to the texture atlas. */ public readonly onAddTextureAtlasCanvas: IEvent; /** - * An event that is fired when the a page is removed from the texture atlas. + * An event that is fired when a page is removed from the texture atlas. */ public readonly onRemoveTextureAtlasCanvas: IEvent; diff --git a/bin/esbuild_all.mjs b/bin/esbuild_all.mjs index 1a3aadea5..789cb5df0 100644 --- a/bin/esbuild_all.mjs +++ b/bin/esbuild_all.mjs @@ -19,14 +19,17 @@ for (const addon of addons) { // Demo job - This requires the others to be built so it's not included when building all // jobs.push(createJob('demo-client', [`--demo-client`])); -await Promise.all(jobs.map((job, i) => { +const codes = await Promise.all(jobs.map(job => { return new Promise(r => { job.cp.on('exit', code => { log(`Finished \x1b[32m${job.name}\x1b[0m${code ? ' \x1b[31mwith errors\x1b[0m' : ''}`); - r(code); + r(code ?? 1); }); }); })); +if (codes.some(code => code !== 0)) { + process.exit(1); +} /** * @param {string} message diff --git a/bin/lint_changes.js b/bin/lint_changes.js index 6ed7ae5fa..b7571c5e3 100644 --- a/bin/lint_changes.js +++ b/bin/lint_changes.js @@ -33,17 +33,47 @@ if (files.length === 0) { console.log(`Linting ${files.length} changed file(s)...`); -const eslintArgs = ['--max-warnings', '0', '--no-warn-ignored']; -if (fix) { - eslintArgs.push('--fix'); +const cwd = path.join(__dirname, '..'); +const isWin = process.platform === 'win32'; + +/** + * @param {string} command + * @param {string[]} args + * @returns {Promise} + */ +function run(command, args) { + return new Promise(/** @type {(resolve: () => void, reject: (reason: Error) => void) => void} */ ((resolve, reject) => { + const child = spawn(command, args, { + stdio: 'inherit', + cwd, + shell: isWin + }); + child.on('close', code => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`${command} exited with code ${code}`)); + } + }); + })); } -eslintArgs.push(...files); -const eslint = process.platform === 'win32' ? 'eslint.cmd' : 'eslint'; -const child = spawn(eslint, eslintArgs, { - stdio: 'inherit', - cwd: path.join(__dirname, '..'), - shell: process.platform === 'win32' +async function main() { + const oxlintArgs = ['--type-aware', '--max-warnings', '0']; + if (fix) { + oxlintArgs.push('--fix'); + } + oxlintArgs.push(...files); + + const oxlint = isWin ? 'oxlint.cmd' : 'oxlint'; + await run(oxlint, oxlintArgs); + + const eslintArgs = ['--config', 'eslint.config.naming.mjs', '--max-warnings', '0', ...files]; + const eslint = isWin ? 'eslint.cmd' : 'eslint'; + await run(eslint, eslintArgs); +} + +main().catch(err => { + console.error(err.message); + process.exit(1); }); - -child.on('close', code => process.exit(code ?? 0)); diff --git a/bin/setup-full.mjs b/bin/setup-full.mjs index 2db85d87a..35a62cbd7 100644 --- a/bin/setup-full.mjs +++ b/bin/setup-full.mjs @@ -5,7 +5,7 @@ import { spawnSync } from 'node:child_process'; import { basename, dirname, resolve, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; -const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const nodeModulesPath = resolve(repoRoot, 'node_modules'); const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm'; @@ -13,7 +13,7 @@ const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm'; /** @param {string} message */ function log(message) { - console.info(`[setup-fast] ${message}`); + console.info(`[setup-full] ${message}`); } /** @param {string[]} args */ diff --git a/bin/test_integration.js b/bin/test_integration.js index 37e6aca7c..0a2531e23 100644 --- a/bin/test_integration.js +++ b/bin/test_integration.js @@ -12,7 +12,7 @@ let argv = process.argv.slice(2); let suiteFilter = undefined; while (argv.some(e => e.startsWith('--suite='))) { const i = argv.findIndex(e => e.startsWith('--suite=')); - const match = argv[i].match(/--suite=(?.+)/) + const match = argv[i].match(/--suite=(?.+)/); suiteFilter = match?.groups?.suitename ?? undefined; argv.splice(i, 1); } @@ -42,12 +42,18 @@ if (suiteFilter) { configs = configs.filter(e => e.name === suiteFilter); } +if (suiteFilter && configs.length === 0) { + console.error(`Unknown suite: ${suiteFilter}`); + process.exit(1); +} + function npmBinScript(script) { return path.resolve(__dirname, `../node_modules/.bin/` + (process.platform === 'win32' ? `${script}.cmd` : script)); } async function run() { + let exitCode = 0; for (const config of configs) { const command = npmBinScript('playwright'); const args = ['test', '-c', config.path, ...argv]; @@ -62,10 +68,13 @@ async function run() { if (run.error) { console.error(run.error); - process.exit(run.status ?? -1); + process.exit(run.status ?? 1); } - process.exit(run.status); + if (run.status) { + exitCode = run.status; + } } + process.exit(exitCode); } run(); diff --git a/bin/test_mousemodes.js b/bin/test_mousemodes.js index 0f12d208b..8954c1d77 100644 --- a/bin/test_mousemodes.js +++ b/bin/test_mousemodes.js @@ -177,7 +177,7 @@ const ENC = { } function printMenu() { - console.log('\x1b[2J\x1b\[HTest mouse reports [Ctrl-C to exit]'); + console.log('\x1b[2J\x1b[HTest mouse reports [Ctrl-C to exit]'); console.log(); console.log(' Selected protocol [Ctrl-A to switch]'); const protocols = Object.keys(PROTOCOLS); diff --git a/bin/test_unit.js b/bin/test_unit.js index 7ec61a814..2ff7f6250 100644 --- a/bin/test_unit.js +++ b/bin/test_unit.js @@ -8,7 +8,7 @@ const path = require('path'); const COVERAGE_LINES_THRESHOLD = 40; -// Add `out` to the NODE_PATH so absolute paths can be resolved. +// Add `out-esbuild` to NODE_PATH so addon path-mapped imports (common/*, browser/*) resolve. const env = { ...process.env }; env.NODE_PATH = path.resolve(__dirname, '../out-esbuild'); @@ -21,7 +21,7 @@ if (process.argv.length > 2) { flagArgs = args.filter(e => e.startsWith('--')); // ability to inject particular test files via // npm run test [testFileA testFileB ...] - files = args.filter(e => !e.startsWith('--')); + const files = args.filter(e => !e.startsWith('--')); if (files.length) { testFiles = files; } @@ -39,8 +39,6 @@ if (checkCoverage) { ...testFiles, ...flagArgs ]; - console.info('executable', executable); - console.info('args', args); const run = cp.spawnSync( executable, args, @@ -51,7 +49,7 @@ if (checkCoverage) { stdio: 'inherit' } ); - process.exit(run.status); + process.exit(run.status ?? -1); } const run = cp.spawnSync( diff --git a/demo/client/components/window/addonImageWindow.ts b/demo/client/components/window/addonImageWindow.ts index 392b7177b..e5402182a 100644 --- a/demo/client/components/window/addonImageWindow.ts +++ b/demo/client/components/window/addonImageWindow.ts @@ -65,7 +65,8 @@ export class AddonImageWindow extends BaseWindow implements IControlWindow { const dtIip = document.createElement('dt'); dtIip.textContent = 'IIP (iTerm)'; dlIip.appendChild(dtIip); - this._addDdWithButton(dlIip, 'image-demo3', 'palette'); + this._addDdWithButton(dlIip, 'image-demo3', 'palette (png File)'); + this._addDdWithButton(dlIip, 'image-demo4', 'dice (qoi MultipartFile)'); container.appendChild(dlIip); // Kitty demos @@ -141,6 +142,21 @@ export class AddonImageWindow extends BaseWindow implements IControlWindow { this._terminal.write(`\x1b]1337;File=inline=1;size=${data.length}:${btoa(sdata)}\x1b\\`); }); + const iipDemoMulti = (url: string) => () => fetch(url) + .then(resp => resp.arrayBuffer()) + .then(buffer => { + const data = new Uint8Array(buffer); + let sdata = ''; + for (let i = 0; i < data.length; ++i) sdata += String.fromCharCode(data[i]); + const encoded = btoa(sdata); + this._terminal.write('\r\n'); + this._terminal.write(`\x1b]1337;MultipartFile=inline=1\x1b\\`); + for (let i = 0; i < encoded.length; i += 100) { + this._terminal.write(`\x1b]1337;FilePart=${encoded.slice(i, i + 100)}\x1b\\`); + } + this._terminal.write(`\x1b]1337;FileEnd\x1b\\`); + }); + const kittyDemo = (url: string) => () => fetch(url) .then(resp => resp.arrayBuffer()) .then(buffer => { @@ -158,6 +174,8 @@ export class AddonImageWindow extends BaseWindow implements IControlWindow { sixelDemo('https://raw.githubusercontent.com/jerch/node-sixel/master/testfiles/test2.sixel')); document.getElementById('image-demo3')!.addEventListener('click', iipDemo('https://raw.githubusercontent.com/jerch/node-sixel/master/palette.png')); + document.getElementById('image-demo4')!.addEventListener('click', + iipDemoMulti('https://raw.githubusercontent.com/jerch/xterm-wasm-parts/master/fixtures/qoi/dice.qoi')); document.getElementById('image-demo-kitty1')!.addEventListener('click', kittyDemo('https://raw.githubusercontent.com/jerch/node-sixel/master/palette.png')); @@ -176,7 +194,7 @@ export class AddonImageWindow extends BaseWindow implements IControlWindow { // } // } - const pos = (this._terminal as any)._core._mouseService!.getCoords(ev, (this._terminal as any)._core.screenElement!, this._terminal.cols, this._terminal.rows); + const pos = (this._terminal as any)._core._mouseCoordsService!.getCoords(ev, (this._terminal as any)._core.screenElement!, this._terminal.cols, this._terminal.rows); const x = pos[0] - 1; const y = pos[1] - 1; const canvas = ev.shiftKey diff --git a/demo/client/components/window/gpuWindow.ts b/demo/client/components/window/gpuWindow.ts index ac7b2c3db..382056aba 100644 --- a/demo/client/components/window/gpuWindow.ts +++ b/demo/client/components/window/gpuWindow.ts @@ -43,7 +43,7 @@ export class GpuWindow extends BaseWindow implements IControlWindow { } private _styleAtlasPage(canvas: HTMLCanvasElement): void { - // eslint-disable-next-line no-restricted-syntax + // oxlint-disable-next-line eslint-js/no-restricted-syntax const dpr = window.devicePixelRatio; canvas.style.width = `${canvas.width / dpr}px`; canvas.style.height = `${canvas.height / dpr}px`; diff --git a/demo/client/components/window/webglWindow.ts b/demo/client/components/window/webglWindow.ts index b61be231f..d7c175c45 100644 --- a/demo/client/components/window/webglWindow.ts +++ b/demo/client/components/window/webglWindow.ts @@ -11,8 +11,33 @@ export class WebglWindow extends BaseWindow implements IControlWindow { public readonly label = 'webgl'; private _textureAtlasContainer!: HTMLElement; + private _stressRunning = false; + private _stressScrolling: HTMLInputElement | undefined; public build(container: HTMLElement): void { + const stressDiv = document.createElement('div'); + const stressStart = document.createElement('button'); + stressStart.id = 'stress-start'; + stressStart.textContent = 'atlas stress start'; + stressStart.addEventListener('click', () => this._stress()); + stressDiv.appendChild(stressStart); + + const stressStop = document.createElement('button'); + stressStop.id = 'stress-stop'; + stressStop.textContent = 'atlas stress stop'; + stressStop.addEventListener('click', () => this._stressRunning = false); + stressDiv.appendChild(stressStop); + + this._stressScrolling = document.createElement('input'); + this._stressScrolling.type = 'checkbox'; + this._stressScrolling.id = 'stress-scrolling'; + stressDiv.appendChild(this._stressScrolling); + const stressScrollingLabel = document.createElement('label'); + stressScrollingLabel.htmlFor = 'stress-scrolling'; + stressScrollingLabel.textContent = 'stress scrolling'; + stressDiv.appendChild(stressScrollingLabel); + container.appendChild(stressDiv); + const zoomCheckbox = document.createElement('input'); zoomCheckbox.type = 'checkbox'; zoomCheckbox.id = 'texture-atlas-zoom'; @@ -43,9 +68,38 @@ export class WebglWindow extends BaseWindow implements IControlWindow { } private _styleAtlasPage(canvas: HTMLCanvasElement): void { - // eslint-disable-next-line no-restricted-syntax + // oxlint-disable-next-line eslint-js/no-restricted-syntax const dpr = window.devicePixelRatio; canvas.style.width = `${canvas.width / dpr}px`; canvas.style.height = `${canvas.height / dpr}px`; } + + private async _stress(): Promise { + const TEXT = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; + if (this._stressRunning) { + return; + } + this._stressRunning = true; + const scrolling = !!(this._stressScrolling?.checked); + for (let r = 0; r < 256; r += 2) { + for (let g = 0; g < 256; g += 2) { + let s: string[] = []; + for (let b = 0; b < 256; b += 2) { + if (!this._stressRunning) { + return; + } + const rbg = `RGB: ${[r, g, b]}`; + s.push(`\r\x1b[38;2;${r};${g};${b}m${rbg.padEnd(18, ' ')}${TEXT}`); + if (s.length >= 16) { + if (scrolling) { + await new Promise(r => this._terminal.write(s.join('\r\n') + '\r\n', r)); + } else { + await new Promise(r => this._terminal.write('\x1b[H' + s.join('\r\n'), r)); + } + s = []; + } + } + } + } + } } diff --git a/demo/client/tsconfig.json b/demo/client/tsconfig.json index 244f19c6e..de1ba6eb9 100644 --- a/demo/client/tsconfig.json +++ b/demo/client/tsconfig.json @@ -2,25 +2,54 @@ "compilerOptions": { "module": "commonjs", "target": "es2021", + "types": [ + "node" + ], "outDir": "../out-demo/client", "rootDir": ".", "sourceMap": true, "strict": true, "skipLibCheck": true, "paths": { - "@xterm/addon-attach": ["../../addons/addon-attach"], - "@xterm/addon-clipboard": ["../../addons/addon-clipboard"], - "@xterm/addon-fit": ["../../addons/addon-fit"], - "@xterm/addon-image": ["../../addons/addon-image"], - "@xterm/addon-progress": ["../../addons/addon-progress"], - "@xterm/addon-search": ["../../addons/addon-search"], - "@xterm/addon-serialize": ["../../addons/addon-serialize"], - "@xterm/addon-web-fonts": ["../../addons/addon-web-fonts"], - "@xterm/addon-web-links": ["../../addons/addon-web-links"], - "@xterm/addon-webgl": ["../../addons/addon-webgl"], - "@xterm/addon-unicode11": ["../../addons/addon-unicode11"], - "@xterm/addon-unicode-graphemes": ["../../addons/addon-unicode-graphemes"], - "@xterm/addon-ligatures": ["../../addons/addon-ligatures"], + "@xterm/addon-attach": [ + "../../addons/addon-attach" + ], + "@xterm/addon-clipboard": [ + "../../addons/addon-clipboard" + ], + "@xterm/addon-fit": [ + "../../addons/addon-fit" + ], + "@xterm/addon-image": [ + "../../addons/addon-image" + ], + "@xterm/addon-progress": [ + "../../addons/addon-progress" + ], + "@xterm/addon-search": [ + "../../addons/addon-search" + ], + "@xterm/addon-serialize": [ + "../../addons/addon-serialize" + ], + "@xterm/addon-web-fonts": [ + "../../addons/addon-web-fonts" + ], + "@xterm/addon-web-links": [ + "../../addons/addon-web-links" + ], + "@xterm/addon-webgl": [ + "../../addons/addon-webgl" + ], + "@xterm/addon-unicode11": [ + "../../addons/addon-unicode11" + ], + "@xterm/addon-unicode-graphemes": [ + "../../addons/addon-unicode-graphemes" + ], + "@xterm/addon-ligatures": [ + "../../addons/addon-ligatures" + ], "*": ["./*"] } }, diff --git a/demo/server/server.ts b/demo/server/server.ts index ef98eb84c..3fe5e1b80 100644 --- a/demo/server/server.ts +++ b/demo/server/server.ts @@ -118,7 +118,7 @@ function startServer(): void { }); appWs.ws('/terminals/:pid', function (ws, req) { - const term = terminals[parseInt(req.params.pid)]; + const term = terminals[parseInt(Array.isArray(req.params.pid) ? req.params.pid[0] : req.params.pid)]; console.log('Connected to terminal ' + term.pid); temporaryDisposable[term.pid].dispose(); delete temporaryDisposable[term.pid]; diff --git a/eslint.config.mjs b/eslint.config.mjs index b73eece7a..a5d8a6f91 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -37,12 +37,13 @@ export default tseslint.config( '@stylistic/comma-spacing': ['warn', { before: false, after: true }], '@stylistic/indent': ['warn', 2], '@stylistic/semi': ['warn', 'always'], - '@stylistic/quotes': ['warn', 'single', { allowTemplateLiterals: true }], + '@stylistic/quotes': ['warn', 'single', { allowTemplateLiterals: 'always' }], '@stylistic/member-delimiter-style': ['warn', { multiline: { delimiter: 'semi', requireLast: true }, singleline: { delimiter: 'comma', requireLast: false } }], '@stylistic/type-annotation-spacing': 'warn', + '@stylistic/space-unary-ops': 'warn', '@typescript-eslint/array-type': ['warn', { default: 'array', readonly: 'generic' }], '@typescript-eslint/consistent-type-assertions': 'warn', @@ -85,6 +86,7 @@ export default tseslint.config( 'eqeqeq': ['warn', 'always'], 'jsdoc/check-alignment': 'warn', 'jsdoc/check-param-names': 'warn', + 'jsdoc/multiline-blocks': 'warn', 'jsdoc/no-multi-asterisks': 'warn', 'keyword-spacing': 'warn', 'max-len': ['warn', { diff --git a/eslint.config.naming.mjs b/eslint.config.naming.mjs new file mode 100644 index 000000000..043f903c4 --- /dev/null +++ b/eslint.config.naming.mjs @@ -0,0 +1,71 @@ +// @ts-check +import tseslint from 'typescript-eslint'; + +const ignores = [ + 'addons/*/src/third-party/*.ts', + '**/out/*', + '**/out-test/*', + '**/out-esbuild/*', + '**/out-esbuild-test/*', + '**/inwasm-sdks/*', + '**/node_modules', + '**/*.js', + '**/*.mjs' +]; + +const namingConventionMain = [ + 'warn', + { selector: 'default', format: ['camelCase'], filter: { regex: '^[a-z]', match: true } }, + { selector: 'variable', format: ['camelCase', 'UPPER_CASE'] }, + { selector: 'variable', filter: '^I.+Service$', format: ['PascalCase'], prefix: ['I'] }, + { selector: 'memberLike', modifiers: ['private'], format: ['camelCase'], leadingUnderscore: 'require' }, + { selector: 'memberLike', modifiers: ['protected'], format: ['camelCase'], leadingUnderscore: 'require' }, + { selector: 'enumMember', format: ['UPPER_CASE'] }, + { selector: 'property', modifiers: ['public'], format: ['camelCase', 'UPPER_CASE'], filter: { regex: '^[a-z]', match: true } }, + { selector: 'method', modifiers: ['public'], format: ['camelCase', 'UPPER_CASE'], custom: { regex: '^on[A-Z].+', match: false } }, + { selector: 'method', modifiers: ['private'], format: ['camelCase'], leadingUnderscore: 'require', custom: { regex: '^on[A-Z].+', match: false } }, + { selector: 'method', modifiers: ['protected'], format: ['camelCase'], leadingUnderscore: 'require', custom: { regex: '^on[A-Z].+', match: false } }, + { selector: 'typeLike', format: ['PascalCase'] }, + { selector: 'interface', format: ['PascalCase'], prefix: ['I'] } +]; + +const namingConventionTypings = [ + 'warn', + { selector: 'typeLike', format: ['PascalCase'] }, + { selector: 'interface', format: ['PascalCase'], prefix: ['I'] } +]; + +export default tseslint.config( + { + ignores + }, + { + files: ['**/*.ts'], + ignores: ['typings/**/*.d.ts', 'addons/**/typings/**'], + plugins: { + '@typescript-eslint': tseslint.plugin + }, + languageOptions: { + parser: tseslint.parser, + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname + } + }, + rules: { + '@typescript-eslint/naming-convention': namingConventionMain + } + }, + { + files: ['typings/**/*.d.ts'], + plugins: { + '@typescript-eslint': tseslint.plugin + }, + languageOptions: { + parser: tseslint.parser + }, + rules: { + '@typescript-eslint/naming-convention': namingConventionTypings + } + } +); diff --git a/eslint.config.typings.mjs b/eslint.config.typings.mjs index 773a91593..a772f7c60 100644 --- a/eslint.config.typings.mjs +++ b/eslint.config.typings.mjs @@ -17,7 +17,7 @@ export default tseslint.config( rules: { '@stylistic/indent': ['warn', 2], '@stylistic/semi': ['warn', 'always'], - '@stylistic/quotes': ['warn', 'single', { allowTemplateLiterals: true }], + '@stylistic/quotes': ['warn', 'single', { allowTemplateLiterals: 'always' }], '@stylistic/member-delimiter-style': ['warn', { multiline: { delimiter: 'semi', requireLast: true }, singleline: { delimiter: 'comma', requireLast: false } diff --git a/package-lock.json b/package-lock.json index bb713de74..5f5877240 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,41 +12,46 @@ "addons/*" ], "devDependencies": { + "@eslint/js": "^10.0.1", "@lunapaint/png-codec": "^0.2.0", - "@playwright/test": "^1.57.0", - "@stylistic/eslint-plugin": "^4.4.1", - "@types/chai": "^4.2.22", - "@types/express": "4", + "@playwright/test": "^1.59.1", + "@stylistic/eslint-plugin": "^5.10.0", + "@types/chai": "^5.2.3", + "@types/express": "^5.0.6", "@types/express-ws": "^3.0.1", - "@types/jsdom": "^27.0.0", - "@types/mocha": "^9.0.0", + "@types/jsdom": "^28.0.1", + "@types/mocha": "^10.0.10", "@types/node": "^22.19.3", "@types/webpack": "^5.28.0", "@types/ws": "^8.2.0", - "@typescript-eslint/eslint-plugin": "^8.50.1", - "@typescript-eslint/parser": "^8.50.1", - "@typescript/native-preview": "^7.0.0-dev.20260213.1", - "chai": "^4.3.4", + "@typescript-eslint/eslint-plugin": "^8.59.2", + "@typescript-eslint/parser": "^8.59.2", + "@typescript/native-preview": "^7.0.0-dev.20260509.2", + "chai": "^6.2.2", "concurrently": "^9.1.2", - "esbuild": "~0.25.2", - "eslint": "^9.39.2", - "eslint-plugin-jsdoc": "^50.8.0", - "express": "^4.19.2", + "esbuild": "^0.28.0", + "eslint": "^10.3.0", + "eslint-plugin-jsdoc": "^62.9.0", + "eslint-plugin-oxlint": "^1.67.0", + "express": "^5.2.1", "express-ws": "^5.0.2", - "jsdom": "^27.3.0", - "mocha": "^10.1.0", + "jsdom": "^29.1.1", + "mocha": "^11.7.5", "mustache": "^4.2.0", "node-pty": "^1.2.0-beta.9", - "nyc": "^17.1.0", - "source-map-loader": "^3.0.0", + "nyc": "^18.0.0", + "oxlint": "^1.67.0", + "oxlint-plugin-eslint": "^1.67.0", + "oxlint-tsgolint": "^0.23.0", + "source-map-loader": "^5.0.0", "source-map-support": "^0.5.20", - "ts-loader": "^9.3.1", + "ts-loader": "^9.5.7", "typescript": "^5.9.3", - "typescript-eslint": "^8.50.1", - "webpack": "^5.61.0", - "webpack-cli": "^4.9.1", - "ws": "^8.2.3", - "xterm-benchmark": "^0.3.1" + "typescript-eslint": "^8.59.2", + "webpack": "^5.106.2", + "webpack-cli": "^7.0.2", + "ws": "^8.20.0", + "xterm-benchmark": "^0.3.2" } }, "addons/addon-attach": { @@ -78,39 +83,17 @@ "version": "0.10.0", "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0", - "opentype.js": "^0.8.0" + "lru-cache": "^11.3.6", + "opentype.js": "^2.0.0" }, "devDependencies": { - "@types/lru-cache": "^5.1.0", - "@types/opentype.js": "^0.7.0", - "axios": "^1.15.0", - "font-finder": "^1.1.0", - "mkdirp": "0.5.5", - "yauzl": "^3.2.1" + "@types/opentype.js": "^1.3.9", + "font-finder": "^1.1.0" }, "engines": { "node": ">8.0.0" } }, - "addons/addon-ligatures/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "addons/addon-ligatures/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "addons/addon-progress": { "name": "@xterm/addon-progress", "version": "0.2.0", @@ -151,69 +134,65 @@ "version": "0.19.0", "license": "MIT" }, - "node_modules/@acemir/cssom": { - "version": "0.9.30", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.30.tgz", - "integrity": "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==", - "dev": true - }, "node_modules/@asamuzakjp/css-color": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", - "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", "dev": true, + "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.4" - } - }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", - "dev": true, + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.7.6", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", - "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", "dev": true, + "license": "MIT", "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", - "css-tree": "^3.1.0", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.4" + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", "dev": true, + "license": "MIT", "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/@asamuzakjp/nwsapi": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -222,29 +201,31 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz", + "integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -264,25 +245,28 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -292,12 +276,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -307,11 +292,22 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -321,32 +317,35 @@ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -360,6 +359,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -369,6 +369,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -378,30 +379,33 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -411,40 +415,43 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -452,10 +459,11 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" @@ -464,10 +472,23 @@ "node": ">=6.9.0" } }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true, "funding": [ { @@ -479,14 +500,15 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT-0", "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", "dev": true, "funding": [ { @@ -498,18 +520,19 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.1.tgz", + "integrity": "sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g==", "dev": true, "funding": [ { @@ -521,22 +544,23 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.2.1" }, "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, "funding": [ { @@ -548,17 +572,18 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.22.tgz", - "integrity": "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz", + "integrity": "sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==", "dev": true, "funding": [ { @@ -570,14 +595,20 @@ "url": "https://opencollective.com/csstools" } ], - "engines": { - "node": ">=18" + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } } }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, "funding": [ { @@ -589,43 +620,57 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-1.1.0.tgz", + "integrity": "sha512-Xc3VhU02wqZ1HvHRJUwL09HkZSTvidqY5Ya0NXBSYOxAp+Ln9dcJr9fySI+CkONzP3PekQo9WdzCv0PGER/mOA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=14.17.0" } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.50.2", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", - "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz", + "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "^1.0.6", - "@typescript-eslint/types": "^8.11.0", - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.1.0" + "@types/estree": "^1.0.8", + "@typescript-eslint/types": "^8.58.0", + "comment-parser": "1.4.6", + "esquery": "^1.7.0", + "jsdoc-type-pratt-parser": "~7.2.0" }, "engines": { - "node": ">=18" + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@es-joy/resolve.exports": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@es-joy/resolve.exports/-/resolve.exports-1.2.0.tgz", + "integrity": "sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -635,13 +680,14 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -651,13 +697,14 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -667,13 +714,14 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -683,13 +731,14 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -699,13 +748,14 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -715,13 +765,14 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -731,13 +782,14 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -747,13 +799,14 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -763,13 +816,14 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -779,13 +833,14 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -795,13 +850,14 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -811,13 +867,14 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", "cpu": [ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -827,13 +884,14 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -843,13 +901,14 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -859,13 +918,14 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -875,13 +935,14 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -891,13 +952,14 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -907,13 +969,14 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -923,13 +986,14 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -939,13 +1003,14 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -955,13 +1020,14 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openharmony" @@ -971,13 +1037,14 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -987,13 +1054,14 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1003,13 +1071,14 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1019,13 +1088,14 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1035,10 +1105,11 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -1057,6 +1128,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -1069,187 +1141,159 @@ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.7", + "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^10.2.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", + "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0" + "@eslint/core": "^1.2.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0", + "@eslint/core": "^1.2.1", "levn": "^0.4.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -1263,6 +1307,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -1271,11 +1316,30 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -1292,6 +1356,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -1301,6 +1366,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -1314,6 +1380,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -1327,6 +1394,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -1339,6 +1407,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -1354,6 +1423,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -1361,20 +1431,12 @@ "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1384,6 +1446,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" @@ -1394,6 +1457,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -1404,6 +1468,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1413,6 +1478,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -1422,13 +1488,15 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1439,18 +1507,437 @@ "resolved": "https://registry.npmjs.org/@lunapaint/png-codec/-/png-codec-0.2.0.tgz", "integrity": "sha512-S2Fk8+I27j8ZL585PlEK9hhljZcp6j+JWB5ZHAeePdufJMYHxXD2zlatLRaiy5riXRFqkCi/gong7yP9kSsEZg==", "dev": true, + "license": "MIT", "dependencies": { "pako": "^2.0.4" } }, + "node_modules/@oxlint-tsgolint/darwin-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-gOs9PVr2wEg4ox9z0aJo+RKhhImW86YL5N6yav8BK/rgPsIrwN/igSZ+pbRr723NFvUNKde9fgMhRA6JrXAOZw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxlint-tsgolint/darwin-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-kjJ8B+7n4tB9VJdxS5A9GdJt6/bYpzbu4lXp2uO1S3sRmCB5gDEABlGoiePNApRWaW+xqL4b4xgiE727jSLhuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxlint-tsgolint/linux-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-6dCZuKNu135seMXilkRk9SpCx6i1XgmiipYGalLij5WVRX6ZYS8c4xI7preN/zv9fCXhsQclTIMDu2Y/cytTjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint-tsgolint/linux-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-3bdilnyA7kmSTjK27rvjIjSxL5SIg3wt7vwNiRkouWB83ytssyKnuGvxSYJxgMEmFpSutzaBzcCUM2jDtPGcgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint-tsgolint/win32-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-j+OEp44SVYiQ+ZD+uttsX7u6L9SvmbbQ77SO1pSFCcJlsVMeCk8qZsjhKfGKuT/jIA+ipOJMVs/+pqUfObBWNw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxlint-tsgolint/win32-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-5MyjFuqf+g8OUPJBSGWHJtmoWnzFJYyOg4To9WMQshZYEWig/vtu7JtJ03VWnzHv9LJkAUeApY0gVCOywFR/iQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.67.0.tgz", + "integrity": "sha512-VrSi571rDv1N8HaEDM+DEX8nmT0y9jJo8tzzW13vsOWTx59xQczCIJx68n2zWOXRT5YKZsOZXp4qkHN/10x4mw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.67.0.tgz", + "integrity": "sha512-l6+NdYxMoRohix5r5bbigW16LPicceCwGcQ6LKKuE1kUdjgFfQolJjrJsQYPFetIs78Gxj/G/f5TEGoTCwj9nQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.67.0.tgz", + "integrity": "sha512-jOzXxS1AxFxhImLIRbtGIMrEwaXcgMw3gR57WB1cRk8ai+vpr6726kxXqVvlNsrXtJ/FrmOm8RxlC0m8SW24Qg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.67.0.tgz", + "integrity": "sha512-3DFAVY94OqjIZHXIPz37yGRSWwOFTAqChQ64/M69GYLawzP0KiwdhDNfqdKKYT0bTR/DNxmMnQsj3ns+8+X/Lg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.67.0.tgz", + "integrity": "sha512-e4dDKZuLu8TR9DEBssWSDahlPgZBwojTTHZUvnjBRJfJJbpxYCjfjKfi0Z1+CSLMiJBwI2yCDtRM1XJQaARjmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.67.0.tgz", + "integrity": "sha512-BKytFdcQzbITV3xlnzDUDTEDtbUMCCiC4EaNTDZ4FyT8gdNvBC4gfiLucXp/sQl0XU3p7syTlorUWVVVBZab2g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.67.0.tgz", + "integrity": "sha512-XYAv0esBDX7BpTzRDjVX2Vdj+zndd8ll2dFQiaeQ6zTZr7A8GRDTN7fH3FP3jU+O0vCDx85oH/EtG7BzPgAXuw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.67.0.tgz", + "integrity": "sha512-zizRMjA0i6u/2B0evgda04iycu+MoNuf1pBy6Eh+1CjC5wMEG7qN5zdDKTCvFc0KSYSDM9QTG3gjZHirgtQuKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.67.0.tgz", + "integrity": "sha512-zB/Tf6sUjmmvvbva9Gj3JTJ8rJ9t4I8/U0o6vSRtd0DRIsIuyegBwJAzhSUFQHdMijIRJkW0exs/yBhpw2S20w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.67.0.tgz", + "integrity": "sha512-kgU40Gt74CK0TCsF51KZymkIwN9U0BajKsMijB52zPqOeZU9NAHkA/NSQkZDHEaCakx42DxhXkODiAqf2b4Gug==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.67.0.tgz", + "integrity": "sha512-tOYhkk/iaG9aD3FvGpBFd1Lrw0x0RaVoJBxjUkfNzS50rC5NS5BteNCwgr8A2zCdADrIIoze6D7u6U5Ic++/iQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.67.0.tgz", + "integrity": "sha512-sEtywrPb+0b+tHYl1SDCrw903fiC4eyKoNqzP3v+f2JT3Xcv4NEYG+P8rj+eEnX7IWhqV/xj8/JmcmVj21CXaA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.67.0.tgz", + "integrity": "sha512-BvR8Moa0zCLxroOx4vZaZN9nUfwAUpSTwjZdxZyKy4bv3PrzrXrxKR/ZQ0L9wNSvlPhnMJeZfa3q5w6ZCTuN6Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.67.0.tgz", + "integrity": "sha512-mm2cxM6fksOpq6l0uFws8BUGKAR4dNa/cZCn37Npq7PFbhD5HDJqWfnoIvTaeRKMy5XdS2tO0MA0qbHDrnXAAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.67.0.tgz", + "integrity": "sha512-WmbMuLapKyDlobMkXAaAL0Y+Uczh4LETfIfQsUpbId4Ip8Ai82/jqeYTOoUCkuuhBFapgqP253+d83tLKOksJg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.67.0.tgz", + "integrity": "sha512-9g/PqxYJelzzTAOR5Y+RiRqdeydhEuXv2KxNeFcAKQ7UsvnWSY1OP4MsuPMbTO2Pf70tz7mFhl1j13H3fyh+8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.67.0.tgz", + "integrity": "sha512-2VhwE6Gatb0vJGnN0TBuQMbKCOiZlSQ/zJvVWYLK4a9d4iDiJOen/yVQkGpmsJ90MuH66fzi0kEKI0jRQMDxGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.67.0.tgz", + "integrity": "sha512-EQ3VExXfeM1InbE5+JjufhZZTWy+kHUwgt3yZR7gQ47Je/mE0WspQPan0OJznh493L5anM210YNJtH1PXjTSFg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.67.0.tgz", + "integrity": "sha512-bw24y+/1MHS4QDkons3YyHkPT9uCMoLHHgQhb+mb8NOjTYwub1CZ+K9Ngr8aO5DMrDrkqHwTzlTwFP2vS8Y/ZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@playwright/test": { - "version": "1.57.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.57.0.tgz", - "integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==", + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.57.0" + "playwright": "1.60.0" }, "bin": { "playwright": "cli.js" @@ -1459,105 +1946,111 @@ "node": ">=18" } }, - "node_modules/@stylistic/eslint-plugin": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.4.1.tgz", - "integrity": "sha512-CEigAk7eOLyHvdgmpZsKFwtiqS2wFwI1fn4j09IU9GmD4euFM4jEBAViWeCqaNLlbX2k2+A/Fq9cje4HQBXuJQ==", + "node_modules/@sindresorhus/base62": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/base62/-/base62-1.0.0.tgz", + "integrity": "sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^8.32.1", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/types": "^8.56.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "estraverse": "^5.3.0", - "picomatch": "^4.0.2" + "picomatch": "^4.0.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": ">=9.0.0" + "eslint": "^9.0.0 || ^10.0.0" } }, - "node_modules/@types/app-root-path": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@types/app-root-path/-/app-root-path-1.2.8.tgz", - "integrity": "sha512-l12miuN6JXAi3yuADZNhRKbyN7IIyaUP9hFVZ/BbHhWYpBkHLbOaX2WkQoXGJyAgMcP9iZ0S9+tz/FN40VrwWQ==", - "dev": true - }, "node_modules/@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "node_modules/@types/chai": { - "version": "4.3.20", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", - "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", - "dev": true - }, - "node_modules/@types/cli-table": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@types/cli-table/-/cli-table-0.3.4.tgz", - "integrity": "sha512-GsALrTL69mlwbAw/MHF1IPTadSLZQnsxe7a80G8l4inN/iEXCOcVeT/S7aRc6hbhqzL9qZ314kHPDQnQ3ev+HA==", - "dev": true + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } + "license": "MIT" }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } + "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", - "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "^1" + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", - "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -1570,6 +2063,7 @@ "resolved": "https://registry.npmjs.org/@types/express-ws/-/express-ws-3.0.6.tgz", "integrity": "sha512-6ZDt+tMEQgM4RC1sMX1fIO7kHQkfUDlWfxoPddXUeeDjmc+Yt/fCzqXfp8rFahNr5eIxdomrWphLEWDkB2q3UQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*", "@types/express-serve-static-core": "*", @@ -1580,117 +2074,92 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/jsdom": { - "version": "27.0.0", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-27.0.0.tgz", - "integrity": "sha512-NZyFl/PViwKzdEkQg96gtnB8wm+1ljhdDay9ahn4hgb+SfVtPCbm3TlmDUFXTA+MGN3CijicnMhG18SI5H3rFw==", + "version": "28.0.3", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-28.0.3.tgz", + "integrity": "sha512-/HQ2uFoetFTXuye8vzIcHw2z6Fwi7Hi/qcgC+RoS9NCyewiqxhVGqlG+ViGB6lkax481R6dmhf1I7lIGlzJStQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", - "parse5": "^7.0.0" + "parse5": "^8.0.0", + "undici-types": "^7.21.0" } }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", "dev": true, "license": "MIT" }, - "node_modules/@types/mathjs": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@types/mathjs/-/mathjs-6.0.12.tgz", - "integrity": "sha512-bpKs8CDJ0aOiiJguywryE/U6Wre/uftJ89xhp4aCgF4oRb3Yug2VyZ87958gmSeq4WMsvWPMs2Q5TtFv+dJtaA==", - "dev": true, - "dependencies": { - "decimal.js": "^10.0.0" - } - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, "node_modules/@types/mocha": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", - "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", - "dev": true + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "22.19.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz", - "integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==", + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~6.21.0" } }, - "node_modules/@types/opentype.js": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@types/opentype.js/-/opentype.js-0.7.2.tgz", - "integrity": "sha512-Riz6WyBUBEFs7YqSsJya3SbDHJZ6BmMkY7bzNoue6rtwj+RNilLc+mgOX/eJ0Y0asq16FSU6DatBeOg8ZMy2UQ==", + "node_modules/@types/node/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, - "node_modules/@types/puppeteer": { - "version": "5.4.7", - "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.7.tgz", - "integrity": "sha512-JdGWZZYL0vKapXF4oQTC5hLVNfOgdPrqeZ1BiQnGk5cB7HeE91EWUiTdVSdQPobRN8rIcdffjiOgCYJ/S8QrnQ==", + "node_modules/@types/opentype.js": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@types/opentype.js/-/opentype.js-1.3.9.tgz", + "integrity": "sha512-KOGywvDPncA4/tTWV5xKNhjpsoSSAHIx3mHOhL5l3XX+c6Xu2dQnHvGs7mRNQsQRte1EqmQ0cPQQ8Z14lkv+yw==", "dev": true, - "dependencies": { - "@types/node": "*" - } + "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", - "dev": true, - "dependencies": { - "@types/mime": "^1", "@types/node": "*" } }, @@ -1698,13 +2167,15 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/webpack": { "version": "5.28.5", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.5.tgz", "integrity": "sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "tapable": "^2.2.0", @@ -1716,24 +2187,26 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.50.1.tgz", - "integrity": "sha512-PKhLGDq3JAg0Jk/aK890knnqduuI/Qj+udH7wCf0217IGi4gt+acgCyPVe79qoT+qKUvHMDQkwJeKW9fwl8Cyw==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.4.tgz", + "integrity": "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.50.1", - "@typescript-eslint/type-utils": "8.50.1", - "@typescript-eslint/utils": "8.50.1", - "@typescript-eslint/visitor-keys": "8.50.1", - "ignore": "^7.0.0", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/type-utils": "8.59.4", + "@typescript-eslint/utils": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1743,22 +2216,23 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.50.1", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "@typescript-eslint/parser": "^8.59.4", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.50.1.tgz", - "integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.4.tgz", + "integrity": "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.50.1", - "@typescript-eslint/types": "8.50.1", - "@typescript-eslint/typescript-estree": "8.50.1", - "@typescript-eslint/visitor-keys": "8.50.1", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1768,19 +2242,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.50.1.tgz", - "integrity": "sha512-E1ur1MCVf+YiP89+o4Les/oBAVzmSbeRB0MQLfSlYtbWU17HPxZ6Bhs5iYmKZRALvEuBoXIZMOIRRc/P++Ortg==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.4.tgz", + "integrity": "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.50.1", - "@typescript-eslint/types": "^8.50.1", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.59.4", + "@typescript-eslint/types": "^8.59.4", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1790,17 +2265,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.50.1.tgz", - "integrity": "sha512-mfRx06Myt3T4vuoHaKi8ZWNTPdzKPNBhiblze5N50//TSHOAQQevl/aolqA/BcqqbJ88GUnLqjjcBc8EWdBcVw==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.4.tgz", + "integrity": "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.50.1", - "@typescript-eslint/visitor-keys": "8.50.1" + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1811,10 +2287,11 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.50.1.tgz", - "integrity": "sha512-ooHmotT/lCWLXi55G4mvaUF60aJa012QzvLK0Y+Mp4WdSt17QhMhWOaBWeGTFVkb2gDgBe19Cxy1elPXylslDw==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.4.tgz", + "integrity": "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1823,20 +2300,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.50.1.tgz", - "integrity": "sha512-7J3bf022QZE42tYMO6SL+6lTPKFk/WphhRPe9Tw/el+cEwzLz1Jjz2PX3GtGQVxooLDKeMVmMt7fWpYRdG5Etg==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.4.tgz", + "integrity": "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.50.1", - "@typescript-eslint/typescript-estree": "8.50.1", - "@typescript-eslint/utils": "8.50.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4", + "@typescript-eslint/utils": "8.59.4", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1846,15 +2324,16 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.50.1.tgz", - "integrity": "sha512-v5lFIS2feTkNyMhd7AucE/9j/4V9v5iIbpVRncjk/K0sQ6Sb+Np9fgYS/63n6nwqahHQvbmujeBL7mp07Q9mlA==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.4.tgz", + "integrity": "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1864,20 +2343,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.50.1.tgz", - "integrity": "sha512-woHPdW+0gj53aM+cxchymJCrh0cyS7BTIdcDxWUNsclr9VDkOSbqC13juHzxOmQ22dDkMZEpZB+3X1WpUvzgVQ==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.4.tgz", + "integrity": "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.50.1", - "@typescript-eslint/tsconfig-utils": "8.50.1", - "@typescript-eslint/types": "8.50.1", - "@typescript-eslint/visitor-keys": "8.50.1", - "debug": "^4.3.4", - "minimatch": "^9.0.4", - "semver": "^7.6.0", + "@typescript-eslint/project-service": "8.59.4", + "@typescript-eslint/tsconfig-utils": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/visitor-keys": "8.59.4", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1887,19 +2367,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.50.1.tgz", - "integrity": "sha512-lCLp8H1T9T7gPbEuJSnHwnSuO9mDf8mfK/Nion5mZmiEaQD9sWf9W4dfeFqRyqRjF06/kBuTmAqcs9sewM2NbQ==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.4.tgz", + "integrity": "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.50.1", - "@typescript-eslint/types": "8.50.1", - "@typescript-eslint/typescript-estree": "8.50.1" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.4", + "@typescript-eslint/types": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1909,18 +2390,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.50.1.tgz", - "integrity": "sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.4.tgz", + "integrity": "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.50.1", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.59.4", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1930,29 +2412,45 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@typescript/native-preview": { - "version": "7.0.0-dev.20260213.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260213.1.tgz", - "integrity": "sha512-TZ/0Tv954jRpn5IHQJZQF0gaNmw//ZTvkgr3nC2H8u9t4GxUhIk5vfAHVFgdl8JnNGbl7gZks37FVsEwXjdHqg==", + "version": "7.0.0-dev.20260521.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260521.1.tgz", + "integrity": "sha512-JhaYbA+BVmHfya8h4QA1HsX6EZr7qaLOoOOHEwwR1ps42wN8LFDSSTbf1y2nPO3h927yh2Udl7gto1u7WGXjAQ==", "dev": true, "license": "Apache-2.0", "bin": { "tsgo": "bin/tsgo.js" }, + "engines": { + "node": ">=16.20.0" + }, "optionalDependencies": { - "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260213.1", - "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260213.1", - "@typescript/native-preview-linux-arm": "7.0.0-dev.20260213.1", - "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260213.1", - "@typescript/native-preview-linux-x64": "7.0.0-dev.20260213.1", - "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260213.1", - "@typescript/native-preview-win32-x64": "7.0.0-dev.20260213.1" + "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260521.1", + "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260521.1", + "@typescript/native-preview-linux-arm": "7.0.0-dev.20260521.1", + "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260521.1", + "@typescript/native-preview-linux-x64": "7.0.0-dev.20260521.1", + "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260521.1", + "@typescript/native-preview-win32-x64": "7.0.0-dev.20260521.1" } }, "node_modules/@typescript/native-preview-darwin-arm64": { - "version": "7.0.0-dev.20260213.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260213.1.tgz", - "integrity": "sha512-nqfuHgFZ8MvaHeb1XOkAGIGc6cR91dwQdlHmlbH918n63JguKzkYjzzulpr48IVn1SVewGwjtfs1moCpaDpWcg==", + "version": "7.0.0-dev.20260521.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260521.1.tgz", + "integrity": "sha512-DfwzV0Qc8VDHqQXG4uc0+bbHB23u/Twrl+D7H1Izo16MmwBse3kjdKAKCJDqeboYvofx/AetKZP9yo+VxjvOWg==", "cpu": [ "arm64" ], @@ -1961,12 +2459,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, "node_modules/@typescript/native-preview-darwin-x64": { - "version": "7.0.0-dev.20260213.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260213.1.tgz", - "integrity": "sha512-JDVDVLPIYhYZR12omTKwzKbdw+wnPEtLnkmM+nioqbISlV29fg7IBgFx0/mf1D+Gz1ztUQVHDTqw4GEgOZ9VTg==", + "version": "7.0.0-dev.20260521.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260521.1.tgz", + "integrity": "sha512-tTtyAkx7VUgfRa+DGJa1/nR40/LsdbA5EUlSTnGV/3I6la7JB5hJxhWz+B99WjHjJbZrMrLxf6S4YHTj13GWew==", "cpu": [ "x64" ], @@ -1975,12 +2476,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, "node_modules/@typescript/native-preview-linux-arm": { - "version": "7.0.0-dev.20260213.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260213.1.tgz", - "integrity": "sha512-O6iVB8tTnLZJVYrChH6VJuCwqAa2ObWVdMtrKQw5UtmLXBhsOhZ3isttSuGzQrPfTiGN091IdW1KuRi8Ft1lnQ==", + "version": "7.0.0-dev.20260521.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260521.1.tgz", + "integrity": "sha512-R+KzxOA6M6AX4p757xNBy8bZgNTXUxjQkEnJk2UzDpB317pwBbrpOaOaIlgB6Giw79jvKH2E428VWhXAk4ydlw==", "cpu": [ "arm" ], @@ -1989,12 +2493,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, "node_modules/@typescript/native-preview-linux-arm64": { - "version": "7.0.0-dev.20260213.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260213.1.tgz", - "integrity": "sha512-d7Gwl8W4aics0KI4H0zz3TP1ngnP8L5COND0TPBZ7ifWVrxKDNSLhF2V9OuStW43RPfA4Gzik9iIv+l0Lg+eGw==", + "version": "7.0.0-dev.20260521.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260521.1.tgz", + "integrity": "sha512-IMyER6SquHD/0rr7727rqTILbY7XWATFp/O1l9CRAEs9E0OY0yPmyHXFT8MYja5m4+isgsMBh618zLt8Ex1h/w==", "cpu": [ "arm64" ], @@ -2003,12 +2510,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, "node_modules/@typescript/native-preview-linux-x64": { - "version": "7.0.0-dev.20260213.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260213.1.tgz", - "integrity": "sha512-Aq55fID1fE5/8K4XvfVddgw8LKUgY3kp5IOb+QEklfyle4MuAV5gtat3MnEv9XMbiidk8iKVxYrYASlUQEQzDw==", + "version": "7.0.0-dev.20260521.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260521.1.tgz", + "integrity": "sha512-xLfDu7chsn0TJagd2oX2Z4nj3m/TRiwQmijGUgF8O0+IblKgbQcp6Egjd9VCRsGwfPidoLgElVrfcAkYfUSnGA==", "cpu": [ "x64" ], @@ -2017,12 +2527,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, "node_modules/@typescript/native-preview-win32-arm64": { - "version": "7.0.0-dev.20260213.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260213.1.tgz", - "integrity": "sha512-VlyULgXApmGMSqAANjskGx0AcjHchf3I8rhZ47AxF/XKAkZPe/5ewfleJ97iln7dg1UL3lq2cJY2CXxU+JPcFQ==", + "version": "7.0.0-dev.20260521.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260521.1.tgz", + "integrity": "sha512-+kcewCXj0A0bpJOx/BVjjcTs8vglcxfYuZdzyQl8O9vM1GoA7LF+jUf5Z7E2qlpKt5By/8c7wXp+4/ACM9drzQ==", "cpu": [ "arm64" ], @@ -2031,12 +2544,15 @@ "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, "node_modules/@typescript/native-preview-win32-x64": { - "version": "7.0.0-dev.20260213.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260213.1.tgz", - "integrity": "sha512-lEtWvZDa2oCgqJ2gbP6BRLUeTyHLyrt5BfJmVlvmVSTZzdoBpFROJdp9yprsa2Zry2o5GK8HFAxd3RlvxkOU5Q==", + "version": "7.0.0-dev.20260521.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260521.1.tgz", + "integrity": "sha512-Uh2PjzN3S/TGTDERgaT4O5rexiWO0nn0oXdCnBVyo0d1rbgDxq/zxsSOZdzdrQn6BRGa8x+6fVtrVFcIw4B+7w==", "cpu": [ "x64" ], @@ -2045,13 +2561,17 @@ "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" @@ -2061,25 +2581,29 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", @@ -2090,13 +2614,15 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -2109,6 +2635,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -2118,6 +2645,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } @@ -2126,13 +2654,15 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -2149,6 +2679,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", @@ -2162,6 +2693,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -2174,6 +2706,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", @@ -2188,47 +2721,12 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, - "node_modules/@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", - "dev": true, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", - "dev": true, - "dependencies": { - "envinfo": "^7.7.3" - }, - "peerDependencies": { - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", - "dev": true, - "peerDependencies": { - "webpack-cli": "4.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, "node_modules/@xterm/addon-attach": { "resolved": "addons/addon-attach", "link": true @@ -2285,39 +2783,36 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, + "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2330,6 +2825,7 @@ "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" }, @@ -2342,24 +2838,17 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -2369,10 +2858,11 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2389,6 +2879,7 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -2402,10 +2893,11 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -2421,24 +2913,20 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -2446,6 +2934,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2456,37 +2945,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/app-root-path": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6.0.0" } @@ -2496,6 +2960,7 @@ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", "dev": true, + "license": "MIT", "dependencies": { "default-require-extensions": "^3.0.0" }, @@ -2507,13 +2972,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/are-docs-informative": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" } @@ -2522,54 +2989,40 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/axios": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", - "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^2.1.0" + "engines": { + "node": ">=12" } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/baseline-browser-mapping": { - "version": "2.9.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", - "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "version": "2.10.31", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.31.tgz", + "integrity": "sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==", "dev": true, + "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/bidi-js": { @@ -2577,68 +3030,47 @@ "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", "dev": true, + "license": "MIT", "dependencies": { "require-from-string": "^2.0.2" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "dev": true, - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -2646,6 +3078,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -2657,12 +3090,13 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -2678,12 +3112,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -2692,26 +3127,19 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2721,6 +3149,7 @@ "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", "dev": true, + "license": "MIT", "dependencies": { "hasha": "^5.0.0", "make-dir": "^3.0.0", @@ -2736,6 +3165,7 @@ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -2749,6 +3179,7 @@ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" @@ -2760,28 +3191,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001761", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz", - "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -2796,24 +3219,17 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=18" } }, "node_modules/chalk": { @@ -2821,6 +3237,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2832,52 +3249,33 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "get-func-name": "^2.0.2" + "has-flag": "^4.0.0" }, "engines": { - "node": "*" + "node": ">=8" } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, + "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/chrome-trace-event": { @@ -2885,6 +3283,7 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } @@ -2894,6 +3293,7 @@ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2911,14 +3311,81 @@ } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/clone": { @@ -2926,6 +3393,7 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -2935,6 +3403,7 @@ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -2949,6 +3418,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2960,19 +3430,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } @@ -2982,6 +3448,7 @@ "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", "dev": true, + "license": "MIT", "dependencies": { "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" @@ -2990,29 +3457,42 @@ "node": ">=8.0.0" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/columnify/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/columnify/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", + "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.0.0" } @@ -3021,13 +3501,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/complex.js": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.4.3.tgz", "integrity": "sha512-UrQVSUur14tNX6tiP4y8T4w4FeJAX3bi2cIv0pu/DTLFNxoq7z2Yh83Vfzztj6Px3X/lubqQ9IrPp7Bpn6p4MQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -3036,12 +3518,6 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, "node_modules/concurrently": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", @@ -3067,76 +3543,18 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/concurrently/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/concurrently/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -3144,6 +3562,7 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3152,28 +3571,35 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "dev": true + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3184,43 +3610,31 @@ } }, "node_modules/css-tree": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", - "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, + "license": "MIT", "dependencies": { - "mdn-data": "2.12.2", - "source-map-js": "^1.0.1" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/cssstyle": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.5.tgz", - "integrity": "sha512-GlsEptulso7Jg0VaOZ8BXQi3AkYM5BOJKEO/rjMidSCq70FkIC5y0eawrCXeYzxgt3OCf4Ls+eoxN+/05vN0Ag==", - "dev": true, - "dependencies": { - "@asamuzakjp/css-color": "^4.1.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.21", - "css-tree": "^3.1.0" - }, - "engines": { - "node": ">=20" - } - }, "node_modules/data-urls": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", - "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", "dev": true, + "license": "MIT", "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" }, "engines": { - "node": ">=20" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/debug": { @@ -3228,6 +3642,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -3245,6 +3660,7 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3253,31 +3669,22 @@ "version": "10.6.0", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", "dev": true, + "license": "MIT", "dependencies": { "strip-bom": "^4.0.0" }, @@ -3293,6 +3700,7 @@ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -3300,39 +3708,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -3342,6 +3733,7 @@ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -3351,53 +3743,66 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true + "version": "1.5.360", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.360.tgz", + "integrity": "sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/enhanced-resolve": { - "version": "5.18.4", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", - "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" } }, "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -3408,6 +3813,7 @@ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", "dev": true, + "license": "MIT", "bin": { "envinfo": "dist/cli.js" }, @@ -3420,6 +3826,7 @@ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -3429,21 +3836,24 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -3451,33 +3861,20 @@ "node": ">= 0.4" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -3485,32 +3882,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" } }, "node_modules/escalade": { @@ -3518,6 +3915,7 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3526,19 +3924,22 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/escape-latex": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3547,32 +3948,30 @@ } }, "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.0.tgz", + "integrity": "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.6.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", + "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", @@ -3582,8 +3981,7 @@ "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -3591,7 +3989,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" @@ -3606,40 +4004,92 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "50.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.8.0.tgz", - "integrity": "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==", + "version": "62.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.9.0.tgz", + "integrity": "sha512-PY7/X4jrVgoIDncUmITlUqK546Ltmx/Pd4Hdsu4CvSjryQZJI2mEV4vrdMufyTetMiZ5taNSqvK//BTgVUlNkA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.50.2", + "@es-joy/jsdoccomment": "~0.86.0", + "@es-joy/resolve.exports": "1.2.0", "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.4.1", + "comment-parser": "1.4.6", + "debug": "^4.4.3", "escape-string-regexp": "^4.0.0", - "espree": "^10.3.0", - "esquery": "^1.6.0", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "html-entities": "^2.6.0", + "object-deep-merge": "^2.0.0", "parse-imports-exports": "^0.2.4", - "semver": "^7.7.2", - "spdx-expression-parse": "^4.0.0" + "semver": "^7.7.4", + "spdx-expression-parse": "^4.0.0", + "to-valid-identifier": "^1.0.0" }, "engines": { - "node": ">=18" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-oxlint": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-oxlint/-/eslint-plugin-oxlint-1.67.0.tgz", + "integrity": "sha512-tS/RGy8x2+rIUp7gV8ICgEeSAgFH6Qg7phzCbUblW/dPUsqXkcedrzO0nOaKhce4fvUVDR9uTmWlLkCNSDKcsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonc-parser": "^3.3.1" + }, + "peerDependencies": { + "oxlint": "~1.67.0" } }, "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3650,6 +4100,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3657,14 +4108,35 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ignore": { @@ -3672,28 +4144,17 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", @@ -3711,6 +4172,7 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -3720,10 +4182,11 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -3736,6 +4199,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -3748,6 +4212,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3757,6 +4222,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -3766,6 +4232,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3775,50 +4242,49 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, + "license": "MIT", "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 18" }, "funding": { "type": "opencollective", @@ -3830,6 +4296,7 @@ "resolved": "https://registry.npmjs.org/express-ws/-/express-ws-5.0.2.tgz", "integrity": "sha512-0uvmuk61O9HXgLhGl3QhNSEtRsQevtmbL94/eILaliEADZBHZOQUAiHFrGPrgsjikohyrmSG5g+sCfASTt0lkQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "ws": "^7.4.6" }, @@ -3845,6 +4312,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -3861,43 +4329,31 @@ } } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { @@ -3908,13 +4364,15 @@ "type": "opencollective", "url": "https://opencollective.com/fastify" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.9.1" } @@ -3924,6 +4382,7 @@ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.0.0" }, @@ -3941,6 +4400,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" }, @@ -3953,6 +4413,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3961,43 +4422,33 @@ } }, "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, "node_modules/find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "dev": true, + "license": "MIT", "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", @@ -4015,6 +4466,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -4031,6 +4483,7 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } @@ -4040,6 +4493,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" @@ -4055,27 +4509,6 @@ "dev": true, "license": "ISC" }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/font-finder": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/font-finder/-/font-finder-1.1.0.tgz", @@ -4095,6 +4528,7 @@ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" @@ -4106,63 +4540,38 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, "funding": { - "type": "patreon", + "type": "github", "url": "https://github.com/sponsors/rawify" } }, "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/fromentries": { @@ -4183,20 +4592,16 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + ], + "license": "MIT" }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -4210,6 +4615,7 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4219,6 +4625,7 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -4228,24 +4635,17 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", @@ -4270,6 +4670,7 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -4279,6 +4680,7 @@ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, + "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -4298,20 +4700,22 @@ } }, "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, + "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=12" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4322,6 +4726,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -4333,31 +4738,40 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } }, "node_modules/glob/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/gopd": { @@ -4365,6 +4779,7 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4376,13 +4791,15 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4392,21 +4809,7 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4419,6 +4822,7 @@ "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", "dev": true, + "license": "MIT", "dependencies": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" @@ -4431,10 +4835,11 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -4447,33 +4852,54 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } }, "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", "dev": true, + "license": "MIT", "dependencies": { - "whatwg-encoding": "^3.1.1" + "@exodus/bytes": "^1.6.0" }, "engines": { - "node": ">=18" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", @@ -4489,42 +4915,21 @@ "url": "https://opencollective.com/express" } }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/ignore": { @@ -4532,31 +4937,17 @@ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -4576,6 +4967,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -4585,34 +4977,26 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/inwasm-runtime": { @@ -4627,29 +5011,19 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -4663,6 +5037,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4672,6 +5047,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4681,6 +5057,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -4693,15 +5070,27 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4711,6 +5100,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -4722,13 +5112,22 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -4740,13 +5139,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4759,6 +5160,7 @@ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4767,13 +5169,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4783,6 +5187,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } @@ -4792,6 +5197,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "append-transform": "^2.0.0" }, @@ -4804,6 +5210,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -4816,20 +5223,21 @@ } }, "node_modules/istanbul-lib-processinfo": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", - "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-3.0.0.tgz", + "integrity": "sha512-P7nLXRRlo7Sqinty6lNa7+4o9jBUYGpqtejqCOZKfgXlRoxY/QArflcB86YO500Ahj4pDJEG34JjMRbQgePLnQ==", "dev": true, + "license": "ISC", "dependencies": { "archy": "^1.0.0", "cross-spawn": "^7.0.3", "istanbul-lib-coverage": "^3.2.0", "p-map": "^3.0.0", - "rimraf": "^3.0.0", + "rimraf": "^6.1.3", "uuid": "^8.3.2" }, "engines": { - "node": ">=8" + "node": "20 || >=22" } }, "node_modules/istanbul-lib-report": { @@ -4837,6 +5245,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -4851,6 +5260,7 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -4861,11 +5271,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -4880,6 +5304,7 @@ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -4888,17 +5313,35 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/javascript-natural-sort": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -4908,32 +5351,19 @@ "node": ">= 10.13.0" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -4942,43 +5372,46 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", - "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.2.0.tgz", + "integrity": "sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">=20.0.0" } }, "node_modules/jsdom": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.3.0.tgz", - "integrity": "sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==", + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", "dev": true, + "license": "MIT", "dependencies": { - "@acemir/cssom": "^0.9.28", - "@asamuzakjp/dom-selector": "^6.7.6", - "cssstyle": "^5.3.4", - "data-urls": "^6.0.0", + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", + "html-encoding-sniffer": "^6.0.0", "is-potential-custom-element-name": "^1.0.1", - "parse5": "^8.0.0", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.0", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.1.0", - "ws": "^8.18.3", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", "xml-name-validator": "^5.0.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" }, "peerDependencies": { "canvas": "^3.0.0" @@ -4989,23 +5422,12 @@ } } }, - "node_modules/jsdom/node_modules/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", - "dev": true, - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -5017,31 +5439,29 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -5049,11 +5469,19 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -5063,6 +5491,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5072,6 +5501,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -5081,10 +5511,11 @@ } }, "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" }, @@ -5098,6 +5529,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -5112,19 +5544,15 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -5136,22 +5564,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.0.tgz", + "integrity": "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, "node_modules/make-dir": { @@ -5159,6 +5578,7 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -5174,6 +5594,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -5183,53 +5604,61 @@ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/mathjs": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-9.5.2.tgz", - "integrity": "sha512-c0erTq0GP503/Ch2OtDOAn50GIOsuxTMjmE00NI/vKJFSWrDaQHRjx6ai+16xYv70yBSnnpUgHZGNf9FR9IwmA==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.2.0.tgz", + "integrity": "sha512-UAQzSVob9rNLdGpqcFMYmSu9dkuLYy7Lr2hBEQS5SHQdknA9VppJz3cy2KkpMzTODunad6V6cNv+5kOLsePLow==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.15.4", - "complex.js": "^2.0.15", - "decimal.js": "^10.3.1", + "@babel/runtime": "^7.26.10", + "complex.js": "^2.2.5", + "decimal.js": "^10.4.3", "escape-latex": "^1.2.0", - "fraction.js": "^4.1.1", + "fraction.js": "^5.2.1", "javascript-natural-sort": "^0.7.1", "seedrandom": "^3.0.5", "tiny-emitter": "^2.1.0", - "typed-function": "^2.0.0" + "typed-function": "^4.2.1" }, "bin": { "mathjs": "bin/cli.js" }, "engines": { - "node": ">= 12" + "node": ">= 18" } }, "node_modules/mdn-data": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", - "dev": true + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -5238,22 +5667,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, - "engines": { - "node": ">= 0.6" - } + "license": "MIT" }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -5275,40 +5697,114 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, + "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mocha": { + "version": "11.7.6", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.6.tgz", + "integrity": "sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/mocha/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { "version": "9.0.9", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", @@ -5324,101 +5820,19 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/mustache": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", "dev": true, + "license": "MIT", "bin": { "mustache": "bin/mustache" } @@ -5427,13 +5841,15 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5442,19 +5858,22 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", "dev": true, + "license": "MIT", "dependencies": { "process-on-spawn": "^1.0.0" }, @@ -5463,9 +5882,9 @@ } }, "node_modules/node-pty": { - "version": "1.2.0-beta.9", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.2.0-beta.9.tgz", - "integrity": "sha512-XR3x/4OQZ7DlceespOQ99kk9jZHwmO78RuEIZtGsSPdsDi11s79VcK04aqcaK3x09Y6ORJM/KBz/oQ/p+WGRLg==", + "version": "1.2.0-beta.13", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.2.0-beta.13.tgz", + "integrity": "sha512-ZbbJ7aJdmvRA53bw30D6YSJJKqo1IXTojD0kJeHZ/xZIxr7p1DCmvOmrOnjUo/rn1z4MDwKQGpx0C7K+cRKETw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -5474,25 +5893,21 @@ } }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "version": "2.0.45", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.45.tgz", + "integrity": "sha512-iIbHXV9eBB2nB0wa7oTsrrXq+qQt+9SIlx9AX3T96YgobtEQfis5n6TJ6vV+3QP8DwdriEAcGhARaFCu37peBg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, "node_modules/nyc": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", - "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-18.0.0.tgz", + "integrity": "sha512-G5UyHinFkB1BxqGTrmZdB6uIYH0+v7ZnVssuflUDi+J+RhKWyAhRT1RCehBSI6jLFLuUUgFDyLt49mUtdO1XeQ==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", @@ -5503,11 +5918,11 @@ "find-up": "^4.1.0", "foreground-child": "^3.3.0", "get-package-type": "^0.1.0", - "glob": "^7.1.6", + "glob": "^13.0.6", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-hook": "^3.0.0", "istanbul-lib-instrument": "^6.0.2", - "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-processinfo": "^3.0.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", @@ -5516,27 +5931,27 @@ "p-map": "^3.0.0", "process-on-spawn": "^1.0.0", "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", + "rimraf": "^6.1.3", "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", + "spawn-wrap": "^3.0.0", + "test-exclude": "^8.0.0", "yargs": "^15.0.2" }, "bin": { "nyc": "bin/nyc.js" }, "engines": { - "node": ">=18" + "node": "20 || >=22" } }, - "node_modules/nyc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/nyc/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/nyc/node_modules/cliui": { @@ -5544,17 +5959,26 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, + "node_modules/nyc/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, "node_modules/nyc/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -5564,21 +5988,18 @@ } }, "node_modules/nyc/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5589,6 +6010,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -5596,24 +6018,12 @@ "node": ">=8" } }, - "node_modules/nyc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/nyc/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -5629,6 +6039,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -5636,11 +6047,54 @@ "node": ">=8" } }, - "node_modules/nyc/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/nyc/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { "node": ">=8" } @@ -5650,6 +6104,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5663,13 +6118,15 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/nyc/node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -5692,6 +6149,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -5700,11 +6158,19 @@ "node": ">=6" } }, + "node_modules/object-deep-merge": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-2.0.1.tgz", + "integrity": "sha512-aKttDKcU3pyZqKcCkDhsMn70WmZFG2JGDQLP9EcLyTSIFQRCPWLAmBZRLJnrVUrhPG1jETEEbfdgbNtJf1LyMg==", + "dev": true, + "license": "MIT" + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5717,6 +6183,7 @@ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -5729,17 +6196,16 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/opentype.js": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-0.8.0.tgz", - "integrity": "sha512-FQHR4oGP+a0m/f6yHoRpBOIbn/5ZWxKd4D/djHVJu8+KpBTYrJda0b7mLcgDEMWXE9xBCJm+qb0yv6FcvPjukg==", - "dependencies": { - "tiny-inflate": "^1.0.2" - }, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-2.0.0.tgz", + "integrity": "sha512-kCyjv6xdDY1W/jLWZ/L3QhhTlKUqDZMQ5+Jdlw12b3dXkKNpYBqqlMMj0YDQPShWFTMwgZI1hG14kN3XUDSg/A==", + "license": "MIT", "bin": { "ot": "bin/ot" } @@ -5749,6 +6215,7 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -5761,11 +6228,92 @@ "node": ">= 0.8.0" } }, + "node_modules/oxlint": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.67.0.tgz", + "integrity": "sha512-blwwaHPdoH8piQ5/z0KHeoHFR7FZgl12WluKJfu4qFLPkZl6mK04PkLE45Fw1NxfBRSlh40Gu7MkxHUw++ociQ==", + "dev": true, + "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.67.0", + "@oxlint/binding-android-arm64": "1.67.0", + "@oxlint/binding-darwin-arm64": "1.67.0", + "@oxlint/binding-darwin-x64": "1.67.0", + "@oxlint/binding-freebsd-x64": "1.67.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.67.0", + "@oxlint/binding-linux-arm-musleabihf": "1.67.0", + "@oxlint/binding-linux-arm64-gnu": "1.67.0", + "@oxlint/binding-linux-arm64-musl": "1.67.0", + "@oxlint/binding-linux-ppc64-gnu": "1.67.0", + "@oxlint/binding-linux-riscv64-gnu": "1.67.0", + "@oxlint/binding-linux-riscv64-musl": "1.67.0", + "@oxlint/binding-linux-s390x-gnu": "1.67.0", + "@oxlint/binding-linux-x64-gnu": "1.67.0", + "@oxlint/binding-linux-x64-musl": "1.67.0", + "@oxlint/binding-openharmony-arm64": "1.67.0", + "@oxlint/binding-win32-arm64-msvc": "1.67.0", + "@oxlint/binding-win32-ia32-msvc": "1.67.0", + "@oxlint/binding-win32-x64-msvc": "1.67.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=0.22.1", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/oxlint-plugin-eslint": { + "version": "1.67.0", + "resolved": "https://registry.npmjs.org/oxlint-plugin-eslint/-/oxlint-plugin-eslint-1.67.0.tgz", + "integrity": "sha512-MfpO9t/l/1qWVKym4sTkz0bhErAkUn/cOOQsFegI5ngQkR1cZEp6G23FKIhGcALoYytPBRmu47yjiEa6XWFBRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/oxlint-tsgolint": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/oxlint-tsgolint/-/oxlint-tsgolint-0.23.0.tgz", + "integrity": "sha512-3mBv3CoPbh8dFbzfDGIWa2ytZjn2v+3EX4aKRXjIhsoGFzG8GCjfRirz3rwZf1wYbZzsNLTSgpw8VjQuWdp/jA==", + "dev": true, + "license": "MIT", + "bin": { + "tsgolint": "bin/tsgolint.js" + }, + "optionalDependencies": { + "@oxlint-tsgolint/darwin-arm64": "0.23.0", + "@oxlint-tsgolint/darwin-x64": "0.23.0", + "@oxlint-tsgolint/linux-arm64": "0.23.0", + "@oxlint-tsgolint/linux-x64": "0.23.0", + "@oxlint-tsgolint/win32-arm64": "0.23.0", + "@oxlint-tsgolint/win32-x64": "0.23.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -5781,6 +6329,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -5796,6 +6345,7 @@ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", "dev": true, + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -5808,6 +6358,7 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5817,6 +6368,7 @@ "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", "dev": true, + "license": "ISC", "dependencies": { "graceful-fs": "^4.1.15", "hasha": "^5.0.0", @@ -5827,29 +6379,26 @@ "node": ">=8" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } + "license": "(MIT AND Zlib)" }, "node_modules/parse-imports-exports": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", "dev": true, + "license": "MIT", "dependencies": { "parse-statements": "1.0.11" } @@ -5858,15 +6407,17 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", "dev": true, + "license": "MIT", "dependencies": { - "entities": "^6.0.0" + "entities": "^8.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -5877,6 +6428,7 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5886,24 +6438,17 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5912,35 +6457,50 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.4", @@ -5960,6 +6520,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -5972,6 +6533,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -5985,6 +6547,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -5997,6 +6560,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -6012,6 +6576,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -6020,12 +6585,13 @@ } }, "node_modules/playwright": { - "version": "1.57.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz", - "integrity": "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==", + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.57.0" + "playwright-core": "1.60.0" }, "bin": { "playwright": "cli.js" @@ -6038,10 +6604,11 @@ } }, "node_modules/playwright-core": { - "version": "1.57.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0.tgz", - "integrity": "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==", + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", "dev": true, + "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, @@ -6049,25 +6616,12 @@ "node": ">=18" } }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -6077,6 +6631,7 @@ "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", "dev": true, + "license": "MIT", "dependencies": { "fromentries": "^1.2.0" }, @@ -6099,6 +6654,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -6107,29 +6663,20 @@ "node": ">= 0.10" } }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6142,74 +6689,57 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", + "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">= 14.18.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, + "license": "MIT", "dependencies": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/release-zalgo": { @@ -6217,6 +6747,7 @@ "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", "dev": true, + "license": "ISC", "dependencies": { "es6-error": "^4.0.1" }, @@ -6229,6 +6760,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6238,6 +6770,7 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6246,14 +6779,30 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/reserved-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/reserved-identifiers/-/reserved-identifiers-1.2.0.tgz", + "integrity": "sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, + "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" @@ -6273,6 +6822,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -6280,82 +6830,86 @@ "node": ">=8" } }, - "node_modules/resolve-cwd/node_modules/resolve-from": { + "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "glob": "^7.1.3" + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/rimraf/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" } }, "node_modules/rxjs": { @@ -6368,37 +6922,19 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, + "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" }, @@ -6411,6 +6947,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -6426,10 +6963,11 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -6446,6 +6984,7 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -6457,19 +6996,22 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/seedrandom": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -6478,85 +7020,82 @@ } }, "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz", + "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==", "dev": true, - "dependencies": { - "randombytes": "^2.1.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" } }, "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dev": true, + "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -6569,6 +7108,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -6581,6 +7121,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6603,6 +7144,7 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -6618,13 +7160,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -6638,6 +7181,7 @@ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -6656,6 +7200,7 @@ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, + "license": "MIT", "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -6671,22 +7216,31 @@ } }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/sixel": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/sixel/-/sixel-0.16.0.tgz", "integrity": "sha512-xicu6Y6Cyhmv5rjyHxq2r5RnKerlL/nyZEGjOU5bLCshXkZryc9JFJThTCKPOAtWXCfeWquEKFVFfMPcTD25PA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -6696,29 +7250,30 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-loader": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", - "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", "dev": true, + "license": "MIT", "dependencies": { - "abab": "^2.0.5", "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.0.0" + "webpack": "^5.72.1" } }, "node_modules/source-map-loader/node_modules/iconv-lite": { @@ -6726,6 +7281,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -6738,21 +7294,24 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-3.0.0.tgz", + "integrity": "sha512-z+s5vv4KzFPJVddGab0xX2n7kQPGMdNUX5l9T8EJqsXdKTWpcxmAqWHpsgHEXoC1taGBCc7b79bi62M5kdbrxQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { + "cross-spawn": "^7.0.6", "foreground-child": "^2.0.0", "is-windows": "^1.0.2", "make-dir": "^3.0.0", - "rimraf": "^3.0.0", + "rimraf": "^6.1.3", "signal-exit": "^3.0.2", "which": "^2.0.1" }, @@ -6765,6 +7324,7 @@ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^3.0.2" @@ -6773,48 +7333,80 @@ "node": ">=8.0.0" } }, + "node_modules/spawn-wrap/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true + "dev": true, + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "dev": true + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -6824,11 +7416,29 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -6836,11 +7446,52 @@ "node": ">=8" } }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6850,6 +7501,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -6858,15 +7510,19 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -6874,6 +7530,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6885,13 +7542,15 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -6901,10 +7560,11 @@ } }, "node_modules/terser": { - "version": "5.44.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", - "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "version": "5.47.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz", + "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -6919,15 +7579,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "engines": { @@ -6941,94 +7601,110 @@ "webpack": "^5.1.0" }, "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, "@swc/core": { "optional": true }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, "esbuild": { "optional": true }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, "uglify-js": { "optional": true } } }, "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", + "integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "glob": "^13.0.6", + "minimatch": "^10.2.2" }, "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node": "20 || >=22" } }, "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "dev": true - }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + "dev": true, + "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "dev": true, + "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -7038,28 +7714,31 @@ } }, "node_modules/tldts": { - "version": "7.0.19", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz", - "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==", + "version": "7.0.30", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.30.tgz", + "integrity": "sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==", "dev": true, + "license": "MIT", "dependencies": { - "tldts-core": "^7.0.19" + "tldts-core": "^7.0.30" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.19", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz", - "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==", - "dev": true + "version": "7.0.30", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.30.tgz", + "integrity": "sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==", + "dev": true, + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -7067,20 +7746,39 @@ "node": ">=8.0" } }, + "node_modules/to-valid-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-valid-identifier/-/to-valid-identifier-1.0.0.tgz", + "integrity": "sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/base62": "^1.0.0", + "reserved-identifiers": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/tough-cookie": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tldts": "^7.0.5" }, @@ -7093,6 +7791,7 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", "dev": true, + "license": "MIT", "dependencies": { "punycode": "^2.3.1" }, @@ -7111,10 +7810,11 @@ } }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18.12" }, @@ -7123,10 +7823,11 @@ } }, "node_modules/ts-loader": { - "version": "9.5.4", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", - "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "version": "9.5.7", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.7.tgz", + "integrity": "sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", @@ -7147,6 +7848,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 12" } @@ -7163,6 +7865,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -7170,44 +7873,57 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "dev": true, + "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/typed-function": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-2.1.0.tgz", - "integrity": "sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.2.tgz", + "integrity": "sha512-VwaXim9Gp1bngi/q3do8hgttYn2uC3MoT/gfuMWylnj1IeZBUAyPddHZlo1K05BDoj8DYPpMdiHqH1dDYdJf2A==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 18" } }, "node_modules/typedarray-to-buffer": { @@ -7215,6 +7931,7 @@ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, + "license": "MIT", "dependencies": { "is-typedarray": "^1.0.0" } @@ -7234,15 +7951,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.50.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.50.1.tgz", - "integrity": "sha512-ytTHO+SoYSbhAH9CrYnMhiLx8To6PSSvqnvXyPUgPETCvB6eBKmTI9w6XMPS3HsBRGkwTVBX+urA8dYQx6bHfQ==", + "version": "8.59.4", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.4.tgz", + "integrity": "sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.50.1", - "@typescript-eslint/parser": "8.50.1", - "@typescript-eslint/typescript-estree": "8.50.1", - "@typescript-eslint/utils": "8.50.1" + "@typescript-eslint/eslint-plugin": "8.59.4", + "@typescript-eslint/parser": "8.59.4", + "@typescript-eslint/typescript-estree": "8.59.4", + "@typescript-eslint/utils": "8.59.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7252,21 +7970,33 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/undici": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" } }, "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.25.0.tgz", + "integrity": "sha512-AXNgS1Byr27fTI+2bsPEkV9CxkT8H6xNyRI68b3TatlZo3RkzlqQBLL+w7SmGPVpokjHbcuNVQUWE7FRTg+LRA==", + "dev": true, + "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -7290,6 +8020,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -7306,24 +8037,18 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -7333,6 +8058,7 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -7342,6 +8068,7 @@ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, + "license": "MIT", "dependencies": { "xml-name-validator": "^5.0.0" }, @@ -7350,10 +8077,11 @@ } }, "node_modules/watchpack": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.0.tgz", - "integrity": "sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -7367,50 +8095,51 @@ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, "node_modules/webidl-conversions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", - "integrity": "sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=20" } }, "node_modules/webpack": { - "version": "5.104.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", - "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", + "version": "5.107.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.0.tgz", + "integrity": "sha512-PSxeHk/dmLYZlnTU+vL1Gej6Evg5RNtl3flhxBresfznFnzxinHMzHKloHnywM/3ouQv7/AlZCswWDIkNSggUA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.4", - "es-module-lexer": "^2.0.0", + "enhanced-resolve": "^5.21.4", + "es-module-lexer": "^2.1.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.16", - "watchpack": "^2.4.4", - "webpack-sources": "^3.3.3" + "terser-webpack-plugin": "^5.5.0", + "watchpack": "^2.5.1", + "webpack-sources": "^3.4.1" }, "bin": { "webpack": "bin/webpack.js" @@ -7429,44 +8158,38 @@ } }, "node_modules/webpack-cli": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", - "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-7.0.2.tgz", + "integrity": "sha512-dB0R4T+C/8YuvM+fabdvil6QE44/ChDXikV5lOOkrUeCkW5hTJv2pGLE3keh+D5hjYw8icBaJkZzpFoaHV4T+g==", "dev": true, + "license": "MIT", "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "cross-spawn": "^7.0.3", + "@discoveryjs/json-ext": "^1.0.0", + "commander": "^14.0.3", + "cross-spawn": "^7.0.6", + "envinfo": "^7.14.0", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^6.0.1" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=10.13.0" + "node": ">=20.9.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x" + "webpack": "^5.101.0", + "webpack-bundle-analyzer": "^4.0.0 || ^5.0.0", + "webpack-dev-server": "^5.0.0" }, "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "@webpack-cli/migrate": { - "optional": true - }, "webpack-bundle-analyzer": { "optional": true }, @@ -7476,33 +8199,36 @@ } }, "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=20" } }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", - "wildcard": "^2.0.0" + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.4.1.tgz", + "integrity": "sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } @@ -7512,6 +8238,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -7525,54 +8252,34 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/whatwg-url": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", - "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", "dev": true, + "license": "MIT", "dependencies": { + "@exodus/bytes": "^1.11.0", "tr46": "^6.0.0", - "webidl-conversions": "^8.0.0" + "webidl-conversions": "^8.0.1" }, "engines": { - "node": ">=20" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/which": { @@ -7580,6 +8287,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -7594,34 +8302,58 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -7634,17 +8366,77 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", @@ -7652,11 +8444,19 @@ "typedarray-to-buffer": "^3.1.5" } }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -7678,6 +8478,7 @@ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18" } @@ -7686,65 +8487,36 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/xterm-benchmark": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/xterm-benchmark/-/xterm-benchmark-0.3.1.tgz", - "integrity": "sha512-JjsCrSxkYKWf5CmBt2BeXm83KQdStyoGWREWQ0jSFF5N8CYVbdKQoWgs56mmy6qWD5GDKxO+V89Cvnbc8YUFjw==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/xterm-benchmark/-/xterm-benchmark-0.3.2.tgz", + "integrity": "sha512-Z9FFAhG6lGMm7j7MRmOCMIbR+KYxS9FhxYef68n+xJcUSV5dMV0dHRcMOINhS63IGpHGsoE9tPqZUJBtgLu/1Q==", "dev": true, + "license": "MIT", "dependencies": { - "@types/app-root-path": "^1.2.4", - "@types/cli-table": "^0.3.0", - "@types/mathjs": "^6.0.11", - "@types/mocha": "^8.2.1", - "@types/node": "^12.12.37", - "@types/puppeteer": "^5.4.3", - "app-root-path": "^3.0.0", - "cli-table": "^0.3.6", - "columnify": "^1.5.4", + "app-root-path": "^3.1.0", + "cli-table": "^0.3.11", + "columnify": "^1.6.0", "commander": "^6.2.1", - "mathjs": "^9.3.0", - "typescript": "^4.2.3" + "mathjs": "^15.2.0" }, "bin": { "xterm-benchmark": "lib/cli.js" } }, - "node_modules/xterm-benchmark/node_modules/@types/mocha": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", - "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", - "dev": true - }, - "node_modules/xterm-benchmark/node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true - }, "node_modules/xterm-benchmark/node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, - "node_modules/xterm-benchmark/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/xterm-wasm-parts": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/xterm-wasm-parts/-/xterm-wasm-parts-0.4.1.tgz", @@ -7760,6 +8532,7 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -7768,33 +8541,36 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-unparser": { @@ -7802,6 +8578,7 @@ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", @@ -7817,6 +8594,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7829,6 +8607,7 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7836,18 +8615,49 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yauzl": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.2.1.tgz", - "integrity": "sha512-k1isifdbpNSFEHFJ1ZY4YDewv0IH9FR61lDetaRMD3j2ae3bIXGV+7c+LHCqtQGofSd8PIyV4X6+dHMAnSr60A==", + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "buffer-crc32": "~0.2.3", - "pend": "~1.2.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=12" + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/yocto-queue": { @@ -7855,6 +8665,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 9590e8a12..cb7d146f0 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,9 @@ "workspaces": [ "addons/*" ], + "overrides": { + "serialize-javascript": "^7.0.3" + }, "keywords": [ "cli", "command-line", @@ -48,11 +51,11 @@ "esbuild-demo-server-watch": "node bin/esbuild.mjs --demo-server --watch", "test": "npm run test-unit", "posttest": "npm run lint", - "lint": "eslint --max-warnings 0 src/ addons/ demo/ test/", + "lint": "oxlint --type-aware --max-warnings 0 src addons demo test && eslint --config eslint.config.naming.mjs --max-warnings 0 src addons demo test", "lint-changes": "node ./bin/lint_changes.js", "lint-changes-fix": "node ./bin/lint_changes.js --fix", - "lint-fix": "eslint --fix src/ addons/ demo/ test/", - "lint-api": "eslint --config eslint.config.typings.mjs --max-warnings 0 typings/", + "lint-fix": "oxlint --type-aware --fix --max-warnings 0 src addons demo test", + "lint-api": "oxlint --max-warnings 0 -c .oxlintrc.typings.json typings && eslint --config eslint.config.naming.mjs --max-warnings 0 typings", "test-unit": "node ./bin/test_unit.js", "test-unit-slow-tests": "npm run test-unit | grep \"ms)\"", "test-unit-coverage": "node ./bin/test_unit.js --coverage", @@ -75,40 +78,45 @@ "prepublishOnly": "npm run package" }, "devDependencies": { + "@eslint/js": "^10.0.1", "@lunapaint/png-codec": "^0.2.0", - "@playwright/test": "^1.57.0", - "@stylistic/eslint-plugin": "^4.4.1", - "@types/chai": "^4.2.22", - "@types/express": "4", + "@playwright/test": "^1.59.1", + "@stylistic/eslint-plugin": "^5.10.0", + "@types/chai": "^5.2.3", + "@types/express": "^5.0.6", "@types/express-ws": "^3.0.1", - "@types/jsdom": "^27.0.0", - "@types/mocha": "^9.0.0", + "@types/jsdom": "^28.0.1", + "@types/mocha": "^10.0.10", "@types/node": "^22.19.3", "@types/webpack": "^5.28.0", "@types/ws": "^8.2.0", - "@typescript-eslint/eslint-plugin": "^8.50.1", - "@typescript-eslint/parser": "^8.50.1", - "@typescript/native-preview": "^7.0.0-dev.20260213.1", - "chai": "^4.3.4", + "@typescript-eslint/eslint-plugin": "^8.59.2", + "@typescript-eslint/parser": "^8.59.2", + "@typescript/native-preview": "^7.0.0-dev.20260509.2", + "chai": "^6.2.2", "concurrently": "^9.1.2", - "esbuild": "~0.25.2", - "eslint": "^9.39.2", - "eslint-plugin-jsdoc": "^50.8.0", - "express": "^4.19.2", + "esbuild": "^0.28.0", + "eslint": "^10.3.0", + "eslint-plugin-jsdoc": "^62.9.0", + "eslint-plugin-oxlint": "^1.67.0", + "express": "^5.2.1", "express-ws": "^5.0.2", - "jsdom": "^27.3.0", - "mocha": "^10.1.0", + "jsdom": "^29.1.1", + "mocha": "^11.7.5", "mustache": "^4.2.0", "node-pty": "^1.2.0-beta.9", - "nyc": "^17.1.0", - "source-map-loader": "^3.0.0", + "nyc": "^18.0.0", + "oxlint": "^1.67.0", + "oxlint-plugin-eslint": "^1.67.0", + "oxlint-tsgolint": "^0.23.0", + "source-map-loader": "^5.0.0", "source-map-support": "^0.5.20", - "ts-loader": "^9.3.1", + "ts-loader": "^9.5.7", "typescript": "^5.9.3", - "typescript-eslint": "^8.50.1", - "webpack": "^5.61.0", - "webpack-cli": "^4.9.1", - "ws": "^8.2.3", - "xterm-benchmark": "^0.3.1" + "typescript-eslint": "^8.59.2", + "webpack": "^5.106.2", + "webpack-cli": "^7.0.2", + "ws": "^8.20.0", + "xterm-benchmark": "^0.3.2" } } diff --git a/src/browser/AccessibilityManager.ts b/src/browser/AccessibilityManager.ts index 6fc421337..04b969afe 100644 --- a/src/browser/AccessibilityManager.ts +++ b/src/browser/AccessibilityManager.ts @@ -3,14 +3,14 @@ * @license MIT */ -import * as Strings from 'browser/LocalizableStrings'; -import { ITerminal, IRenderDebouncer } from 'browser/Types'; -import { TimeBasedDebouncer } from 'browser/TimeBasedDebouncer'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { ICoreBrowserService, IRenderService } from 'browser/services/Services'; -import { IBuffer } from 'common/buffer/Types'; -import { IInstantiationService } from 'common/services/Services'; -import { addDisposableListener } from 'browser/Dom'; +import * as Strings from './LocalizableStrings'; +import { ITerminal, IRenderDebouncer } from './Types'; +import { TimeBasedDebouncer } from './TimeBasedDebouncer'; +import { Disposable, toDisposable } from '../common/Lifecycle'; +import { ICoreBrowserService, IRenderService } from './services/Services'; +import { IBuffer } from '../common/buffer/Types'; +import { IInstantiationService } from '../common/services/Services'; +import { addDisposableListener } from './Dom'; const enum Constants { MAX_ROWS_TO_READ = 20 diff --git a/src/browser/Clipboard.test.ts b/src/browser/Clipboard.test.ts index 2028504ec..cd61e4b8d 100644 --- a/src/browser/Clipboard.test.ts +++ b/src/browser/Clipboard.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import * as Clipboard from 'browser/Clipboard'; +import * as Clipboard from './Clipboard'; describe('evaluatePastedTextProcessing', () => { it('should replace carriage return and/or line feed with carriage return', () => { diff --git a/src/browser/Clipboard.ts b/src/browser/Clipboard.ts index aaf8a48e4..3a7ae14ab 100644 --- a/src/browser/Clipboard.ts +++ b/src/browser/Clipboard.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { ISelectionService } from 'browser/services/Services'; -import { ICoreService, IOptionsService } from 'common/services/Services'; +import { ISelectionService } from './services/Services'; +import { ICoreService, IOptionsService } from '../common/services/Services'; /** * Prepares text to be pasted into the terminal by normalizing the line endings diff --git a/src/browser/ColorContrastCache.test.ts b/src/browser/ColorContrastCache.test.ts index 17e5df383..f3d437ee8 100644 --- a/src/browser/ColorContrastCache.test.ts +++ b/src/browser/ColorContrastCache.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { ColorContrastCache } from 'browser/ColorContrastCache'; +import { ColorContrastCache } from './ColorContrastCache'; describe('ColorContrastCache', () => { let cache: ColorContrastCache; diff --git a/src/browser/ColorContrastCache.ts b/src/browser/ColorContrastCache.ts index 0c60e8db4..fdcd9d133 100644 --- a/src/browser/ColorContrastCache.ts +++ b/src/browser/ColorContrastCache.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { IColorContrastCache } from 'browser/Types'; -import { IColor } from 'common/Types'; -import { TwoKeyMap } from 'common/MultiKeyMap'; +import { IColorContrastCache } from './Types'; +import { IColor } from '../common/Types'; +import { TwoKeyMap } from '../common/MultiKeyMap'; export class ColorContrastCache implements IColorContrastCache { private _color: TwoKeyMap = new TwoKeyMap(); diff --git a/src/browser/CoreBrowserTerminal.ts b/src/browser/CoreBrowserTerminal.ts index 52eb00025..4557e1652 100644 --- a/src/browser/CoreBrowserTerminal.ts +++ b/src/browser/CoreBrowserTerminal.ts @@ -22,43 +22,43 @@ */ import { IDecoration, IDecorationOptions, IDisposable, ILinkProvider, IMarker, IRenderDimensions as IRenderDimensionsApi } from '@xterm/xterm'; -import { copyHandler, handlePasteEvent, moveTextAreaUnderMouseCursor, paste, rightClickHandler } from 'browser/Clipboard'; -import * as Strings from 'browser/LocalizableStrings'; -import { OscLinkProvider } from 'browser/OscLinkProvider'; -import { CharacterJoinerHandler, CustomKeyEventHandler, CustomWheelEventHandler, IBrowser, IBufferRange, ICompositionHelper, ILinkifier2, ITerminal } from 'browser/Types'; -import { Viewport } from 'browser/Viewport'; -import { BufferDecorationRenderer } from 'browser/decorations/BufferDecorationRenderer'; -import { OverviewRulerRenderer } from 'browser/decorations/OverviewRulerRenderer'; -import { CompositionHelper } from 'browser/input/CompositionHelper'; -import { DomRenderer } from 'browser/renderer/dom/DomRenderer'; -import { IRenderer } from 'browser/renderer/shared/Types'; -import { CharSizeService } from 'browser/services/CharSizeService'; -import { CharacterJoinerService } from 'browser/services/CharacterJoinerService'; -import { CoreBrowserService } from 'browser/services/CoreBrowserService'; -import { LinkProviderService } from 'browser/services/LinkProviderService'; -import { MouseCoordsService } from 'browser/services/MouseCoordsService'; -import { MouseService } from 'browser/services/MouseService'; -import { RenderService } from 'browser/services/RenderService'; -import { SelectionService } from 'browser/services/SelectionService'; -import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IKeyboardService, ILinkProviderService, IMouseCoordsService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services'; -import { ThemeService } from 'browser/services/ThemeService'; -import { KeyboardService } from 'browser/services/KeyboardService'; -import { channels, color, rgb } from 'common/Color'; -import { CoreTerminal } from 'common/CoreTerminal'; -import * as Browser from 'common/Platform'; -import { ColorRequestType, IColorEvent, ITerminalOptions, KeyboardResultType, SpecialColorIndex } from 'common/Types'; -import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { IBuffer } from 'common/buffer/Types'; -import { C0, C1ESCAPED } from 'common/data/EscapeSequences'; -import { toRgbString } from 'common/input/XParseColor'; -import { DecorationService } from 'common/services/DecorationService'; -import { IDecorationService } from 'common/services/Services'; +import { copyHandler, handlePasteEvent, moveTextAreaUnderMouseCursor, paste, rightClickHandler } from './Clipboard'; +import * as Strings from './LocalizableStrings'; +import { OscLinkProvider } from './OscLinkProvider'; +import { CharacterJoinerHandler, CustomKeyEventHandler, CustomWheelEventHandler, IBrowser, IBufferRange, ICompositionHelper, ILinkifier2, ITerminal } from './Types'; +import { Viewport } from './Viewport'; +import { BufferDecorationRenderer } from './decorations/BufferDecorationRenderer'; +import { OverviewRulerRenderer } from './decorations/OverviewRulerRenderer'; +import { CompositionHelper } from './input/CompositionHelper'; +import { DomRenderer } from './renderer/dom/DomRenderer'; +import { IRenderer } from './renderer/shared/Types'; +import { CharSizeService } from './services/CharSizeService'; +import { CharacterJoinerService } from './services/CharacterJoinerService'; +import { CoreBrowserService } from './services/CoreBrowserService'; +import { LinkProviderService } from './services/LinkProviderService'; +import { MouseCoordsService } from './services/MouseCoordsService'; +import { MouseEventCssClasses, MouseService } from './services/MouseService'; +import { RenderService } from './services/RenderService'; +import { SelectionService } from './services/SelectionService'; +import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IKeyboardService, ILinkProviderService, IMouseCoordsService, IMouseService, IRenderService, ISelectionService, IThemeService } from './services/Services'; +import { ThemeService } from './services/ThemeService'; +import { KeyboardService } from './services/KeyboardService'; +import { channels, color, rgb } from '../common/Color'; +import { CoreTerminal } from '../common/CoreTerminal'; +import * as Browser from '../common/Platform'; +import { ColorRequestType, IColorEvent, ITerminalOptions, KeyboardResultType, SpecialColorIndex } from '../common/Types'; +import { DEFAULT_ATTR_DATA } from '../common/buffer/BufferLine'; +import { IBuffer } from '../common/buffer/Types'; +import { C0, C1ESCAPED } from '../common/data/EscapeSequences'; +import { toRgbString } from '../common/input/XParseColor'; +import { DecorationService } from '../common/services/DecorationService'; +import { IDecorationService } from '../common/services/Services'; import { WindowsOptionsReportType } from '../common/InputHandler'; import { AccessibilityManager } from './AccessibilityManager'; import { Linkifier } from './Linkifier'; -import { Emitter, EventUtils, type IEvent } from 'common/Event'; -import { addDisposableListener } from 'browser/Dom'; -import { MutableDisposable, toDisposable } from 'common/Lifecycle'; +import { Emitter, EventUtils, type IEvent } from '../common/Event'; +import { addDisposableListener } from './Dom'; +import { MutableDisposable, toDisposable } from '../common/Lifecycle'; export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { public textarea: HTMLTextAreaElement | undefined; @@ -102,7 +102,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { private _keyDownHandled: boolean = false; /** - * Records whether a keydown event has occured since the last keyup event, i.e. whether a key + * Records whether a keydown event has occurred since the last keyup event, i.e. whether a key * is currently "pressed". */ private _keyDownSeen: boolean = false; @@ -212,7 +212,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { if (!this._themeService) return; for (const req of event) { let acc: 'foreground' | 'background' | 'cursor' | 'ansi'; - let ident = ''; + let ident: string; switch (req.index) { case SpecialColorIndex.FOREGROUND: // OSC 10 | 110 acc = 'foreground'; @@ -505,7 +505,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this.textarea, parent.ownerDocument.defaultView ?? window, // Force unsafe null in node.js environment for tests - this._document ?? (typeof window !== 'undefined') ? window.document : null as any + this._document ?? ((typeof window !== 'undefined') ? window.document : null as any) )); this._instantiationService.setService(ICoreBrowserService, this._coreBrowserService); @@ -563,8 +563,9 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { try { this._onWillOpen.fire(this.element); + } catch (e) { + this._logService.error('onWillOpen handler threw an exception', e); } - catch { /* fails to load addon for some reason */ } if (!this._renderService.hasRenderer()) { this._renderService.setRenderer(this._createRenderer()); } @@ -617,11 +618,12 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { this._register(addDisposableListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService!.handleMouseDown(e))); // apply mouse event classes set by escape codes before terminal was attached - if (this.mouseStateService.areMouseEventsActive) { + if (this.mouseStateService.areMouseEventsActive && !this.options.mouseEventsRequireAlt) { this._selectionService.disable(); - this.element.classList.add('enable-mouse-events'); + this.element.classList.add(MouseEventCssClasses.ENABLE_MOUSE_EVENTS); } else { this._selectionService.enable(); + this.element.classList.remove(MouseEventCssClasses.ENABLE_MOUSE_EVENTS); } if (this.options.screenReaderMode) { @@ -1070,10 +1072,6 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { * Clear the entire buffer, making the prompt line the new first line. */ public clear(): void { - if (this.buffer.ybase === 0 && this.buffer.y === 0) { - // Don't clear if it's already clear - return; - } this.buffer.clearAllMarkers(); this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y)!); this.buffer.lines.length = 1; diff --git a/src/browser/Dom.ts b/src/browser/Dom.ts index 56e7c0417..4d174270b 100644 --- a/src/browser/Dom.ts +++ b/src/browser/Dom.ts @@ -5,8 +5,8 @@ * Minimal DOM helpers for xterm.js browser code. */ -import { IntervalTimer } from 'common/Async'; -import { IDisposable } from 'common/Lifecycle'; +import { IntervalTimer } from '../common/Async'; +import { IDisposable } from '../common/Lifecycle'; export function getWindow(e: Node | UIEvent | undefined | null): Window { const candidateNode = e as Node | undefined | null; diff --git a/src/browser/Linkifier.test.ts b/src/browser/Linkifier.test.ts index 4294ef105..5f8b07531 100644 --- a/src/browser/Linkifier.test.ts +++ b/src/browser/Linkifier.test.ts @@ -4,11 +4,11 @@ */ import { assert } from 'chai'; -import { IBufferService } from 'common/services/Services'; +import { IBufferService } from '../common/services/Services'; import { Linkifier } from './Linkifier'; -import { MockBufferService } from 'common/TestUtils.test'; -import { ILink } from 'browser/Types'; -import { LinkProviderService } from 'browser/services/LinkProviderService'; +import { MockBufferService } from '../common/TestUtils.test'; +import { ILink } from './Types'; +import { LinkProviderService } from './services/LinkProviderService'; import jsdom = require('jsdom'); class TestLinkifier2 extends Linkifier { @@ -43,6 +43,20 @@ describe('Linkifier2', () => { }, activate: () => { } }; + const multiLineLink: ILink = { + text: 'foo', + range: { + start: { + x: 2, + y: 1 + }, + end: { + x: 4, + y: 2 + } + }, + activate: () => { } + }; beforeEach(() => { const dom = new jsdom.JSDOM(); @@ -86,4 +100,30 @@ describe('Linkifier2', () => { linkifier.linkLeave({ classList: { add: () => { } } } as any, link, {} as any); }); + it('onShowLinkUnderline event range is correct for wrapped links', done => { + linkifier.onShowLinkUnderline(e => { + assert.equal(multiLineLink.range.start.x - 1, e.x1); + assert.equal(multiLineLink.range.start.y - 1, e.y1); + assert.equal(multiLineLink.range.end.x, e.x2); + assert.equal(multiLineLink.range.end.y - 1, e.y2); + + done(); + }); + + linkifier.linkHover({ classList: { add: () => { } } } as any, multiLineLink, {} as any); + }); + + it('onHideLinkUnderline event range is correct for wrapped links', done => { + linkifier.onHideLinkUnderline(e => { + assert.equal(multiLineLink.range.start.x - 1, e.x1); + assert.equal(multiLineLink.range.start.y - 1, e.y1); + assert.equal(multiLineLink.range.end.x, e.x2); + assert.equal(multiLineLink.range.end.y - 1, e.y2); + + done(); + }); + + linkifier.linkLeave({ classList: { add: () => { } } } as any, multiLineLink, {} as any); + }); + }); diff --git a/src/browser/Linkifier.ts b/src/browser/Linkifier.ts index 31c91daee..9581fb299 100644 --- a/src/browser/Linkifier.ts +++ b/src/browser/Linkifier.ts @@ -3,13 +3,13 @@ * @license MIT */ -import { IBufferCellPosition, ILink, ILinkDecorations, ILinkWithState, ILinkifier2, ILinkifierEvent } from 'browser/Types'; -import { Disposable, dispose, toDisposable } from 'common/Lifecycle'; -import { IDisposable } from 'common/Types'; -import { IBufferService } from 'common/services/Services'; +import { IBufferCellPosition, ILink, ILinkDecorations, ILinkWithState, ILinkifier2, ILinkifierEvent } from './Types'; +import { Disposable, dispose, toDisposable } from '../common/Lifecycle'; +import { IDisposable } from '../common/Types'; +import { IBufferService } from '../common/services/Services'; import { ILinkProviderService, IMouseCoordsService, IRenderService } from './services/Services'; -import { Emitter } from 'common/Event'; -import { addDisposableListener } from 'browser/Dom'; +import { Emitter } from '../common/Event'; +import { addDisposableListener } from './Dom'; export class Linkifier extends Disposable implements ILinkifier2 { public get currentLink(): ILinkWithState | undefined { return this._currentLink; } diff --git a/src/browser/OscLinkProvider.test.ts b/src/browser/OscLinkProvider.test.ts new file mode 100644 index 000000000..0356bcfdc --- /dev/null +++ b/src/browser/OscLinkProvider.test.ts @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { OscLinkProvider } from './OscLinkProvider'; +import { ILink } from './Types'; +import { createCellData, MockBufferService, MockOptionsService } from '../common/TestUtils.test'; +import { IBufferService, IOscLinkService } from '../common/services/Services'; +import { IOscLinkData } from '../common/Types'; +import { IBufferLine } from '../common/buffer/Types'; + +class TestOscLinkService implements IOscLinkService { + public serviceBrand: any; + public registerLink(_linkData: IOscLinkData): number { return 0; } + public addLineToLink(_linkId: number, _y: number): void { } + public getLinkData(linkId: number): IOscLinkData | undefined { + return { uri: `https://example.com/${linkId}` }; + } +} + +function setText(line: IBufferLine | undefined, x: number, text: string): void { + if (!line) { + throw new Error('Missing buffer line'); + } + for (let i = 0; i < text.length; i++) { + line.setCell(x + i, createCellData(0, text[i], 1)); + } +} + +function setUrl(line: IBufferLine | undefined, x: number, text: string, linkId: number): void { + if (!line) { + throw new Error('Missing buffer line'); + } + for (let i = 0; i < text.length; i++) { + const cell = createCellData(0, text[i], 1); + cell.extended.urlId = linkId; + cell.updateExtended(); + line.setCell(x + i, cell); + } +} + +function getLinks(provider: OscLinkProvider, y: number): Promise { + return new Promise(resolve => provider.provideLinks(y, links => resolve(links ?? []))); +} + +describe('OscLinkProvider', () => { + let bufferService: IBufferService; + let provider: OscLinkProvider; + + beforeEach(() => { + const optionsService = new MockOptionsService(); + bufferService = new MockBufferService(5, 5, optionsService); + provider = new OscLinkProvider(bufferService, optionsService, new TestOscLinkService()); + }); + + it('expands a wrapped link range backward to the previous line', async () => { + const line1 = bufferService.buffer.lines.get(0); + const line2 = bufferService.buffer.lines.get(1); + setText(line1, 0, 'aa'); + setUrl(line1, 2, 'bbb', 1); + setUrl(line2, 0, 'cccc', 1); + setText(line2, 4, 'x'); + line2!.isWrapped = true; + + const links = await getLinks(provider, 2); + assert.lengthOf(links, 1); + assert.deepEqual(links[0].range, { + start: { x: 3, y: 1 }, + end: { x: 4, y: 2 } + }); + }); + + it('expands a wrapped link range forward when a link ends at line boundary', async () => { + const line1 = bufferService.buffer.lines.get(0); + const line2 = bufferService.buffer.lines.get(1); + setUrl(line1, 0, 'aaaaa', 1); + setUrl(line2, 0, 'bb', 1); + setText(line2, 2, 'ccc'); + line2!.isWrapped = true; + + const links = await getLinks(provider, 1); + assert.lengthOf(links, 1); + assert.deepEqual(links[0].range, { + start: { x: 1, y: 1 }, + end: { x: 2, y: 2 } + }); + }); + + it('does not merge wrapped links with different url ids', async () => { + const line1 = bufferService.buffer.lines.get(0); + const line2 = bufferService.buffer.lines.get(1); + setUrl(line1, 0, 'aaaaa', 1); + setUrl(line2, 0, 'bbb', 2); + setText(line2, 3, 'cc'); + line2!.isWrapped = true; + + const links = await getLinks(provider, 1); + assert.lengthOf(links, 1); + assert.deepEqual(links[0].range, { + start: { x: 1, y: 1 }, + end: { x: 5, y: 1 } + }); + }); +}); diff --git a/src/browser/OscLinkProvider.ts b/src/browser/OscLinkProvider.ts index b6a3cce0a..9fdef1561 100644 --- a/src/browser/OscLinkProvider.ts +++ b/src/browser/OscLinkProvider.ts @@ -3,10 +3,11 @@ * @license MIT */ -import { IBufferRange, ILink } from 'browser/Types'; -import { ILinkProvider } from 'browser/services/Services'; -import { CellData } from 'common/buffer/CellData'; -import { IBufferService, IOptionsService, IOscLinkService } from 'common/services/Services'; +import { IBufferRange, ILink } from './Types'; +import { ILinkProvider } from './services/Services'; +import { CellData } from '../common/buffer/CellData'; +import { IBufferLine } from '../common/buffer/Types'; +import { IBufferService, IOptionsService, IOscLinkService } from '../common/services/Services'; export class OscLinkProvider implements ILinkProvider { private readonly _workCell = new CellData(); @@ -57,19 +58,8 @@ export class OscLinkProvider implements ILinkProvider { if (finishLink || (currentStart !== -1 && x === lineLength - 1)) { const text = this._oscLinkService.getLinkData(currentLinkId)?.uri; if (text) { - // These ranges are 1-based - const range: IBufferRange = { - start: { - x: currentStart + 1, - y - }, - end: { - // Offset end x if it's a link that ends on the last cell in the line - x: x + (!finishLink && x === lineLength - 1 ? 1 : 0), - y - } - }; - + const endX = x + (!finishLink && x === lineLength - 1 ? 1 : 0); + const range = this._getRangeWithLineWrap(y, currentStart, endX, currentLinkId); let ignoreLink = false; if (!linkHandler?.allowNonHttpProtocols) { try { @@ -111,6 +101,82 @@ export class OscLinkProvider implements ILinkProvider { // id callback(result); } + + /** + * Expand a single-line OSC 8 range to a contiguous wrapped range for the same link id. + */ + private _getRangeWithLineWrap(y: number, startX: number, endX: number, linkId: number): IBufferRange { + let startY = y; + let finalStartX = startX; + let endY = y; + let finalEndX = endX; + + // Expand upward only when this segment starts at column 0 and the current line is wrapped. + while (finalStartX === 0) { + const currentLine = this._bufferService.buffer.lines.get(startY - 1); + if (!currentLine?.isWrapped) { + break; + } + const previousLine = this._bufferService.buffer.lines.get(startY - 2); + if (!previousLine) { + break; + } + const previousLineLength = previousLine.getTrimmedLength(); + if (previousLineLength === 0 || !this._hasUrlId(previousLine, previousLineLength - 1, linkId)) { + break; + } + let previousStartX = previousLineLength - 1; + while (previousStartX > 0 && this._hasUrlId(previousLine, previousStartX - 1, linkId)) { + previousStartX--; + } + startY--; + finalStartX = previousStartX; + } + + // Expand downward only when this segment reaches trimmed EOL and the next line is wrapped. + while (true) { + const currentLine = this._bufferService.buffer.lines.get(endY - 1); + if (!currentLine) { + break; + } + const currentLineLength = currentLine.getTrimmedLength(); + if (finalEndX !== currentLineLength) { + break; + } + const nextLine = this._bufferService.buffer.lines.get(endY); + if (!nextLine?.isWrapped) { + break; + } + const nextLineLength = nextLine.getTrimmedLength(); + if (nextLineLength === 0 || !this._hasUrlId(nextLine, 0, linkId)) { + break; + } + let nextEndX = 1; + while (nextEndX < nextLineLength && this._hasUrlId(nextLine, nextEndX, linkId)) { + nextEndX++; + } + endY++; + finalEndX = nextEndX; + } + + // IBufferRange uses 1-based coordinates. + return { + start: { + x: finalStartX + 1, + y: startY + }, + end: { + x: finalEndX, + y: endY + } + }; + } + + private _hasUrlId(line: IBufferLine, x: number, linkId: number): boolean { + const cell = this._workCell; + line.loadCell(x, cell); + return !!cell.hasExtendedAttrs() && cell.extended.urlId === linkId; + } } function defaultActivate(e: MouseEvent, uri: string): void { diff --git a/src/browser/RenderDebouncer.ts b/src/browser/RenderDebouncer.ts index c7ddb6cec..eeadbe018 100644 --- a/src/browser/RenderDebouncer.ts +++ b/src/browser/RenderDebouncer.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { IRenderDebouncerWithCallback } from 'browser/Types'; -import { ICoreBrowserService } from 'browser/services/Services'; +import { IRenderDebouncerWithCallback } from './Types'; +import { ICoreBrowserService } from './services/Services'; /** * Debounces calls to render terminal rows using animation frames. @@ -23,7 +23,7 @@ export class RenderDebouncer implements IRenderDebouncerWithCallback { } public dispose(): void { - if (this._animationFrame) { + if (this._animationFrame !== undefined) { this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame); this._animationFrame = undefined; } @@ -31,9 +31,7 @@ export class RenderDebouncer implements IRenderDebouncerWithCallback { public addRefreshCallback(callback: FrameRequestCallback): number { this._refreshCallbacks.push(callback); - if (!this._animationFrame) { - this._animationFrame = this._coreBrowserService.window.requestAnimationFrame(() => this._innerRefresh()); - } + this._animationFrame ??= this._coreBrowserService.window.requestAnimationFrame(() => this._innerRefresh()); return this._animationFrame; } @@ -46,7 +44,7 @@ export class RenderDebouncer implements IRenderDebouncerWithCallback { this._rowStart = this._rowStart !== undefined ? Math.min(this._rowStart, rowStart) : rowStart; this._rowEnd = this._rowEnd !== undefined ? Math.max(this._rowEnd, rowEnd) : rowEnd; - if (this._animationFrame) { + if (this._animationFrame !== undefined) { return; } diff --git a/src/browser/Terminal.test.ts b/src/browser/Terminal.test.ts index d359fa28c..a98ddf865 100644 --- a/src/browser/Terminal.test.ts +++ b/src/browser/Terminal.test.ts @@ -3,13 +3,13 @@ * @license MIT */ -import { MockCompositionHelper, MockRenderer, MockViewport, TestTerminal } from 'browser/TestUtils.test'; -import type { IBrowser } from 'browser/Types'; +import { MockCompositionHelper, MockRenderer, MockViewport, TestTerminal } from './TestUtils.test'; +import type { IBrowser } from './Types'; import { assert } from 'chai'; -import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { CellData } from 'common/buffer/CellData'; -import { MockUnicodeService, createCellData } from 'common/TestUtils.test'; -import { IMarker } from 'common/Types'; +import { DEFAULT_ATTR_DATA } from '../common/buffer/BufferLine'; +import { CellData } from '../common/buffer/CellData'; +import { MockUnicodeService, createCellData } from '../common/TestUtils.test'; +import { IMarker } from '../common/buffer/Types'; const INIT_COLS = 80; const INIT_ROWS = 24; diff --git a/src/browser/Terminal2.test.ts b/src/browser/Terminal2.test.ts index 6c2b3db65..8274a47e5 100644 --- a/src/browser/Terminal2.test.ts +++ b/src/browser/Terminal2.test.ts @@ -7,14 +7,14 @@ import * as path from 'path'; import * as os from 'os'; import * as fs from 'fs'; import * as pty from 'node-pty'; -import { CoreBrowserTerminal } from 'browser/CoreBrowserTerminal'; +import { CoreBrowserTerminal } from './CoreBrowserTerminal'; import { IDisposable } from '@xterm/xterm'; // all test files expect terminal in 80x25 const COLS = 80; const ROWS = 25; -const escapeSequenceFilesDir = path.join(__dirname, '../../fixtures/escape_sequence_files'); +const escapeSequenceFilesDir = path.join(__dirname, '../../test/fixtures/escape_sequence_files'); const TESTFILES = fs.readdirSync(escapeSequenceFilesDir) .filter(f => f.endsWith('.in')) .map(f => path.join(escapeSequenceFilesDir, f)); @@ -125,7 +125,7 @@ function formatError(input: string, output: string, expected: string): string { // simple debug output of terminal cells function terminalToString(term: CoreBrowserTerminal): string { let result = ''; - let lineText = ''; + let lineText: string; for (let line = term.buffer.ybase; line < term.buffer.ybase + term.rows; line++) { lineText = term.buffer.lines.get(line)!.translateToString(true); // rtrim empty cells as xterm does diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts index 65a18da72..7b3464595 100644 --- a/src/browser/TestUtils.test.ts +++ b/src/browser/TestUtils.test.ts @@ -4,21 +4,22 @@ */ import { IDisposable, IMarker, ILinkProvider, IDecorationOptions, IDecoration, IRenderDimensions as IRenderDimensionsApi } from '@xterm/xterm'; -import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services'; -import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types'; -import { IColorSet, ITerminal, ILinkifier2, IBrowser, IViewport, ICompositionHelper, CharacterJoinerHandler, IBufferRange, ReadonlyColorSet, IBufferElementProvider } from 'browser/Types'; -import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, ICharset, ITerminalOptions, ColorIndex } from 'common/Types'; -import { Buffer } from 'common/buffer/Buffer'; -import * as Browser from 'common/Platform'; -import { CoreBrowserTerminal } from 'browser/CoreBrowserTerminal'; -import { IUnicodeService, IOptionsService, ICoreService, IMouseStateService } from 'common/services/Services'; -import { IFunctionIdentifier, IParams } from 'common/parser/Types'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { ISelectionRedrawRequestEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types'; -import { css } from 'common/Color'; -import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils'; -import { Emitter, type IEvent } from 'common/Event'; +import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IMouseService, IRenderService, ISelectionService, IThemeService } from './services/Services'; +import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from './renderer/shared/Types'; +import { IColorSet, ITerminal, ILinkifier2, IBrowser, IViewport, ICompositionHelper, CharacterJoinerHandler, IBufferRange, ReadonlyColorSet, IBufferElementProvider } from './Types'; +import { IAttributeData, IBuffer, IBufferLine, IBufferSet, ICellData } from '../common/buffer/Types'; +import { ICircularList } from '../common/CircularList'; +import { XtermListener, ICharset, ITerminalOptions, ColorIndex } from '../common/Types'; +import { Buffer } from '../common/buffer/Buffer'; +import * as Browser from '../common/Platform'; +import { CoreBrowserTerminal } from './CoreBrowserTerminal'; +import { IUnicodeService, IOptionsService, ICoreService, IMouseStateService } from '../common/services/Services'; +import { IFunctionIdentifier, IParams } from '../common/parser/Types'; +import { AttributeData } from '../common/buffer/AttributeData'; +import { ISelectionRedrawRequestEvent, ISelectionRequestScrollLinesEvent } from './selection/Types'; +import { css } from '../common/Color'; +import { createRenderDimensions } from './renderer/shared/RendererUtils'; +import { Emitter, type IEvent } from '../common/Event'; export class TestTerminal extends CoreBrowserTerminal { public get curAttrData(): IAttributeData { return (this as any)._inputHandler._curAttrData; } diff --git a/src/browser/TimeBasedDebouncer.ts b/src/browser/TimeBasedDebouncer.ts index 997312901..27b692bae 100644 --- a/src/browser/TimeBasedDebouncer.ts +++ b/src/browser/TimeBasedDebouncer.ts @@ -3,9 +3,9 @@ * @license MIT */ -const RENDER_DEBOUNCE_THRESHOLD_MS = 1000; // 1 Second +import { IRenderDebouncer } from './Types'; -import { IRenderDebouncer } from 'browser/Types'; +const RENDER_DEBOUNCE_THRESHOLD_MS = 1000; // 1 Second /** * Debounces calls to update screen readers to update at most once configurable interval of time. @@ -31,7 +31,9 @@ export class TimeBasedDebouncer implements IRenderDebouncer { public dispose(): void { if (this._refreshTimeoutID) { clearTimeout(this._refreshTimeoutID); + this._refreshTimeoutID = undefined; } + this._additionalRefreshRequested = false; } public refresh(rowStart: number | undefined, rowEnd: number | undefined, rowCount: number): void { @@ -47,7 +49,12 @@ export class TimeBasedDebouncer implements IRenderDebouncer { // enough time to pass before refreshing again. const refreshRequestTime: number = performance.now(); if (refreshRequestTime - this._lastRefreshMs >= this._debounceThresholdMS) { - // Enough time has lapsed since the last refresh; refresh immediately + // Enough time has elapsed since the last refresh; refresh immediately + if (this._refreshTimeoutID !== undefined) { + clearTimeout(this._refreshTimeoutID); + this._refreshTimeoutID = undefined; + this._additionalRefreshRequested = false; + } this._lastRefreshMs = refreshRequestTime; this._innerRefresh(); } else if (!this._additionalRefreshRequested) { diff --git a/src/browser/Types.ts b/src/browser/Types.ts index fa08de2e3..497afcf53 100644 --- a/src/browser/Types.ts +++ b/src/browser/Types.ts @@ -3,11 +3,12 @@ * @license MIT */ -import { CharData, IColor, ICoreTerminal, ITerminalOptions } from 'common/Types'; -import { IBuffer } from 'common/buffer/Types'; +import { IColor, ITerminalOptions } from '../common/Types'; +import { CharData, IBuffer } from '../common/buffer/Types'; +import { ICoreTerminal } from '../common/CoreTerminal'; import { IDisposable, IRenderDimensions as IRenderDimensionsApi, Terminal as ITerminalApi } from '@xterm/xterm'; -import { channels, css } from 'common/Color'; -import type { IEvent } from 'common/Event'; +import { channels, css } from '../common/Color'; +import type { IEvent } from '../common/Event'; /** * A portion of the public API that are implemented identially internally and simply passed through. diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 3b6ae8301..18c275ccb 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -3,16 +3,16 @@ * @license MIT */ -import { ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services'; -import { ViewportConstants } from 'browser/shared/Constants'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IBufferService, ICoreService, IMouseStateService, IOptionsService } from 'common/services/Services'; -import { CoreMouseEventType } from 'common/Types'; -import { scheduleAtNextAnimationFrame } from 'browser/Dom'; -import { SmoothScrollableElement } from 'browser/scrollable/scrollableElement'; -import type { IScrollableElementChangeOptions } from 'browser/scrollable/scrollableElementOptions'; -import { Emitter, EventUtils } from 'common/Event'; -import { Scrollable, ScrollbarVisibility, type IScrollEvent } from 'browser/scrollable/scrollable'; +import { ICoreBrowserService, IRenderService, IThemeService } from './services/Services'; +import { ViewportConstants } from './shared/Constants'; +import { Disposable, toDisposable } from '../common/Lifecycle'; +import { IBufferService, ICoreService, IMouseStateService, IOptionsService } from '../common/services/Services'; +import { CoreMouseEventType } from '../common/Types'; +import { scheduleAtNextAnimationFrame } from './Dom'; +import { SmoothScrollableElement } from './scrollable/scrollableElement'; +import type { IScrollableElementChangeOptions } from './scrollable/scrollableElementOptions'; +import { Emitter, EventUtils } from '../common/Event'; +import { Scrollable, ScrollbarVisibility, type IScrollEvent } from './scrollable/scrollable'; export class Viewport extends Disposable { diff --git a/src/browser/decorations/BufferDecorationRenderer.ts b/src/browser/decorations/BufferDecorationRenderer.ts index e374af260..fd356808e 100644 --- a/src/browser/decorations/BufferDecorationRenderer.ts +++ b/src/browser/decorations/BufferDecorationRenderer.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ICoreBrowserService, IRenderService } from 'browser/services/Services'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IBufferService, IDecorationService, IInternalDecoration } from 'common/services/Services'; +import { ICoreBrowserService, IRenderService } from '../services/Services'; +import { Disposable, toDisposable } from '../../common/Lifecycle'; +import { IBufferService, IDecorationService, IInternalDecoration } from '../../common/services/Services'; export class BufferDecorationRenderer extends Disposable { private readonly _container: HTMLElement; diff --git a/src/browser/decorations/ColorZoneStore.test.ts b/src/browser/decorations/ColorZoneStore.test.ts index 4759e3c8b..360ad6570 100644 --- a/src/browser/decorations/ColorZoneStore.test.ts +++ b/src/browser/decorations/ColorZoneStore.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { ColorZoneStore } from 'browser/decorations/ColorZoneStore'; +import { ColorZoneStore } from './ColorZoneStore'; const optionsRedFull = { overviewRulerOptions: { diff --git a/src/browser/decorations/ColorZoneStore.ts b/src/browser/decorations/ColorZoneStore.ts index d066bedb8..b63c865f8 100644 --- a/src/browser/decorations/ColorZoneStore.ts +++ b/src/browser/decorations/ColorZoneStore.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IInternalDecoration } from 'common/services/Services'; +import { IInternalDecoration } from '../../common/services/Services'; export interface IColorZoneStore { readonly zones: IColorZone[]; diff --git a/src/browser/decorations/OverviewRulerRenderer.ts b/src/browser/decorations/OverviewRulerRenderer.ts index b28b25965..2ec441bad 100644 --- a/src/browser/decorations/OverviewRulerRenderer.ts +++ b/src/browser/decorations/OverviewRulerRenderer.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ColorZoneStore, IColorZone, IColorZoneStore } from 'browser/decorations/ColorZoneStore'; -import { ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services'; +import { ColorZoneStore, IColorZone, IColorZoneStore } from './ColorZoneStore'; +import { ICoreBrowserService, IRenderService, IThemeService } from '../services/Services'; +import { Disposable, toDisposable } from '../../common/Lifecycle'; +import { IBufferService, IDecorationService, IOptionsService } from '../../common/services/Services'; const enum Constants { OVERVIEW_RULER_BORDER_WIDTH = 1 diff --git a/src/browser/input/CompositionHelper.test.ts b/src/browser/input/CompositionHelper.test.ts index 94b5841af..5a1e6c38c 100644 --- a/src/browser/input/CompositionHelper.test.ts +++ b/src/browser/input/CompositionHelper.test.ts @@ -4,9 +4,9 @@ */ import { assert } from 'chai'; -import { CompositionHelper } from 'browser/input/CompositionHelper'; -import { MockRenderService } from 'browser/TestUtils.test'; -import { MockCoreService, MockBufferService, MockOptionsService } from 'common/TestUtils.test'; +import { CompositionHelper } from './CompositionHelper'; +import { MockRenderService } from '../TestUtils.test'; +import { MockCoreService, MockBufferService, MockOptionsService } from '../../common/TestUtils.test'; describe('CompositionHelper', () => { let compositionHelper: CompositionHelper; diff --git a/src/browser/input/CompositionHelper.ts b/src/browser/input/CompositionHelper.ts index 283874139..c9ec396ab 100644 --- a/src/browser/input/CompositionHelper.ts +++ b/src/browser/input/CompositionHelper.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { IRenderService } from 'browser/services/Services'; -import { IBufferService, ICoreService, IOptionsService } from 'common/services/Services'; -import { C0 } from 'common/data/EscapeSequences'; +import { IRenderService } from '../services/Services'; +import { IBufferService, ICoreService, IOptionsService } from '../../common/services/Services'; +import { C0 } from '../../common/data/EscapeSequences'; interface IPosition { start: number; diff --git a/src/browser/input/Mouse.test.ts b/src/browser/input/Mouse.test.ts index 002603612..8333d13f8 100644 --- a/src/browser/input/Mouse.test.ts +++ b/src/browser/input/Mouse.test.ts @@ -5,7 +5,7 @@ import jsdom = require('jsdom'); import { assert } from 'chai'; -import { getCoords } from 'browser/input/Mouse'; +import { getCoords } from './Mouse'; const CHAR_WIDTH = 10; const CHAR_HEIGHT = 20; diff --git a/src/browser/input/Mouse.ts b/src/browser/input/Mouse.ts index c40a7cc78..c9840aec2 100644 --- a/src/browser/input/Mouse.ts +++ b/src/browser/input/Mouse.ts @@ -6,8 +6,8 @@ export function getCoordsRelativeToElement(window: Pick, event: {clientX: number, clientY: number}, element: HTMLElement): [number, number] { const rect = element.getBoundingClientRect(); const elementStyle = window.getComputedStyle(element); - const leftPadding = parseInt(elementStyle.getPropertyValue('padding-left')); - const topPadding = parseInt(elementStyle.getPropertyValue('padding-top')); + const leftPadding = parseInt(elementStyle.getPropertyValue('padding-left'), 10); + const topPadding = parseInt(elementStyle.getPropertyValue('padding-top'), 10); return [ event.clientX - rect.left - leftPadding, event.clientY - rect.top - topPadding @@ -22,7 +22,7 @@ export function getCoordsRelativeToElement(window: Pick, event: Pick, element: HTMLElement, colCount: number, rowCount: number, hasValidCharSize: boolean, cssCellWidth: number, cssCellHeight: number, isSelection?: boolean): [number, number] | undefined { - // Coordinates cannot be measured if there are no valid + // Coordinates cannot be measured if there is no valid character size. if (!hasValidCharSize) { return undefined; } const coords = getCoordsRelativeToElement(window, event, element); - if (!coords) { - return undefined; - } - coords[0] = Math.ceil((coords[0] + (isSelection ? cssCellWidth / 2 : 0)) / cssCellWidth); coords[1] = Math.ceil(coords[1] / cssCellHeight); // Ensure coordinates are within the terminal viewport. Note that selections - // need an addition point of precision to cover the end point (as characters + // need an additional point of precision to cover the end point (as characters // cover half of one char and half of the next). coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSelection ? 1 : 0)); coords[1] = Math.min(Math.max(coords[1], 1), rowCount); diff --git a/src/browser/input/MoveToCell.test.ts b/src/browser/input/MoveToCell.test.ts index 61e5f90b9..8200fa24e 100644 --- a/src/browser/input/MoveToCell.test.ts +++ b/src/browser/input/MoveToCell.test.ts @@ -4,8 +4,8 @@ */ import { assert } from 'chai'; -import { IBufferService } from 'common/services/Services'; -import { MockBufferService } from 'common/TestUtils.test'; +import { IBufferService } from '../../common/services/Services'; +import { MockBufferService } from '../../common/TestUtils.test'; import { moveToCellSequence } from './MoveToCell'; describe('MoveToCell', () => { diff --git a/src/browser/input/MoveToCell.ts b/src/browser/input/MoveToCell.ts index ce4c59224..9cc27088d 100644 --- a/src/browser/input/MoveToCell.ts +++ b/src/browser/input/MoveToCell.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { C0 } from 'common/data/EscapeSequences'; -import { IBufferService } from 'common/services/Services'; +import { C0 } from '../../common/data/EscapeSequences'; +import { IBufferService } from '../../common/services/Services'; const enum Direction { UP = 'A', @@ -156,7 +156,7 @@ function wrappedRowsForRow(currentRow: number, bufferService: IBufferService): n */ function horizontalDirection(startX: number, startY: number, targetX: number, targetY: number, bufferService: IBufferService, applicationCursor: boolean): Direction { let startRow; - if (moveToRequestedRow(targetX, targetY, bufferService, applicationCursor).length > 0) { + if (moveToRequestedRow(startY, targetY, bufferService, applicationCursor).length > 0) { startRow = targetY - wrappedRowsForRow(targetY, bufferService); } else { startRow = startY; diff --git a/src/browser/public/Terminal.ts b/src/browser/public/Terminal.ts index 75aada048..69ab09bf1 100644 --- a/src/browser/public/Terminal.ts +++ b/src/browser/public/Terminal.ts @@ -3,17 +3,17 @@ * @license MIT */ -import * as Strings from 'browser/LocalizableStrings'; -import { CoreBrowserTerminal as TerminalCore } from 'browser/CoreBrowserTerminal'; -import { IBufferRange, ITerminal } from 'browser/Types'; -import { Disposable } from 'common/Lifecycle'; -import { ITerminalOptions } from 'common/Types'; -import { AddonManager } from 'common/public/AddonManager'; -import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi'; -import { ParserApi } from 'common/public/ParserApi'; -import { UnicodeApi } from 'common/public/UnicodeApi'; +import * as Strings from '../LocalizableStrings'; +import { CoreBrowserTerminal as TerminalCore } from '../CoreBrowserTerminal'; +import { IBufferRange, ITerminal } from '../Types'; +import { Disposable } from '../../common/Lifecycle'; +import { ITerminalOptions } from '../../common/Types'; +import { AddonManager } from '../../common/public/AddonManager'; +import { BufferNamespaceApi } from '../../common/public/BufferNamespaceApi'; +import { ParserApi } from '../../common/public/ParserApi'; +import { UnicodeApi } from '../../common/public/UnicodeApi'; import { IBufferNamespace as IBufferNamespaceApi, IDecoration, IDecorationOptions, IDisposable, ILinkProvider, ILocalizableStrings, IMarker, IModes, IParser, IRenderDimensions, ITerminalAddon, Terminal as ITerminalApi, ITerminalInitOnlyOptions, IUnicodeHandling } from '@xterm/xterm'; -import type { IEvent } from 'common/Event'; +import type { IEvent } from '../../common/Event'; /** * The set of options that only have an effect when set in the Terminal constructor. diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 6f873af7b..657217f71 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -3,20 +3,20 @@ * @license MIT */ -import { DomRendererRowFactory, RowCss } from 'browser/renderer/dom/DomRendererRowFactory'; -import { WidthCache } from 'browser/renderer/dom/WidthCache'; -import { INVERTED_DEFAULT_COLOR, RendererConstants } from 'browser/renderer/shared/Constants'; -import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils'; -import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel'; -import { TextBlinkStateManager } from 'browser/renderer/shared/TextBlinkStateManager'; -import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ISelectionRenderModel } from 'browser/renderer/shared/Types'; -import { ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; -import { ILinkifier2, ILinkifierEvent, ITerminal, ReadonlyColorSet } from 'browser/Types'; -import { color } from 'common/Color'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IBufferService, ICoreService, IInstantiationService, IOptionsService } from 'common/services/Services'; -import { Emitter } from 'common/Event'; -import { addDisposableListener } from 'browser/Dom'; +import { DomRendererRowFactory, RowCss } from './DomRendererRowFactory'; +import { WidthCache } from './WidthCache'; +import { INVERTED_DEFAULT_COLOR, RendererConstants } from '../shared/Constants'; +import { createRenderDimensions } from '../shared/RendererUtils'; +import { createSelectionRenderModel } from '../shared/SelectionRenderModel'; +import { TextBlinkStateManager } from '../shared/TextBlinkStateManager'; +import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ISelectionRenderModel } from '../shared/Types'; +import { ICharSizeService, ICoreBrowserService, IThemeService } from '../../services/Services'; +import { ILinkifier2, ILinkifierEvent, ITerminal, ReadonlyColorSet } from '../../Types'; +import { color } from '../../../common/Color'; +import { Disposable, toDisposable } from '../../../common/Lifecycle'; +import { IBufferService, ICoreService, IInstantiationService, IOptionsService } from '../../../common/services/Services'; +import { Emitter } from '../../../common/Event'; +import { addDisposableListener } from '../../Dom'; const enum Constants { @@ -536,9 +536,14 @@ export class DomRenderer extends Disposable implements IRenderer { for (let y = start; y <= end; y++) { const row = y + buffer.ydisp; const rowElement = this._rowElements[y]; + if (!rowElement) { + continue; + } const lineData = buffer.lines.get(row); - if (!rowElement || !lineData) { - break; + if (!lineData) { + rowElement.replaceChildren(); + this._setRowBlinkState(y, false); + continue; } rowElement.replaceChildren( ...this._rowFactory.createRow( @@ -610,9 +615,14 @@ export class DomRenderer extends Disposable implements IRenderer { for (let i = y; i <= y2; ++i) { const row = i + buffer.ydisp; const rowElement = this._rowElements[i]; + if (!rowElement) { + continue; + } const bufferline = buffer.lines.get(row); - if (!rowElement || !bufferline) { - break; + if (!bufferline) { + rowElement.replaceChildren(); + this._setRowBlinkState(i, false); + continue; } rowElement.replaceChildren( ...this._rowFactory.createRow( @@ -694,7 +704,7 @@ class CursorBlinkStateManager { } private _clearIdleTimer(): void { - if (this._idleTimeout) { + if (this._idleTimeout !== undefined) { this._coreBrowserService.window.clearTimeout(this._idleTimeout); this._idleTimeout = undefined; } diff --git a/src/browser/renderer/dom/DomRendererRowFactory.test.ts b/src/browser/renderer/dom/DomRendererRowFactory.test.ts index 6ca84569a..ade53f461 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.test.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.test.ts @@ -5,15 +5,15 @@ import jsdom = require('jsdom'); import { assert } from 'chai'; -import { DomRendererRowFactory } from 'browser/renderer/dom/DomRendererRowFactory'; -import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR, FgFlags, BgFlags, Attributes, UnderlineStyle } from 'common/buffer/Constants'; -import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache'; -import { IBufferLine } from 'common/Types'; -import { CellData } from 'common/buffer/CellData'; -import { MockCoreService, MockDecorationService, MockOptionsService, createCellData, NULL_CELL_DATA } from 'common/TestUtils.test'; -import { MockCharacterJoinerService, MockCoreBrowserService, MockThemeService } from 'browser/TestUtils.test'; -import { TestWidthCache } from 'browser/renderer/dom/WidthCache.test'; +import { DomRendererRowFactory } from './DomRendererRowFactory'; +import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR, FgFlags, BgFlags, Attributes, UnderlineStyle } from '../../../common/buffer/Constants'; +import { BufferLine, DEFAULT_ATTR_DATA } from '../../../common/buffer/BufferLine'; +import { BufferLineStringCache } from '../../../common/buffer/BufferLineStringCache'; +import { IBufferLine } from '../../../common/buffer/Types'; +import { CellData } from '../../../common/buffer/CellData'; +import { MockCoreService, MockDecorationService, MockOptionsService, createCellData, NULL_CELL_DATA } from '../../../common/TestUtils.test'; +import { MockCharacterJoinerService, MockCoreBrowserService, MockThemeService } from '../../TestUtils.test'; +import { TestWidthCache } from './WidthCache.test'; const TEST_STRING_CACHE = new BufferLineStringCache(); diff --git a/src/browser/renderer/dom/DomRendererRowFactory.ts b/src/browser/renderer/dom/DomRendererRowFactory.ts index 0cff9c25f..6ae089a43 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.ts @@ -3,18 +3,19 @@ * @license MIT */ -import { IBufferLine, ICellData, IColor } from 'common/Types'; -import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants'; -import { WHITESPACE_CELL_CHAR, Attributes } from 'common/buffer/Constants'; -import { CellData } from 'common/buffer/CellData'; -import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services'; -import { channels, color } from 'common/Color'; -import { ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; -import { JoinedCellData } from 'browser/services/CharacterJoinerService'; -import { treatGlyphAsBackgroundColor } from 'browser/renderer/shared/RendererUtils'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { WidthCache } from 'browser/renderer/dom/WidthCache'; -import { IColorContrastCache } from 'browser/Types'; +import { IColor } from '../../../common/Types'; +import { IBufferLine, ICellData } from '../../../common/buffer/Types'; +import { INVERTED_DEFAULT_COLOR } from '../shared/Constants'; +import { WHITESPACE_CELL_CHAR, Attributes } from '../../../common/buffer/Constants'; +import { CellData } from '../../../common/buffer/CellData'; +import { ICoreService, IDecorationService, IOptionsService } from '../../../common/services/Services'; +import { channels, color } from '../../../common/Color'; +import { ICharacterJoinerService, ICoreBrowserService, IThemeService } from '../../services/Services'; +import { JoinedCellData } from '../../services/CharacterJoinerService'; +import { treatGlyphAsBackgroundColor } from '../shared/RendererUtils'; +import { AttributeData } from '../../../common/buffer/AttributeData'; +import { WidthCache } from './WidthCache'; +import { IColorContrastCache } from '../../Types'; export const enum RowCss { @@ -90,14 +91,14 @@ export class DomRendererRowFactory { let charElement: HTMLSpanElement | undefined; let cellAmount = 0; let text = ''; - let i = 0; + let i; let oldBg = 0; let oldFg = 0; let oldExt = 0; let oldLinkHover: number | boolean = false; let oldSpacing = 0; let oldIsInSelection: boolean = false; - let spacing = 0; + let spacing; let skipJoinedCheckUntilX = 0; const classes: string[] = []; diff --git a/src/browser/renderer/dom/WidthCache.test.ts b/src/browser/renderer/dom/WidthCache.test.ts index c1e511c94..f8bc5961a 100644 --- a/src/browser/renderer/dom/WidthCache.test.ts +++ b/src/browser/renderer/dom/WidthCache.test.ts @@ -4,7 +4,7 @@ */ import * as assert from 'assert'; -import { IWidthCacheFontVariantCanvas, WidthCache, WidthCacheSettings } from 'browser/renderer/dom/WidthCache'; +import { IWidthCacheFontVariantCanvas, WidthCache, WidthCacheSettings } from './WidthCache'; class MockWidthCacheFontVariantCanvas implements IWidthCacheFontVariantCanvas { diff --git a/src/browser/renderer/dom/WidthCache.ts b/src/browser/renderer/dom/WidthCache.ts index b598bbd6f..d45938515 100644 --- a/src/browser/renderer/dom/WidthCache.ts +++ b/src/browser/renderer/dom/WidthCache.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; -import { IDisposable } from 'common/Types'; -import { FontWeight } from 'common/services/Services'; +import { throwIfFalsy } from '../shared/RendererUtils'; +import { IDisposable } from '../../../common/Types'; +import { FontWeight } from '../../../common/services/Services'; export const enum WidthCacheSettings { @@ -110,7 +110,7 @@ export class WidthCache implements IDisposable { * `variant` denotes the font variant to be used. */ public get(c: string, bold: boolean | number, italic: boolean | number): number { - let cp = 0; + let cp: number; if (!bold && !italic && c.length === 1 && (cp = c.charCodeAt(0)) < WidthCacheSettings.FLAT_SIZE) { if (this._flat[cp] !== WidthCacheSettings.FLAT_UNSET) { return this._flat[cp]; diff --git a/src/browser/renderer/shared/RendererUtils.test.ts b/src/browser/renderer/shared/RendererUtils.test.ts index 4512cb6d9..4f4e843af 100644 --- a/src/browser/renderer/shared/RendererUtils.test.ts +++ b/src/browser/renderer/shared/RendererUtils.test.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { computeNextVariantOffset } from 'browser/renderer/shared/RendererUtils'; +import { computeNextVariantOffset } from './RendererUtils'; import { assert } from 'chai'; describe('RendererUtils', () => { diff --git a/src/browser/renderer/shared/RendererUtils.ts b/src/browser/renderer/shared/RendererUtils.ts index 010643648..da8914abe 100644 --- a/src/browser/renderer/shared/RendererUtils.ts +++ b/src/browser/renderer/shared/RendererUtils.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IDimensions, IRenderDimensions } from 'browser/renderer/shared/Types'; +import { IDimensions, IRenderDimensions } from './Types'; export function throwIfFalsy(value: T | undefined | null): T { if (!value) { diff --git a/src/browser/renderer/shared/SelectionRenderModel.ts b/src/browser/renderer/shared/SelectionRenderModel.ts index d3b7a99c4..1df166c28 100644 --- a/src/browser/renderer/shared/SelectionRenderModel.ts +++ b/src/browser/renderer/shared/SelectionRenderModel.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { ITerminal } from 'browser/Types'; -import { ISelectionRenderModel } from 'browser/renderer/shared/Types'; +import { ITerminal } from '../../Types'; +import { ISelectionRenderModel } from './Types'; import { Terminal } from '@xterm/xterm'; class SelectionRenderModel implements ISelectionRenderModel { diff --git a/src/browser/renderer/shared/TextBlinkStateManager.test.ts b/src/browser/renderer/shared/TextBlinkStateManager.test.ts index 5c8ce448a..3af39cac8 100644 --- a/src/browser/renderer/shared/TextBlinkStateManager.test.ts +++ b/src/browser/renderer/shared/TextBlinkStateManager.test.ts @@ -4,10 +4,10 @@ */ import { assert } from 'chai'; -import { TextBlinkStateManager } from 'browser/renderer/shared/TextBlinkStateManager'; -import { MockOptionsService } from 'common/TestUtils.test'; -import type { ICoreBrowserService } from 'browser/services/Services'; -import { Emitter } from 'common/Event'; +import { TextBlinkStateManager } from './TextBlinkStateManager'; +import { MockOptionsService } from '../../../common/TestUtils.test'; +import type { ICoreBrowserService } from '../../services/Services'; +import { Emitter } from '../../../common/Event'; class FakeWindow { public nextId = 1; diff --git a/src/browser/renderer/shared/TextBlinkStateManager.ts b/src/browser/renderer/shared/TextBlinkStateManager.ts index 028cde898..058abf73b 100644 --- a/src/browser/renderer/shared/TextBlinkStateManager.ts +++ b/src/browser/renderer/shared/TextBlinkStateManager.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { ICoreBrowserService } from 'browser/services/Services'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IOptionsService } from 'common/services/Services'; +import { ICoreBrowserService } from '../../services/Services'; +import { Disposable, toDisposable } from '../../../common/Lifecycle'; +import { IOptionsService } from '../../../common/services/Services'; export class TextBlinkStateManager extends Disposable { private _intervalDuration: number = 0; diff --git a/src/browser/renderer/shared/Types.ts b/src/browser/renderer/shared/Types.ts index c78e7794f..d664d1611 100644 --- a/src/browser/renderer/shared/Types.ts +++ b/src/browser/renderer/shared/Types.ts @@ -4,9 +4,9 @@ */ import { Terminal } from '@xterm/xterm'; -import { ITerminal } from 'browser/Types'; -import { IDisposable } from 'common/Types'; -import type { IEvent } from 'common/Event'; +import { ITerminal } from '../../Types'; +import { IDisposable } from '../../../common/Types'; +import type { IEvent } from '../../../common/Event'; export interface IDimensions { width: number; diff --git a/src/browser/scrollable/abstractScrollbar.ts b/src/browser/scrollable/abstractScrollbar.ts index 64c25d9d8..906190f76 100644 --- a/src/browser/scrollable/abstractScrollbar.ts +++ b/src/browser/scrollable/abstractScrollbar.ts @@ -11,7 +11,7 @@ import { ScrollbarArrow, IScrollbarArrowOptions } from './scrollbarArrow'; import { ScrollbarState } from './scrollbarState'; import { ScrollbarVisibilityController } from './scrollbarVisibilityController'; import { Widget } from './widget'; -import * as platform from 'common/Platform'; +import * as platform from '../../common/Platform'; import { INewScrollPosition, Scrollable, ScrollbarVisibility } from './scrollable'; /** diff --git a/src/browser/scrollable/globalPointerMoveMonitor.ts b/src/browser/scrollable/globalPointerMoveMonitor.ts index a80e0507f..56ad16699 100644 --- a/src/browser/scrollable/globalPointerMoveMonitor.ts +++ b/src/browser/scrollable/globalPointerMoveMonitor.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from '../Dom'; -import { DisposableStore, IDisposable, toDisposable } from 'common/Lifecycle'; +import { DisposableStore, IDisposable, toDisposable } from '../../common/Lifecycle'; type PointerMoveCallback = (event: PointerEvent) => void; type OnStopCallback = () => void; diff --git a/src/browser/scrollable/mouseEvent.ts b/src/browser/scrollable/mouseEvent.ts index a12b63d52..f6fca88f1 100644 --- a/src/browser/scrollable/mouseEvent.ts +++ b/src/browser/scrollable/mouseEvent.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as platform from 'common/Platform'; +import * as platform from '../../common/Platform'; interface IWindowChainElement { readonly window: WeakRef; @@ -217,7 +217,7 @@ export class StandardWheelEvent { let shouldFactorDPR: boolean = false; if (platform.isChrome) { const chromeVersionMatch = navigator.userAgent.match(/Chrome\/(\d+)/); - const chromeMajorVersion = chromeVersionMatch ? parseInt(chromeVersionMatch[1]) : 123; + const chromeMajorVersion = chromeVersionMatch ? parseInt(chromeVersionMatch[1], 10) : 123; shouldFactorDPR = chromeMajorVersion <= 122; } diff --git a/src/browser/scrollable/scrollable.ts b/src/browser/scrollable/scrollable.ts index 18275ffe5..29435ad8f 100644 --- a/src/browser/scrollable/scrollable.ts +++ b/src/browser/scrollable/scrollable.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Emitter, IEvent } from 'common/Event'; -import { Disposable, IDisposable } from 'common/Lifecycle'; +import { Emitter, IEvent } from '../../common/Event'; +import { Disposable, IDisposable } from '../../common/Lifecycle'; export const enum ScrollbarVisibility { AUTO = 1, diff --git a/src/browser/scrollable/scrollableElement.ts b/src/browser/scrollable/scrollableElement.ts index 4039d0c4e..df3628e10 100644 --- a/src/browser/scrollable/scrollableElement.ts +++ b/src/browser/scrollable/scrollableElement.ts @@ -11,10 +11,10 @@ import { HorizontalScrollbar } from './horizontalScrollbar'; import { IScrollableElementChangeOptions, IScrollableElementCreationOptions, IScrollableElementResolvedOptions } from './scrollableElementOptions'; import { VerticalScrollbar } from './verticalScrollbar'; import { Widget } from './widget'; -import { TimeoutTimer } from 'common/Async'; -import { Emitter, IEvent } from 'common/Event'; -import { IDisposable, dispose } from 'common/Lifecycle'; -import * as platform from 'common/Platform'; +import { TimeoutTimer } from '../../common/Async'; +import { Emitter, IEvent } from '../../common/Event'; +import { IDisposable, dispose } from '../../common/Lifecycle'; +import * as platform from '../../common/Platform'; import { INewScrollDimensions, INewScrollPosition, IScrollDimensions, IScrollPosition, IScrollEvent, Scrollable, ScrollbarVisibility } from './scrollable'; // import 'vs/css!./media/scrollbars'; diff --git a/src/browser/scrollable/scrollbarArrow.ts b/src/browser/scrollable/scrollbarArrow.ts index d543669c1..2f1f9e9fe 100644 --- a/src/browser/scrollable/scrollbarArrow.ts +++ b/src/browser/scrollable/scrollbarArrow.ts @@ -5,7 +5,7 @@ import { GlobalPointerMoveMonitor } from './globalPointerMoveMonitor'; import { Widget } from './widget'; -import { TimeoutTimer } from 'common/Async'; +import { TimeoutTimer } from '../../common/Async'; import * as dom from '../Dom'; export interface IScrollbarArrowOptions { diff --git a/src/browser/scrollable/scrollbarVisibilityController.ts b/src/browser/scrollable/scrollbarVisibilityController.ts index 59d172bce..84a8b460f 100644 --- a/src/browser/scrollable/scrollbarVisibilityController.ts +++ b/src/browser/scrollable/scrollbarVisibilityController.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { FastDomNode } from './fastDomNode'; -import { TimeoutTimer } from 'common/Async'; -import { Disposable } from 'common/Lifecycle'; +import { TimeoutTimer } from '../../common/Async'; +import { Disposable } from '../../common/Lifecycle'; import { ScrollbarVisibility } from './scrollable'; export class ScrollbarVisibilityController extends Disposable { diff --git a/src/browser/scrollable/touch.ts b/src/browser/scrollable/touch.ts index 8ffdfe699..5c58eac3b 100644 --- a/src/browser/scrollable/touch.ts +++ b/src/browser/scrollable/touch.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as DomUtils from '../Dom'; -import { Disposable, IDisposable, toDisposable } from 'common/Lifecycle'; +import { Disposable, IDisposable, toDisposable } from '../../common/Lifecycle'; const mainWindow = (typeof window === 'object' ? window : globalThis) as Window & typeof globalThis; @@ -367,7 +367,7 @@ export class Gesture extends Disposable { private _dispatchEvent(event: IGestureEvent): void { if (event.type === EventType.TAP) { const currentTime = (new Date()).getTime(); - let setTapCount = 0; + let setTapCount; if (currentTime - this._lastSetTapCountTime > Gesture._clearTapCountTime) { setTapCount = 1; } else { diff --git a/src/browser/scrollable/widget.ts b/src/browser/scrollable/widget.ts index 80220c9b1..578492853 100644 --- a/src/browser/scrollable/widget.ts +++ b/src/browser/scrollable/widget.ts @@ -5,7 +5,7 @@ import * as dom from '../Dom'; import { IMouseEvent, StandardMouseEvent } from './mouseEvent'; -import { Disposable } from 'common/Lifecycle'; +import { Disposable } from '../../common/Lifecycle'; export abstract class Widget extends Disposable { diff --git a/src/browser/selection/SelectionModel.test.ts b/src/browser/selection/SelectionModel.test.ts index 79ff372b3..10ca79a34 100644 --- a/src/browser/selection/SelectionModel.test.ts +++ b/src/browser/selection/SelectionModel.test.ts @@ -5,7 +5,7 @@ import { assert } from 'chai'; import { SelectionModel } from './SelectionModel'; -import { MockBufferService } from 'common/TestUtils.test'; +import { MockBufferService } from '../../common/TestUtils.test'; describe('SelectionModel', () => { let model: SelectionModel; @@ -64,6 +64,13 @@ describe('SelectionModel', () => { assert.deepEqual(model.finalSelectionStart, undefined); assert.deepEqual(model.finalSelectionEnd, undefined); }); + it('should reset selection start to origin when start row is trimmed', () => { + model.selectionStart = [50, 0]; + model.selectionEnd = [10, 2]; + assert.equal(model.handleTrim(1), true); + assert.deepEqual(model.finalSelectionStart, [0, 0]); + assert.deepEqual(model.finalSelectionEnd, [10, 1]); + }); }); describe('finalSelectionStart', () => { diff --git a/src/browser/selection/SelectionModel.ts b/src/browser/selection/SelectionModel.ts index b26cf944f..8f87f17e2 100644 --- a/src/browser/selection/SelectionModel.ts +++ b/src/browser/selection/SelectionModel.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IBufferService } from 'common/services/Services'; +import { IBufferService } from '../../common/services/Services'; /** * Represents a selection within the buffer. This model only cares about column @@ -135,9 +135,10 @@ export class SelectionModel { return true; } - // If the selection start is trimmed, ensure the start column is 0. + // If the selection start row is trimmed away, reset to the buffer origin. if (this.selectionStart && this.selectionStart[1] < 0) { - this.selectionStart[1] = 0; + this.selectionStart = [0, 0]; + return true; } return false; } diff --git a/src/browser/services/CharSizeService.ts b/src/browser/services/CharSizeService.ts index 6baf9b50a..002ca5c18 100644 --- a/src/browser/services/CharSizeService.ts +++ b/src/browser/services/CharSizeService.ts @@ -3,10 +3,10 @@ * @license MIT */ -import { IOptionsService } from 'common/services/Services'; -import { ICharSizeService } from 'browser/services/Services'; -import { Disposable } from 'common/Lifecycle'; -import { Emitter } from 'common/Event'; +import { IOptionsService } from '../../common/services/Services'; +import { ICharSizeService } from './Services'; +import { Disposable } from '../../common/Lifecycle'; +import { Emitter } from '../../common/Event'; export class CharSizeService extends Disposable implements ICharSizeService { public serviceBrand: undefined; diff --git a/src/browser/services/CharacterJoinerService.test.ts b/src/browser/services/CharacterJoinerService.test.ts index 06730c7ac..2e73f035b 100644 --- a/src/browser/services/CharacterJoinerService.test.ts +++ b/src/browser/services/CharacterJoinerService.test.ts @@ -4,13 +4,13 @@ */ import { assert } from 'chai'; -import { ICharacterJoinerService } from 'browser/services/Services'; -import { CharacterJoinerService } from 'browser/services/CharacterJoinerService'; -import { BufferLine } from 'common/buffer/BufferLine'; -import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache'; -import { IBufferLine } from 'common/Types'; -import { CellData } from 'common/buffer/CellData'; -import { MockBufferService, createCellData } from 'common/TestUtils.test'; +import { ICharacterJoinerService } from './Services'; +import { CharacterJoinerService } from './CharacterJoinerService'; +import { BufferLine } from '../../common/buffer/BufferLine'; +import { BufferLineStringCache } from '../../common/buffer/BufferLineStringCache'; +import { IBufferLine } from '../../common/buffer/Types'; +import { CellData } from '../../common/buffer/CellData'; +import { MockBufferService, createCellData } from '../../common/TestUtils.test'; const TEST_STRING_CACHE = new BufferLineStringCache(); @@ -285,7 +285,7 @@ function substringJoiner(substring: string): (sequence: string) => [number, numb return (sequence: string): [number, number][] => { const ranges: [number, number][] = []; let searchIndex = 0; - let matchIndex = -1; + let matchIndex; while ((matchIndex = sequence.indexOf(substring, searchIndex)) !== -1) { const matchEndIndex = matchIndex + substring.length; diff --git a/src/browser/services/CharacterJoinerService.ts b/src/browser/services/CharacterJoinerService.ts index ca4f1984e..2cf3bd506 100644 --- a/src/browser/services/CharacterJoinerService.ts +++ b/src/browser/services/CharacterJoinerService.ts @@ -3,13 +3,13 @@ * @license MIT */ -import { IBufferLine, ICellData, CharData } from 'common/Types'; -import { ICharacterJoiner } from 'browser/Types'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { WHITESPACE_CELL_CHAR, Content } from 'common/buffer/Constants'; -import { CellData } from 'common/buffer/CellData'; -import { IBufferService } from 'common/services/Services'; -import { ICharacterJoinerService } from 'browser/services/Services'; +import { CharData, IBufferLine, ICellData } from '../../common/buffer/Types'; +import { ICharacterJoiner } from '../Types'; +import { AttributeData } from '../../common/buffer/AttributeData'; +import { WHITESPACE_CELL_CHAR, Content } from '../../common/buffer/Constants'; +import { CellData } from '../../common/buffer/CellData'; +import { IBufferService } from '../../common/services/Services'; +import { ICharacterJoinerService } from './Services'; export class JoinedCellData extends AttributeData implements ICellData { private _width: number; @@ -100,6 +100,7 @@ export class CharacterJoinerService implements ICharacterJoinerService { const ranges: [number, number][] = []; const lineStr = line.translateToString(true); + const trimmedLength = line.getTrimmedLength(); // Because some cells can be represented by multiple javascript characters, // we track the cell and the string indexes separately. This allows us to @@ -111,7 +112,7 @@ export class CharacterJoinerService implements ICharacterJoinerService { let rangeAttrFG = line.getFg(0); let rangeAttrBG = line.getBg(0); - for (let x = 0; x < line.getTrimmedLength(); x++) { + for (let x = 0; x < trimmedLength; x++) { line.loadCell(x, this._workCell); if (this._workCell.getWidth() === 0) { @@ -147,7 +148,7 @@ export class CharacterJoinerService implements ICharacterJoinerService { } // Process any trailing ranges. - if (this._bufferService.cols - rangeStartColumn > 1) { + if (trimmedLength - rangeStartColumn > 1) { const joinedRanges = this._getJoinedRanges( lineStr, rangeStartStringIndex, @@ -216,7 +217,8 @@ export class CharacterJoinerService implements ICharacterJoinerService { return; } - for (let x = startCol; x < this._bufferService.cols; x++) { + const trimmedLength = line.getTrimmedLength(); + for (let x = startCol; x < trimmedLength; x++) { const width = line.getWidth(x); const length = line.getString(x).length || WHITESPACE_CELL_CHAR.length; @@ -264,7 +266,7 @@ export class CharacterJoinerService implements ICharacterJoinerService { // If there is still a range left at the end, it must extend all the way to // the end of the line. if (currentRange) { - currentRange[1] = this._bufferService.cols; + currentRange[1] = trimmedLength; } } diff --git a/src/browser/services/CoreBrowserService.ts b/src/browser/services/CoreBrowserService.ts index 658caaeb1..bcc39544e 100644 --- a/src/browser/services/CoreBrowserService.ts +++ b/src/browser/services/CoreBrowserService.ts @@ -4,9 +4,9 @@ */ import { ICoreBrowserService } from './Services'; -import { Emitter, EventUtils } from 'common/Event'; -import { addDisposableListener } from 'browser/Dom'; -import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle'; +import { Emitter, EventUtils } from '../../common/Event'; +import { addDisposableListener } from '../Dom'; +import { Disposable, MutableDisposable, toDisposable } from '../../common/Lifecycle'; export class CoreBrowserService extends Disposable implements ICoreBrowserService { public serviceBrand: undefined; diff --git a/src/browser/services/KeyboardService.ts b/src/browser/services/KeyboardService.ts index 493f30653..a85eb2339 100644 --- a/src/browser/services/KeyboardService.ts +++ b/src/browser/services/KeyboardService.ts @@ -3,13 +3,13 @@ * @license MIT */ -import { IKeyboardService } from 'browser/services/Services'; -import { evaluateKeyboardEvent } from 'common/input/Keyboard'; -import { KittyKeyboard, KittyKeyboardEventType, KittyKeyboardFlags } from 'common/input/KittyKeyboard'; -import { Win32InputMode } from 'common/input/Win32InputMode'; -import { isMac } from 'common/Platform'; -import { ICoreService, IOptionsService } from 'common/services/Services'; -import { IKeyboardResult } from 'common/Types'; +import { IKeyboardService } from './Services'; +import { evaluateKeyboardEvent } from '../../common/input/Keyboard'; +import { KittyKeyboard, KittyKeyboardEventType, KittyKeyboardFlags } from '../../common/input/KittyKeyboard'; +import { Win32InputMode } from '../../common/input/Win32InputMode'; +import { isMac } from '../../common/Platform'; +import { ICoreService, IOptionsService } from '../../common/services/Services'; +import { IKeyboardResult } from '../../common/Types'; export class KeyboardService implements IKeyboardService { public serviceBrand: undefined; diff --git a/src/browser/services/LinkProviderService.ts b/src/browser/services/LinkProviderService.ts index 7a7b530d0..fe4b564a2 100644 --- a/src/browser/services/LinkProviderService.ts +++ b/src/browser/services/LinkProviderService.ts @@ -1,6 +1,6 @@ -import { ILinkProvider, ILinkProviderService } from 'browser/services/Services'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IDisposable } from 'common/Types'; +import { ILinkProvider, ILinkProviderService } from './Services'; +import { Disposable, toDisposable } from '../../common/Lifecycle'; +import { IDisposable } from '../../common/Types'; export class LinkProviderService extends Disposable implements ILinkProviderService { declare public serviceBrand: undefined; diff --git a/src/browser/services/MouseCoordsService.ts b/src/browser/services/MouseCoordsService.ts index e2455fd2b..7e110ea98 100644 --- a/src/browser/services/MouseCoordsService.ts +++ b/src/browser/services/MouseCoordsService.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { getWindow } from 'browser/Dom'; -import { getCoords, getCoordsRelativeToElement } from 'browser/input/Mouse'; -import { ICharSizeService, IMouseCoordsService, IRenderService } from 'browser/services/Services'; +import { getWindow } from '../Dom'; +import { getCoords, getCoordsRelativeToElement } from '../input/Mouse'; +import { ICharSizeService, IMouseCoordsService, IRenderService } from './Services'; export class MouseCoordsService implements IMouseCoordsService { public serviceBrand: undefined; @@ -18,7 +18,7 @@ export class MouseCoordsService implements IMouseCoordsService { public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined { return getCoords( - window, + getWindow(element), event, element, colCount, diff --git a/src/browser/services/MouseService.test.ts b/src/browser/services/MouseService.test.ts index f395083e3..b4655a1a1 100644 --- a/src/browser/services/MouseService.test.ts +++ b/src/browser/services/MouseService.test.ts @@ -3,11 +3,12 @@ * @license MIT */ import { assert } from 'chai'; -import { MouseService } from 'browser/services/MouseService'; -import { MouseStateService } from 'common/services/MouseStateService'; -import { CoreMouseAction, CoreMouseButton } from 'common/Types'; -import { IBufferService, ICoreService, ILogService, IOptionsService } from 'common/services/Services'; -import { MockCoreBrowserService, MockRenderService, MockSelectionService } from 'browser/TestUtils.test'; +import { AltMouseCursorController, MouseEventCssClasses, MouseService } from './MouseService'; +import { MouseStateService } from '../../common/services/MouseStateService'; +import { CoreMouseAction, CoreMouseButton } from '../../common/Types'; +import { IBufferService, ICoreService, ILogService, IOptionsService } from '../../common/services/Services'; +import { OptionsService } from '../../common/services/OptionsService'; +import { MockCoreBrowserService, MockRenderService, MockSelectionService } from '../TestUtils.test'; function toBytes(s: string | undefined): number[] { if (!s) { @@ -42,6 +43,36 @@ const logService: ILogService = { error: () => {} } as any; +class TestSelectionService extends MockSelectionService { + public enableCount = 0; + public disableCount = 0; + + public override enable(): void { + this.enableCount++; + } + + public override disable(): void { + this.disableCount++; + } + + public override shouldForceSelection(): boolean { + return false; + } +} + +function createTestMouseTargetElement(): HTMLElement { + const classes = new Set(); + return { + classList: { + add: (className: string) => classes.add(className), + remove: (className: string) => classes.delete(className), + contains: (className: string) => classes.has(className) + }, + addEventListener: () => {}, + removeEventListener: () => {} + } as any; +} + describe('MouseService _triggerMouseEvent', () => { let mouseService: MouseService; let mouseStateService: MouseStateService; @@ -145,7 +176,7 @@ describe('MouseService _triggerMouseEvent', () => { for (let i = 0; i < bufferService.cols; ++i) { assert.equal(trigger({ col: i, row: 0, x: 0, y: 0, button: CoreMouseButton.LEFT, action: CoreMouseAction.DOWN }), true); if (i > 222) { - // supress mouse reports if we are out of addressible range (max. 222) + // suppress mouse reports if we are out of addressable range (max. 222) assert.deepEqual(toBytes(reports.pop()), []); } else { assert.deepEqual(toBytes(reports.pop()), [0x1b, 0x5b, 0x4d, 0x20, i + 33, 0x21]); @@ -211,3 +242,112 @@ describe('MouseService _triggerMouseEvent', () => { reports = []; }); }); + +describe('MouseService mouseEventsRequireAlt', () => { + it('should update selection state and cursor class when toggled while mouse events are active', () => { + const mouseStateService = new MouseStateService(); + const optionsService = new OptionsService({}); + const selectionService = new TestSelectionService(); + const mouseService = new MouseService( + new MockRenderService(), + { + getMouseReportCoords: (_ev: MouseEvent, _el: HTMLElement) => ({ col: 0, row: 0, x: 0, y: 0 }) + } as any, + mouseStateService, + { + triggerDataEvent: () => {}, + triggerBinaryEvent: () => {}, + decPrivateModes: { applicationCursorKeys: false } + } as any, + bufferService, + optionsService, + selectionService, + logService, + new MockCoreBrowserService() + ); + const element = createTestMouseTargetElement(); + const screenElement = createTestMouseTargetElement(); + const document = { + addEventListener: () => {}, + removeEventListener: () => {} + } as any; + + mouseService.bindMouse({ + element, + screenElement, + document + }, disposable => disposable, () => {}); + + mouseStateService.activeProtocol = 'ANY'; + assert.isTrue(element.classList.contains(MouseEventCssClasses.ENABLE_MOUSE_EVENTS)); + assert.equal(selectionService.disableCount, 1); + + optionsService.options.mouseEventsRequireAlt = true; + assert.isFalse(element.classList.contains(MouseEventCssClasses.ENABLE_MOUSE_EVENTS)); + assert.equal(selectionService.enableCount, 2); + + optionsService.options.mouseEventsRequireAlt = false; + assert.isTrue(element.classList.contains(MouseEventCssClasses.ENABLE_MOUSE_EVENTS)); + assert.equal(selectionService.disableCount, 2); + }); + + it('should strip alt modifier from forwarded mouse reports', () => { + const mouseStateService = new MouseStateService(); + mouseStateService.activeProtocol = 'ANY'; + mouseStateService.activeEncoding = 'SGR'; + const optionsService = new OptionsService({ mouseEventsRequireAlt: true }); + const reports: string[] = []; + const mouseService = new MouseService( + new MockRenderService(), + { + getMouseReportCoords: () => ({ col: 0, row: 0, x: 0, y: 0 }) + } as any, + mouseStateService, + { + triggerDataEvent: (data: string) => reports.push(data), + triggerBinaryEvent: () => {}, + decPrivateModes: { applicationCursorKeys: false } + } as any, + bufferService, + optionsService, + new TestSelectionService(), + logService, + new MockCoreBrowserService() + ); + const ctx = { + target: { + screenElement: createTestMouseTargetElement() + }, + requestedEvents: {} + } as any; + + const sent = (mouseService as any)._sendEvent(ctx, { + type: 'mousedown', + button: 0, + altKey: true, + ctrlKey: false, + shiftKey: false + } as MouseEvent); + + assert.isTrue(sent); + assert.deepEqual(reports, ['\x1b[<0;1;1M']); + }); + + it('should toggle enable-mouse-events class when alt modifier changes', () => { + const element = createTestMouseTargetElement(); + const altMouseCursor = new AltMouseCursorController(element, { + addEventListener: () => {}, + removeEventListener: () => {} + } as any, () => true); + + const sync = (altHeld: boolean) => altMouseCursor.syncFromModifier({ + getModifierState: (key: string) => key === 'Alt' && altHeld + } as KeyboardEvent); + + assert.isFalse(element.classList.contains(MouseEventCssClasses.ENABLE_MOUSE_EVENTS)); + sync(true); + assert.isTrue(element.classList.contains(MouseEventCssClasses.ENABLE_MOUSE_EVENTS)); + sync(false); + assert.isFalse(element.classList.contains(MouseEventCssClasses.ENABLE_MOUSE_EVENTS)); + }); +}); diff --git a/src/browser/services/MouseService.ts b/src/browser/services/MouseService.ts index d701796c2..61cbfa86c 100644 --- a/src/browser/services/MouseService.ts +++ b/src/browser/services/MouseService.ts @@ -3,16 +3,20 @@ * @license MIT */ -import { addDisposableListener } from 'browser/Dom'; -import { IBufferService, IMouseStateService, ICoreService, ILogService, IOptionsService } from 'common/services/Services'; -import { CoreMouseAction, CoreMouseButton, CoreMouseEventType, ICoreMouseEvent, IDisposable } from 'common/Types'; -import { C0 } from 'common/data/EscapeSequences'; -import { toDisposable } from 'common/Lifecycle'; +import { addDisposableListener } from '../Dom'; +import { IBufferService, IMouseStateService, ICoreService, ILogService, IOptionsService } from '../../common/services/Services'; +import { CoreMouseAction, CoreMouseButton, CoreMouseEventType, ICoreMouseEvent, IDisposable } from '../../common/Types'; +import { C0 } from '../../common/data/EscapeSequences'; +import { DisposableStore, MutableDisposable, toDisposable } from '../../common/Lifecycle'; import { ICoreBrowserService, IMouseCoordsService, IMouseService, IMouseServiceTarget, IRenderService, ISelectionService } from './Services'; -import { Gesture, EventType as GestureEventType, IGestureEvent } from 'browser/scrollable/touch'; +import { Gesture, EventType as GestureEventType, IGestureEvent } from '../scrollable/touch'; type RequestedMouseEvents = Record<'mouseup' | 'wheel' | 'mousedrag' | 'mousemove', EventListener | null>; +export const enum MouseEventCssClasses { + ENABLE_MOUSE_EVENTS = 'enable-mouse-events' +} + interface IMouseBindContext { readonly target: IMouseServiceTarget; readonly focus: () => void; @@ -25,6 +29,7 @@ export class MouseService implements IMouseService { private _lastEvent: ICoreMouseEvent | null = null; private _wheelPartialScroll: number = 0; private _touchScrollAccumulator: number = 0; + private _altMouseCursor: AltMouseCursorController | undefined; constructor( @IRenderService private readonly _renderService: IRenderService, @@ -63,9 +68,20 @@ export class MouseService implements IMouseService { mousedrag: (ev: Event) => this._handleMouseDrag(ctx, ev as MouseEvent), mousemove: (ev: Event) => this._handleMouseMove(ctx, ev as MouseEvent) }; + this._altMouseCursor = new AltMouseCursorController( + element, + document, + () => this._mouseStateService.areMouseEventsActive + && !!this._optionsService.rawOptions.mouseEventsRequireAlt + ); + register(this._altMouseCursor); register(this._mouseStateService.onProtocolChange(events => { this._handleProtocolChange(ctx, eventListeners, events); })); + register(this._optionsService.onSpecificOptionChange('mouseEventsRequireAlt', () => { + this._syncMouseModeState(element); + this._altMouseCursor?.sync(); + })); // force initial onProtocolChange so we dont miss early mouse requests this._mouseStateService.activeProtocol = this._mouseStateService.activeProtocol; @@ -153,6 +169,19 @@ export class MouseService implements IMouseService { return false; } + if (but !== CoreMouseButton.WHEEL + && this._optionsService.rawOptions.mouseEventsRequireAlt + && this._mouseStateService.areMouseEventsActive + && !ev.altKey) { + return false; + } + + // Alt is only used locally to gate mouse passthrough; do not forward it to the + // application (e.g. tmux ignores alt-modified mouse reports). + const stripAltFromReport = but !== CoreMouseButton.WHEEL + && this._optionsService.rawOptions.mouseEventsRequireAlt + && this._mouseStateService.areMouseEventsActive; + return this._triggerMouseEvent({ col: pos.col, row: pos.row, @@ -161,7 +190,7 @@ export class MouseService implements IMouseService { button: but, action, ctrl: ev.ctrlKey, - alt: ev.altKey, + alt: stripAltFromReport ? false : ev.altKey, shift: ev.shiftKey }); } @@ -353,6 +382,21 @@ export class MouseService implements IMouseService { this._touchScrollAccumulator = 0; } + private _syncMouseModeState(element: HTMLElement): void { + if (this._mouseStateService.areMouseEventsActive) { + if (this._optionsService.rawOptions.mouseEventsRequireAlt) { + this._altMouseCursor?.resetClass(); + this._selectionService.enable(); + } else { + element.classList.add(MouseEventCssClasses.ENABLE_MOUSE_EVENTS); + this._selectionService.disable(); + } + } else { + element.classList.remove(MouseEventCssClasses.ENABLE_MOUSE_EVENTS); + this._selectionService.enable(); + } + } + private _handleProtocolChange(ctx: IMouseBindContext, eventListeners: Record<'mouseup' | 'wheel' | 'mousedrag' | 'mousemove', EventListener>, events: CoreMouseEventType): void { const { element, document } = ctx.target; const { requestedEvents } = ctx; @@ -361,13 +405,11 @@ export class MouseService implements IMouseService { if (this._optionsService.rawOptions.logLevel === 'debug') { this._logService.debug('Binding to mouse events:', this._explainEvents(events)); } - element.classList.add('enable-mouse-events'); - this._selectionService.disable(); } else { this._logService.debug('Unbinding from mouse events.'); - element.classList.remove('enable-mouse-events'); - this._selectionService.enable(); } + this._syncMouseModeState(element); + this._altMouseCursor?.sync(); // add/remove handlers from requestedEvents if (!(events & CoreMouseEventType.MOVE)) { @@ -537,3 +579,64 @@ export class MouseService implements IMouseService { } } + +/** + * Toggles MouseEventCssClasses.ENABLE_MOUSE_EVENTS on the terminal element while alt is held when + * `mouseEventsRequireAlt` is active. DOM listeners are only registered while active. + */ +export class AltMouseCursorController implements IDisposable { + private readonly _listeners = new MutableDisposable(); + + constructor( + private readonly _element: HTMLElement, + private readonly _document: Document, + private readonly _isActive: () => boolean + ) { + } + + public dispose(): void { + this._listeners.dispose(); + } + + public sync(): void { + this._listeners.clear(); + + if (!this._isActive()) { + return; + } + + const store = new DisposableStore(); + const syncFromModifier = (ev: KeyboardEvent | MouseEvent): void => this.syncFromModifier(ev); + store.add(addDisposableListener(this._document, 'keydown', syncFromModifier)); + store.add(addDisposableListener(this._document, 'keyup', syncFromModifier)); + store.add(addDisposableListener(this._element, 'mousemove', syncFromModifier)); + const targetWindow = this._element.ownerDocument?.defaultView; + if (targetWindow) { + store.add(addDisposableListener(targetWindow, 'blur', () => { + if (this._isActive()) { + this.resetClass(); + } + })); + } + this._listeners.value = store; + } + + public resetClass(): void { + this._updateClass(false); + } + + public syncFromModifier(ev: KeyboardEvent | MouseEvent): void { + if (!this._isActive()) { + return; + } + this._updateClass(ev.getModifierState('Alt')); + } + + private _updateClass(altHeld: boolean): void { + if (altHeld) { + this._element.classList.add(MouseEventCssClasses.ENABLE_MOUSE_EVENTS); + } else { + this._element.classList.remove(MouseEventCssClasses.ENABLE_MOUSE_EVENTS); + } + } +} diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index 83e3d3379..75cd55418 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -3,14 +3,14 @@ * @license MIT */ -import { RenderDebouncer } from 'browser/RenderDebouncer'; -import { IRenderDebouncerWithCallback } from 'browser/Types'; -import { IRenderDimensions, IRenderer } from 'browser/renderer/shared/Types'; -import { ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services'; -import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle'; -import { DebouncedIdleTask } from 'common/TaskQueue'; -import { IBufferService, ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services'; -import { Emitter } from 'common/Event'; +import { RenderDebouncer } from '../RenderDebouncer'; +import { IRenderDebouncerWithCallback } from '../Types'; +import { IRenderDimensions, IRenderer } from '../renderer/shared/Types'; +import { ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from './Services'; +import { Disposable, MutableDisposable, toDisposable } from '../../common/Lifecycle'; +import { DebouncedIdleTask } from '../../common/TaskQueue'; +import { IBufferService, ICoreService, IDecorationService, ILogService, IOptionsService } from '../../common/services/Services'; +import { Emitter } from '../../common/Event'; interface ISelectionState { start: [number, number] | undefined; @@ -29,6 +29,7 @@ export class RenderService extends Disposable implements IRenderService { private _renderDebouncer: IRenderDebouncerWithCallback; private _pausedResizeTask: DebouncedIdleTask; private _observerDisposable = this._register(new MutableDisposable()); + private _intersectionObserver: IntersectionObserver | undefined; private _isPaused: boolean = false; private _needsFullRefresh: boolean = false; @@ -127,8 +128,12 @@ export class RenderService extends Disposable implements IRenderService { // and resume based on terminal visibility if so if ('IntersectionObserver' in w) { const observer = new w.IntersectionObserver(e => this._handleIntersectionChange(e[e.length - 1]), { threshold: 0 }); + this._observerDisposable.value = toDisposable(() => { + this._intersectionObserver?.disconnect(); + this._intersectionObserver = undefined; + }); + this._intersectionObserver = observer; observer.observe(screenElement); - this._observerDisposable.value = toDisposable(() => observer.disconnect()); } } diff --git a/src/browser/services/SelectionService.test.ts b/src/browser/services/SelectionService.test.ts index be62ccc6b..1f65e909e 100644 --- a/src/browser/services/SelectionService.test.ts +++ b/src/browser/services/SelectionService.test.ts @@ -5,16 +5,15 @@ import { assert } from 'chai'; import { SelectionService, SelectionMode } from './SelectionService'; -import { SelectionModel } from 'browser/selection/SelectionModel'; -import { IBufferLine } from 'common/Types'; -import { MockBufferService, MockOptionsService, MockCoreService, createCellData } from 'common/TestUtils.test'; -import { BufferLine } from 'common/buffer/BufferLine'; -import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache'; -import { IBufferService, IOptionsService } from 'common/services/Services'; -import { MockCoreBrowserService, MockMouseService, MockRenderService } from 'browser/TestUtils.test'; -import { CellData } from 'common/buffer/CellData'; -import { IBuffer } from 'common/buffer/Types'; -import { IRenderService } from 'browser/services/Services'; +import { SelectionModel } from '../selection/SelectionModel'; +import { IBuffer, IBufferLine } from '../../common/buffer/Types'; +import { MockBufferService, MockOptionsService, MockCoreService, MockMouseStateService, createCellData } from '../../common/TestUtils.test'; +import { BufferLine } from '../../common/buffer/BufferLine'; +import { BufferLineStringCache } from '../../common/buffer/BufferLineStringCache'; +import { IBufferService, IOptionsService } from '../../common/services/Services'; +import { MockCoreBrowserService, MockMouseService, MockRenderService } from '../TestUtils.test'; +import { CellData } from '../../common/buffer/CellData'; +import { IRenderService } from './Services'; const TEST_STRING_CACHE = new BufferLineStringCache(); @@ -22,9 +21,10 @@ class TestSelectionService extends SelectionService { constructor( bufferService: IBufferService, optionsService: IOptionsService, - renderService: IRenderService + renderService: IRenderService, + public readonly mouseStateService: MockMouseStateService ) { - super(null!, null!, null!, bufferService, new MockCoreService(), new MockMouseService(), optionsService, renderService, new MockCoreBrowserService()); + super(null!, null!, null!, bufferService, new MockCoreService(), new MockMouseService(), optionsService, mouseStateService, renderService, new MockCoreBrowserService()); } public get model(): SelectionModel { return this._model; } @@ -45,16 +45,18 @@ describe('SelectionService', () => { let buffer: IBuffer; let bufferService: IBufferService; let optionsService: IOptionsService; + let mouseStateService: MockMouseStateService; let selectionService: TestSelectionService; beforeEach(() => { optionsService = new MockOptionsService(); + mouseStateService = new MockMouseStateService(); bufferService = new MockBufferService(20, 20, optionsService); buffer = bufferService.buffer; const renderService = new MockRenderService(); renderService.dimensions.css.canvas.height = 10 * 20; renderService.dimensions.css.canvas.width = 10 * 20; - selectionService = new TestSelectionService(bufferService, optionsService, renderService); + selectionService = new TestSelectionService(bufferService, optionsService, renderService, mouseStateService); }); function stringToRow(text: string): IBufferLine { @@ -499,5 +501,21 @@ describe('SelectionService', () => { assert.isFalse(selectionService.areCoordsInSelection([2, 1], [2, 0], [2, 1])); }); }); + + describe('shouldForceSelection', () => { + it('should force selection without alt when mouseEventsRequireAlt is enabled', () => { + optionsService.options.mouseEventsRequireAlt = true; + mouseStateService.areMouseEventsActive = true; + assert.isTrue(selectionService.shouldForceSelection({ altKey: false } as MouseEvent)); + assert.isFalse(selectionService.shouldForceSelection({ altKey: true } as MouseEvent)); + }); + + it('should take precedence over macOptionClickForcesSelection', () => { + optionsService.options.mouseEventsRequireAlt = true; + optionsService.options.macOptionClickForcesSelection = true; + mouseStateService.areMouseEventsActive = true; + assert.isFalse(selectionService.shouldForceSelection({ altKey: true } as MouseEvent)); + }); + }); }); diff --git a/src/browser/services/SelectionService.ts b/src/browser/services/SelectionService.ts index 39692a871..39d8dd76b 100644 --- a/src/browser/services/SelectionService.ts +++ b/src/browser/services/SelectionService.ts @@ -3,20 +3,20 @@ * @license MIT */ -import { IBufferRange, ILinkifier2 } from 'browser/Types'; -import { getCoordsRelativeToElement } from 'browser/input/Mouse'; -import { moveToCellSequence } from 'browser/input/MoveToCell'; -import { SelectionModel } from 'browser/selection/SelectionModel'; -import { ISelectionRedrawRequestEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types'; -import { ICoreBrowserService, IMouseCoordsService, IRenderService, ISelectionService } from 'browser/services/Services'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import * as Browser from 'common/Platform'; -import { IBufferLine, ICellData, IDisposable } from 'common/Types'; -import { getRangeLength } from 'common/buffer/BufferRange'; -import { CellData } from 'common/buffer/CellData'; -import { IBuffer } from 'common/buffer/Types'; -import { IBufferService, ICoreService, IOptionsService } from 'common/services/Services'; -import { Emitter } from 'common/Event'; +import { IBufferRange, ILinkifier2 } from '../Types'; +import { getCoordsRelativeToElement } from '../input/Mouse'; +import { moveToCellSequence } from '../input/MoveToCell'; +import { SelectionModel } from '../selection/SelectionModel'; +import { ISelectionRedrawRequestEvent, ISelectionRequestScrollLinesEvent } from '../selection/Types'; +import { ICoreBrowserService, IMouseCoordsService, IRenderService, ISelectionService } from './Services'; +import { Disposable, MutableDisposable, toDisposable } from '../../common/Lifecycle'; +import * as Browser from '../../common/Platform'; +import { IDisposable } from '../../common/Types'; +import { IBuffer, IBufferLine, ICellData } from '../../common/buffer/Types'; +import { getRangeLength } from '../../common/buffer/BufferRange'; +import { CellData } from '../../common/buffer/CellData'; +import { IBufferService, ICoreService, IMouseStateService, IOptionsService } from '../../common/services/Services'; +import { Emitter } from '../../common/Event'; const enum Constants { /** @@ -102,7 +102,7 @@ export class SelectionService extends Disposable implements ISelectionService { private _mouseMoveListener: EventListener; private _mouseUpListener: EventListener; - private _trimListener: IDisposable; + private readonly _trimListener = this._register(new MutableDisposable()); private _workCell: CellData = new CellData(); private _mouseDownTimeStamp: number = 0; @@ -127,6 +127,7 @@ export class SelectionService extends Disposable implements ISelectionService { @ICoreService private readonly _coreService: ICoreService, @IMouseCoordsService private readonly _mouseCoordsService: IMouseCoordsService, @IOptionsService private readonly _optionsService: IOptionsService, + @IMouseStateService private readonly _mouseStateService: IMouseStateService, @IRenderService private readonly _renderService: IRenderService, @ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService ) { @@ -140,7 +141,7 @@ export class SelectionService extends Disposable implements ISelectionService { this.clearSelection(); } }); - this._trimListener = this._bufferService.buffer.lines.onTrim(amount => this._handleTrim(amount)); + this._trimListener.value = this._bufferService.buffer.lines.onTrim(amount => this._handleTrim(amount)); this._register(this._bufferService.buffers.onBufferActivate(e => this._handleBufferActivate(e))); this.enable(); @@ -434,6 +435,10 @@ export class SelectionService extends Disposable implements ISelectionService { * @param event The mouse event. */ public shouldForceSelection(event: MouseEvent): boolean { + if (this._optionsService.rawOptions.mouseEventsRequireAlt && this._mouseStateService.areMouseEventsActive) { + return !event.altKey; + } + if (Browser.isMac) { return event.altKey && this._optionsService.rawOptions.macOptionClickForcesSelection; } @@ -458,6 +463,10 @@ export class SelectionService extends Disposable implements ISelectionService { return; } + if (this._optionsService.rawOptions.mouseEventsRequireAlt && this._mouseStateService.areMouseEventsActive && event.altKey) { + return; + } + // Allow selection when using a specific modifier key, even when disabled if (!this._enabled) { if (!this.shouldForceSelection(event)) { @@ -596,6 +605,9 @@ export class SelectionService extends Disposable implements ISelectionService { * @param event the mouse or keyboard event */ public shouldColumnSelect(event: KeyboardEvent | MouseEvent): boolean { + if (this._optionsService.rawOptions.mouseEventsRequireAlt && this._mouseStateService.areMouseEventsActive) { + return false; + } return event.altKey && !(Browser.isMac && this._optionsService.rawOptions.macOptionClickForcesSelection); } @@ -692,7 +704,7 @@ export class SelectionService extends Disposable implements ISelectionService { if (this._activeSelectionMode !== SelectionMode.COLUMN) { this._model.selectionEnd[0] = this._bufferService.cols; } - this._model.selectionEnd[1] = Math.min(buffer.ydisp + this._bufferService.rows, buffer.lines.length - 1); + this._model.selectionEnd[1] = Math.min(buffer.ydisp + this._bufferService.rows - 1, buffer.lines.length - 1); } else { if (this._activeSelectionMode !== SelectionMode.COLUMN) { this._model.selectionEnd[0] = 0; @@ -769,8 +781,7 @@ export class SelectionService extends Disposable implements ISelectionService { // reverseIndex) and delete in a splice is only ever used when the same // number of elements was just added. Given this is could actually be // beneficial to leave the selection as is for these cases. - this._trimListener.dispose(); - this._trimListener = e.activeBuffer.lines.onTrim(amount => this._handleTrim(amount)); + this._trimListener.value = e.activeBuffer.lines.onTrim(amount => this._handleTrim(amount)); } /** @@ -919,10 +930,10 @@ export class SelectionService extends Disposable implements ISelectionService { // Calculate the start _column_, converting the the string indexes back to // column coordinates. let start = - startIndex // The index of the selection's start char in the line string - + charOffset // The difference between the initial char's column and index - - leftWideCharCount // The number of wide chars left of the initial char - + leftLongCharOffset; // The number of additional chars left of the initial char added by columns with strings longer than 1 (emojis) + startIndex // The index of the selection's start char in the line string + + charOffset // The difference between the initial char's column and index + - leftWideCharCount // The number of wide chars left of the initial char + + leftLongCharOffset; // The number of additional chars left of the initial char added by columns with strings longer than 1 (emojis) // Calculate the length in _columns_, converting the the string indexes back // to column coordinates. diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts index 72659cafe..2b8e06b7d 100644 --- a/src/browser/services/Services.ts +++ b/src/browser/services/Services.ts @@ -3,12 +3,12 @@ * @license MIT */ -import { IRenderDimensions, IRenderer } from 'browser/renderer/shared/Types'; -import { IColorSet, ILink, ReadonlyColorSet } from 'browser/Types'; -import { ISelectionRedrawRequestEvent as ISelectionRequestRedrawEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types'; -import { createDecorator } from 'common/services/ServiceRegistry'; -import { AllColorIndex, IDisposable, IKeyboardResult } from 'common/Types'; -import type { IEvent } from 'common/Event'; +import { IRenderDimensions, IRenderer } from '../renderer/shared/Types'; +import { IColorSet, ILink, ReadonlyColorSet } from '../Types'; +import { ISelectionRedrawRequestEvent as ISelectionRequestRedrawEvent, ISelectionRequestScrollLinesEvent } from '../selection/Types'; +import { createDecorator } from '../../common/services/ServiceRegistry'; +import { AllColorIndex, IDisposable, IKeyboardResult } from '../../common/Types'; +import type { IEvent } from '../../common/Event'; export const ICharSizeService = createDecorator('CharSizeService'); export interface ICharSizeService { diff --git a/src/browser/services/ThemeService.test.ts b/src/browser/services/ThemeService.test.ts index a36dea31c..08a319ef5 100644 --- a/src/browser/services/ThemeService.test.ts +++ b/src/browser/services/ThemeService.test.ts @@ -5,9 +5,9 @@ import jsdom = require('jsdom'); import { assert } from 'chai'; -import { ThemeService } from 'browser/services/ThemeService'; -import { OptionsService } from 'common/services/OptionsService'; -import { DEFAULT_ANSI_COLORS } from 'browser/Types'; +import { ThemeService } from './ThemeService'; +import { OptionsService } from '../../common/services/OptionsService'; +import { DEFAULT_ANSI_COLORS } from '../Types'; describe('ThemeService', () => { let themeService: ThemeService; diff --git a/src/browser/services/ThemeService.ts b/src/browser/services/ThemeService.ts index f2b23f3ce..e12e5e2b3 100644 --- a/src/browser/services/ThemeService.ts +++ b/src/browser/services/ThemeService.ts @@ -3,14 +3,14 @@ * @license MIT */ -import { ColorContrastCache } from 'browser/ColorContrastCache'; -import { IThemeService } from 'browser/services/Services'; -import { DEFAULT_ANSI_COLORS, IColorContrastCache, IColorSet, ReadonlyColorSet } from 'browser/Types'; -import { color, css, NULL_COLOR } from 'common/Color'; -import { Disposable } from 'common/Lifecycle'; -import { IOptionsService, ITheme } from 'common/services/Services'; -import { AllColorIndex, IColor, SpecialColorIndex } from 'common/Types'; -import { Emitter } from 'common/Event'; +import { ColorContrastCache } from '../ColorContrastCache'; +import { IThemeService } from './Services'; +import { DEFAULT_ANSI_COLORS, IColorContrastCache, IColorSet, ReadonlyColorSet } from '../Types'; +import { color, css, NULL_COLOR } from '../../common/Color'; +import { Disposable } from '../../common/Lifecycle'; +import { IOptionsService, ITheme } from '../../common/services/Services'; +import { AllColorIndex, IColor, SpecialColorIndex } from '../../common/Types'; +import { Emitter } from '../../common/Event'; interface IRestoreColorSet { foreground: IColor; @@ -132,7 +132,7 @@ export class ThemeService extends Disposable implements IThemeService { colors.ansi[i + 16] = parseColor(theme.extendedAnsi[i], DEFAULT_ANSI_COLORS[i + 16]); } } - // Clear our the cache + // Clear the cache this._contrastCache.clear(); this._halfContrastCache.clear(); this._updateRestoreColors(); diff --git a/src/browser/tsconfig.json b/src/browser/tsconfig.json index ff5bf6ad7..52c2051ab 100644 --- a/src/browser/tsconfig.json +++ b/src/browser/tsconfig.json @@ -9,17 +9,15 @@ "types": [ "../../node_modules/@types/mocha" ], - "skipLibCheck": true, - "paths": { - "common/*": [ "./../common/*" ], - "*": [ "./../*" ] - } + "skipLibCheck": true }, "include": [ "./**/*", "../../typings/xterm.d.ts" ], "references": [ - { "path": "../common" } + { + "path": "../common" + } ] } diff --git a/src/common/Async.ts b/src/common/Async.ts index 7345f19da..3189d6293 100644 --- a/src/common/Async.ts +++ b/src/common/Async.ts @@ -5,7 +5,7 @@ * Minimal async helpers for xterm.js core. */ -import { DisposableStore, IDisposable, toDisposable } from 'common/Lifecycle'; +import { DisposableStore, IDisposable, toDisposable } from './Lifecycle'; export function timeout(millis: number): Promise { return new Promise(resolve => setTimeout(resolve, millis)); @@ -73,6 +73,42 @@ export class TimeoutTimer implements IDisposable { } } +/** + * Schedules a single runner on the microtask queue. Unlike {@link TimeoutTimer}, a scheduled + * microtask cannot be unqueued; {@link cancel} prevents the runner from executing if it has not + * run yet. + */ +export class MicrotaskTimer implements IDisposable { + private _isScheduled = false; + private _isDisposed = false; + + public dispose(): void { + this.cancel(); + this._isDisposed = true; + } + + public cancel(): void { + this._isScheduled = false; + } + + public set(runner: () => void): void { + if (this._isDisposed) { + throw new Error('Calling set on a disposed MicrotaskTimer'); + } + if (this._isScheduled) { + return; + } + this._isScheduled = true; + queueMicrotask(() => { + if (!this._isScheduled) { + return; + } + this._isScheduled = false; + runner(); + }); + } +} + export class IntervalTimer implements IDisposable { private _disposable: IDisposable | undefined; private _isDisposed = false; diff --git a/src/common/CircularList.test.ts b/src/common/CircularList.test.ts index 7a578a8cc..4c07b16c3 100644 --- a/src/common/CircularList.test.ts +++ b/src/common/CircularList.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { CircularList } from 'common/CircularList'; +import { CircularList } from './CircularList'; describe('CircularList', () => { describe('push', () => { diff --git a/src/common/CircularList.ts b/src/common/CircularList.ts index 3663bfc17..b773391f9 100644 --- a/src/common/CircularList.ts +++ b/src/common/CircularList.ts @@ -3,9 +3,8 @@ * @license MIT */ -import { ICircularList } from 'common/Types'; -import { Disposable } from 'common/Lifecycle'; -import { Emitter } from 'common/Event'; +import { Disposable } from './Lifecycle'; +import { Emitter, type IEvent } from './Event'; export interface IInsertEvent { index: number; @@ -17,6 +16,28 @@ export interface IDeleteEvent { amount: number; } +export interface ICircularList { + length: number; + maxLength: number; + isFull: boolean; + + onDeleteEmitter: Emitter; + onDelete: IEvent; + onInsertEmitter: Emitter; + onInsert: IEvent; + onTrimEmitter: Emitter; + onTrim: IEvent; + + get(index: number): T | undefined; + set(index: number, value: T): void; + push(value: T): void; + recycle(): T; + pop(): T | undefined; + splice(start: number, deleteCount: number, ...items: T[]): void; + trimStart(count: number): void; + shiftElements(start: number, count: number, offset: number): void; +} + /** * Represents a circular list; a list with a maximum size that wraps around when push is called, * overriding values at the start of the list. diff --git a/src/common/Clone.test.ts b/src/common/Clone.test.ts deleted file mode 100644 index 5fbe4bf9b..000000000 --- a/src/common/Clone.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { assert } from 'chai'; -import { clone } from 'common/Clone'; - -describe('clone', () => { - it('should clone simple objects', () => { - const test = { - a: 1, - b: 2 - }; - - assert.deepEqual(clone(test), { a: 1, b: 2 }); - }); - - it('should clone nested objects', () => { - const test = { - bar: { - a: 1, - b: 2, - c: { - foo: 'bar' - } - } - }; - - assert.deepEqual(clone(test), { - bar: { - a: 1, - b: 2, - c: { - foo: 'bar' - } - } - }); - }); - - it('should clone array values', () => { - const test = { - a: [1, 2, 3], - b: [1, null, 'test', { foo: 'bar' }] - }; - - assert.deepEqual(clone(test), { - a: [1, 2, 3], - b: [1, null, 'test', { foo: 'bar' }] - }); - }); - - it('should stop mutation from occuring on the original object', () => { - const test = { - a: 1, - b: 2, - c: { - foo: 'bar' - } - }; - - const cloned = clone(test); - - test.a = 5; - test.c.foo = 'barbaz'; - - assert.deepEqual(cloned, { - a: 1, - b: 2, - c: { - foo: 'bar' - } - }); - }); - - it('should clone to a maximum depth of 5 by default', () => { - const test = { - a: { - b: { - c: { - d: { - e: { - f: 'foo' - } - } - } - } - } - }; - - const cloned = clone(test); - - test.a.b.c.d.e.f = 'bar'; - - // The values at a greater depth then 5 should not be cloned - assert.equal((cloned as any).a.b.c.d.e.f, 'bar'); - }); - - it('should allow an optional maximum depth to be set', () => { - const test = { - a: { - b: { - c: 'foo' - } - } - }; - - const cloned = clone(test, 2); - - test.a.b.c = 'bar'; - - // The values at a greater depth then 2 should not be cloned - assert.equal((cloned as any).a.b.c, 'bar'); - }); - - it('should not throw when cloning a recursive reference', () => { - const test = { - a: { - b: { - c: {} - } - } - }; - - test.a.b.c = test; - - assert.doesNotThrow(() => clone(test)); - }); -}); diff --git a/src/common/Clone.ts b/src/common/Clone.ts deleted file mode 100644 index 37821fe02..000000000 --- a/src/common/Clone.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -/* - * A simple utility for cloning values - */ -export function clone(val: T, depth: number = 5): T { - if (typeof val !== 'object') { - return val; - } - - // If we're cloning an array, use an array as the base, otherwise use an object - const clonedObject: any = Array.isArray(val) ? [] : {}; - - for (const key in val) { - // Recursively clone eack item unless we're at the maximum depth - clonedObject[key] = depth <= 1 ? val[key] : (val[key] && clone(val[key], depth - 1)); - } - - return clonedObject as T; -} diff --git a/src/common/Color.test.ts b/src/common/Color.test.ts index dbe759b4f..5f4140d9e 100644 --- a/src/common/Color.test.ts +++ b/src/common/Color.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { channels, color, css, rgb, rgba, toPaddedHex, contrastRatio } from 'common/Color'; +import { channels, color, css, rgb, rgba, toPaddedHex, contrastRatio } from './Color'; describe('Color', () => { diff --git a/src/common/Color.ts b/src/common/Color.ts index b3d13fc99..b8a9d8d60 100644 --- a/src/common/Color.ts +++ b/src/common/Color.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IColor, IColorRGB } from 'common/Types'; +import { IColor, IColorRGB } from './Types'; let $r = 0; let $g = 0; @@ -177,9 +177,9 @@ export namespace css { // Formats: rgb() or rgba() const rgbaMatch = css.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(,\s*(0|1|\d?\.(\d+))\s*)?\)/); if (rgbaMatch) { - $r = parseInt(rgbaMatch[1]); - $g = parseInt(rgbaMatch[2]); - $b = parseInt(rgbaMatch[3]); + $r = parseInt(rgbaMatch[1], 10); + $g = parseInt(rgbaMatch[2], 10); + $b = parseInt(rgbaMatch[3], 10); $a = Math.round((rgbaMatch[5] === undefined ? 1 : parseFloat(rgbaMatch[5])) * 0xFF); return channels.toColor($r, $g, $b, $a); } @@ -373,7 +373,7 @@ export function toPaddedHex(c: number): string { /** * Gets the contrast ratio between two relative luminance values. * @param l1 The first relative luminance. - * @param l2 The first relative luminance. + * @param l2 The second relative luminance. * @see https://www.w3.org/TR/WCAG20/#contrast-ratiodef */ export function contrastRatio(l1: number, l2: number): number { diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 9bd7faaf5..cf16c1e14 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -21,28 +21,43 @@ * http://linux.die.net/man/7/urxvt */ -import { IInstantiationService, IOptionsService, IBufferService, ILogService, ICharsetService, ICoreService, IMouseStateService, IUnicodeService, LogLevelEnum, ITerminalOptions, IOscLinkService } from 'common/services/Services'; -import { InstantiationService } from 'common/services/InstantiationService'; -import { LogService } from 'common/services/LogService'; -import { BufferService, BufferServiceConstants } from 'common/services/BufferService'; -import { OptionsService } from 'common/services/OptionsService'; -import { IDisposable, IAttributeData, ICoreTerminal, IScrollEvent } from 'common/Types'; -import { CoreService } from 'common/services/CoreService'; -import { MouseStateService } from 'common/services/MouseStateService'; -import { UnicodeService } from 'common/services/UnicodeService'; -import { CharsetService } from 'common/services/CharsetService'; -import { updateWindowsModeWrappedState } from 'common/WindowsMode'; -import { IFunctionIdentifier, IParams } from 'common/parser/Types'; -import { IBufferSet } from 'common/buffer/Types'; -import { InputHandler } from 'common/InputHandler'; -import { WriteBuffer } from 'common/input/WriteBuffer'; -import { OscLinkService } from 'common/services/OscLinkService'; -import { Emitter, EventUtils, type IEvent } from 'common/Event'; -import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle'; +import { IInstantiationService, IOptionsService, IBufferService, ILogService, ICharsetService, ICoreService, IMouseStateService, IUnicodeService, LogLevelEnum, IOscLinkService } from './services/Services'; +import { InstantiationService } from './services/InstantiationService'; +import { LogService } from './services/LogService'; +import { BufferService, BufferServiceConstants } from './services/BufferService'; +import { OptionsService } from './services/OptionsService'; +import { IDisposable, IScrollEvent, ITerminalOptions, IParams } from './Types'; +import { IAttributeData, IBufferSet } from './buffer/Types'; +import { CoreService } from './services/CoreService'; +import { MouseStateService } from './services/MouseStateService'; +import { UnicodeV6 } from './input/UnicodeV6'; +import { UnicodeService } from './services/UnicodeService'; +import { CharsetService } from './services/CharsetService'; +import { updateWindowsModeWrappedState } from './WindowsMode'; +import { IFunctionIdentifier } from './parser/Types'; +import { InputHandler } from './InputHandler'; +import { WriteBuffer } from './input/WriteBuffer'; +import { OscLinkService } from './services/OscLinkService'; +import { Emitter, EventUtils, type IEvent } from './Event'; +import { Disposable, MutableDisposable, toDisposable } from './Lifecycle'; // Only trigger this warning a single time per session let hasWriteSyncWarnHappened = false; +export interface ICoreTerminal { + mouseStateService: IMouseStateService; + coreService: ICoreService; + optionsService: IOptionsService; + unicodeService: IUnicodeService; + buffers: IBufferSet; + options: Required; + registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise): IDisposable; + registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise): IDisposable; + registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise): IDisposable; + registerOscHandler(ident: number, callback: (data: string) => boolean | Promise): IDisposable; + registerApcHandler(id: IFunctionIdentifier, callback: (data: string) => boolean | Promise): IDisposable; +} + export abstract class CoreTerminal extends Disposable implements ICoreTerminal { protected readonly _instantiationService: IInstantiationService; protected readonly _bufferService: IBufferService; @@ -116,6 +131,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { this.mouseStateService = this._register(this._instantiationService.createInstance(MouseStateService)); this._instantiationService.setService(IMouseStateService, this.mouseStateService); this.unicodeService = this._register(this._instantiationService.createInstance(UnicodeService)); + this.unicodeService.register(new UnicodeV6()); this._instantiationService.setService(IUnicodeService, this.unicodeService); this._charsetService = this._instantiationService.createInstance(CharsetService); this._instantiationService.setService(ICharsetService, this._charsetService); @@ -263,7 +279,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { private _handleWindowsPtyOptionChange(): void { let value = false; const windowsPty = this.optionsService.rawOptions.windowsPty; - if (windowsPty && windowsPty.buildNumber !== undefined && windowsPty.buildNumber !== undefined) { + if (windowsPty && windowsPty.backend !== undefined && windowsPty.buildNumber !== undefined) { value = !!(windowsPty.backend === 'conpty' && windowsPty.buildNumber < 21376); } if (value) { diff --git a/src/common/Event.test.ts b/src/common/Event.test.ts index 8d1cfadd5..a8d09c5ce 100644 --- a/src/common/Event.test.ts +++ b/src/common/Event.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { Emitter } from 'common/Event'; +import { Emitter } from './Event'; describe('Emitter', () => { it('should fire with 0 listeners without error', () => { diff --git a/src/common/Event.ts b/src/common/Event.ts index f92ab2ac1..88417fc83 100644 --- a/src/common/Event.ts +++ b/src/common/Event.ts @@ -6,7 +6,7 @@ * Simplified from VS Code's event.ts - no leak detection/profiling. */ -import { IDisposable, DisposableStore, toDisposable } from 'common/Lifecycle'; +import { IDisposable, DisposableStore, toDisposable } from './Lifecycle'; export interface IEvent { (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable; diff --git a/src/common/InputHandler.test.ts b/src/common/InputHandler.test.ts index f9da81a25..9eab8cfa2 100644 --- a/src/common/InputHandler.test.ts +++ b/src/common/InputHandler.test.ts @@ -4,20 +4,22 @@ */ import { assert } from 'chai'; -import { InputHandler } from 'common/InputHandler'; -import { IBufferLine, IAttributeData, IColorEvent, ColorRequestType, SpecialColorIndex } from 'common/Types'; -import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { CellData } from 'common/buffer/CellData'; -import { Attributes, BgFlags, UnderlineStyle } from 'common/buffer/Constants'; -import { AttributeData, ExtendedAttrs } from 'common/buffer/AttributeData'; -import { Params } from 'common/parser/Params'; -import { MockCoreService, MockBufferService, MockOptionsService, MockLogService, MockMouseStateService, MockCharsetService, MockUnicodeService, MockOscLinkService, extendedAttributes } from 'common/TestUtils.test'; -import { IBufferService, ICoreService, type IOscLinkService } from 'common/services/Services'; -import { DEFAULT_OPTIONS } from 'common/services/OptionsService'; -import { clone } from 'common/Clone'; -import { BufferService } from 'common/services/BufferService'; -import { CoreService } from 'common/services/CoreService'; -import { OscLinkService } from 'common/services/OscLinkService'; +import { InputHandler } from './InputHandler'; +import { IColorEvent, ColorRequestType, SpecialColorIndex } from './Types'; +import { IAttributeData, IBufferLine } from './buffer/Types'; +import { DEFAULT_ATTR_DATA } from './buffer/BufferLine'; +import { CellData } from './buffer/CellData'; +import { Attributes, BgFlags, UnderlineStyle } from './buffer/Constants'; +import { AttributeData, ExtendedAttrs } from './buffer/AttributeData'; +import { Params } from './parser/Params'; +import { MockCoreService, MockBufferService, MockOptionsService, MockLogService, MockMouseStateService, MockCharsetService, MockUnicodeService, MockOscLinkService, extendedAttributes } from './TestUtils.test'; +import { IBufferService, ICoreService, type IOscLinkService } from './services/Services'; +import { DEFAULT_OPTIONS } from './services/OptionsService'; +import { BufferService } from './services/BufferService'; +import { CharsetService } from './services/CharsetService'; +import { CoreService } from './services/CoreService'; +import { OscLinkService } from './services/OscLinkService'; +import { CHARSETS } from './data/Charsets'; function getCursor(bufferService: IBufferService): number[] { @@ -227,32 +229,32 @@ describe('InputHandler', () => { assert.equal(coreService.decPrivateModes.cursorStyle, undefined); assert.equal(coreService.decPrivateModes.cursorBlink, undefined); - optionsService.options = clone(DEFAULT_OPTIONS); + optionsService.options = structuredClone(DEFAULT_OPTIONS); inputHandler.setCursorStyle(Params.fromArray([1])); assert.equal(coreService.decPrivateModes.cursorStyle, 'block'); assert.equal(coreService.decPrivateModes.cursorBlink, true); - optionsService.options = clone(DEFAULT_OPTIONS); + optionsService.options = structuredClone(DEFAULT_OPTIONS); inputHandler.setCursorStyle(Params.fromArray([2])); assert.equal(coreService.decPrivateModes.cursorStyle, 'block'); assert.equal(coreService.decPrivateModes.cursorBlink, false); - optionsService.options = clone(DEFAULT_OPTIONS); + optionsService.options = structuredClone(DEFAULT_OPTIONS); inputHandler.setCursorStyle(Params.fromArray([3])); assert.equal(coreService.decPrivateModes.cursorStyle, 'underline'); assert.equal(coreService.decPrivateModes.cursorBlink, true); - optionsService.options = clone(DEFAULT_OPTIONS); + optionsService.options = structuredClone(DEFAULT_OPTIONS); inputHandler.setCursorStyle(Params.fromArray([4])); assert.equal(coreService.decPrivateModes.cursorStyle, 'underline'); assert.equal(coreService.decPrivateModes.cursorBlink, false); - optionsService.options = clone(DEFAULT_OPTIONS); + optionsService.options = structuredClone(DEFAULT_OPTIONS); inputHandler.setCursorStyle(Params.fromArray([5])); assert.equal(coreService.decPrivateModes.cursorStyle, 'bar'); assert.equal(coreService.decPrivateModes.cursorBlink, true); - optionsService.options = clone(DEFAULT_OPTIONS); + optionsService.options = structuredClone(DEFAULT_OPTIONS); inputHandler.setCursorStyle(Params.fromArray([6])); assert.equal(coreService.decPrivateModes.cursorStyle, 'bar'); assert.equal(coreService.decPrivateModes.cursorBlink, false); @@ -639,19 +641,38 @@ describe('InputHandler', () => { }); describe('print', () => { it('should not cause an infinite loop (regression test)', () => { - const inputHandler = new TestInputHandler( - new MockBufferService(80, 30), - new MockCharsetService(), - new MockCoreService(), - new MockLogService(), - new MockOptionsService(), - new MockOscLinkService(), - new MockMouseStateService(), - new MockUnicodeService() - ); const container = new Uint32Array(10); container[0] = 0x200B; + const lineCountBefore = bufferService.buffer.lines.length; inputHandler.print(container, 0, 1); + assert.strictEqual(bufferService.buffer.y, 0); + assert.strictEqual(bufferService.buffer.lines.length, lineCountBefore); + }); + it('should join combining characters in a single print', async () => { + await inputHandler.parseP('e\u0301'); + assert.strictEqual(bufferService.buffer.translateBufferLineToString(0, true), 'e\u0301'); + assert.strictEqual(bufferService.buffer.x, 1); + }); + it('should join combining characters split across parse calls', async () => { + await inputHandler.parseP('e'); + await inputHandler.parseP('\u0301'); + assert.strictEqual(bufferService.buffer.translateBufferLineToString(0, true), 'e\u0301'); + assert.strictEqual(bufferService.buffer.x, 1); + }); + it('should repeat preceding grapheme cluster via REP', async () => { + await inputHandler.parseP('e\u0301\x1b[2b'); + assert.strictEqual(bufferService.buffer.translateBufferLineToString(0, true), 'e\u0301e\u0301e\u0301'); + assert.strictEqual(bufferService.buffer.x, 3); + }); + it('should not repeat when REP has no preceding join state', async () => { + await inputHandler.parseP('\x1b[2b'); + assert.strictEqual(bufferService.buffer.translateBufferLineToString(0, true), ''); + assert.strictEqual(bufferService.buffer.x, 0); + }); + it('should not repeat after an intervening escape sequence', async () => { + await inputHandler.parseP('a\x1b[0m\x1b[2b'); + assert.strictEqual(bufferService.buffer.translateBufferLineToString(0, true), 'a'); + assert.strictEqual(bufferService.buffer.x, 1); }); it('should clear cells to the right on early wrap-around', async () => { bufferService.resize(5, 5); @@ -668,6 +689,49 @@ describe('InputHandler', () => { }); }); + describe('ISO-2022 character sets', () => { + let charsetService: CharsetService; + + beforeEach(() => { + charsetService = new CharsetService(); + inputHandler = new TestInputHandler( + bufferService, + charsetService, + coreService, + new MockLogService(), + optionsService, + oscLinkService, + new MockMouseStateService(), + new MockUnicodeService() + ); + }); + + it('should map G0 line drawing via ESC ( 0', async () => { + await inputHandler.parseP('\x1b(0q\x1b(Bq'); + assert.strictEqual(bufferService.buffer.translateBufferLineToString(0, true), '\u2500q'); + }); + + it('should map G1 line drawing after ESC ) 0 and SO', async () => { + await inputHandler.parseP('\x1b)0\x0eq\x0f\x1b(Bq'); + assert.strictEqual(bufferService.buffer.translateBufferLineToString(0, true), '\u2500q'); + }); + + it('should restore charset and glevel on ESC 7 / ESC 8', async () => { + await inputHandler.parseP('\x1b)0\x0e'); + assert.strictEqual(charsetService.glevel, 1); + assert.strictEqual(charsetService.charset, CHARSETS['0']); + await inputHandler.parseP('\x1b7'); + await inputHandler.parseP('\x0f\x1b(B'); + assert.strictEqual(charsetService.glevel, 0); + assert.ok(charsetService.charset === undefined); + await inputHandler.parseP('\x1b8'); + assert.strictEqual(charsetService.glevel, 1); + assert.strictEqual(charsetService.charset, CHARSETS['0']); + await inputHandler.parseP('q'); + assert.strictEqual(bufferService.buffer.translateBufferLineToString(0, true), '\u2500'); + }); + }); + describe('alt screen', () => { let bufferService: IBufferService; let handler: TestInputHandler; @@ -1182,6 +1246,19 @@ describe('InputHandler', () => { await inputHandler.parseP('\x1b[100;100H'); assert.deepEqual(getCursor(bufferService), [9, 9]); }); + it('cursor position (CUP) with DECOM and scroll margins', async () => { + await inputHandler.parseP('\x1b[?6h\x1b[2;3r\x1b[1;1H'); + assert.deepEqual(getCursor(bufferService), [0, 1]); + await inputHandler.parseP('X'); + assert.strictEqual(getLines(bufferService, 3)[1], 'X'); + await inputHandler.parseP('\x1b[2;1H'); + assert.deepEqual(getCursor(bufferService), [0, 2]); + await inputHandler.parseP('\x1b[10;10H'); + assert.deepEqual(getCursor(bufferService), [9, 2]); + await inputHandler.parseP('\x1b[?6l'); + await inputHandler.parseP('\x1b[2;1H'); + assert.deepEqual(getCursor(bufferService), [0, 1]); + }); it('horizontal position absolute (HPA)', async () => { await inputHandler.parseP('\x1b[`'); assert.deepEqual(getCursor(bufferService), [0, 0]); @@ -1241,7 +1318,7 @@ describe('InputHandler', () => { await inputHandler.parseP('\x1b[e'); assert.deepEqual(getCursor(bufferService), [8, 5]); }); - describe('should clamp cursor into addressible range', () => { + describe('should clamp cursor into addressable range', () => { it('CUF', async () => { bufferService.buffer.x = 10000; bufferService.buffer.y = 10000; diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 2b7142dd0..0b12dd8e1 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -4,26 +4,26 @@ * @license MIT */ -import { IInputHandler, IAttributeData, IDisposable, IWindowOptions, IColorEvent, IParseStack, ColorIndex, ColorRequestType, SpecialColorIndex } from 'common/Types'; -import { C0, C1 } from 'common/data/EscapeSequences'; -import { CHARSETS, DEFAULT_CHARSET } from 'common/data/Charsets'; -import { EscapeSequenceParser } from 'common/parser/EscapeSequenceParser'; -import { Disposable } from 'common/Lifecycle'; -import { StringToUtf32, stringFromCodePoint, Utf8ToUtf32 } from 'common/input/TextDecoder'; -import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { IParsingState, IEscapeSequenceParser, IParams, IFunctionIdentifier } from 'common/parser/Types'; -import { NULL_CELL_CODE, NULL_CELL_WIDTH, Attributes, FgFlags, BgFlags, Content, UnderlineStyle } from 'common/buffer/Constants'; -import { CellData } from 'common/buffer/CellData'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { ICoreService, IBufferService, IOptionsService, ILogService, IMouseStateService, ICharsetService, IUnicodeService, LogLevelEnum, IOscLinkService } from 'common/services/Services'; -import { UnicodeService } from 'common/services/UnicodeService'; -import { OscHandler } from 'common/parser/OscParser'; -import { DcsHandler } from 'common/parser/DcsParser'; -import { ApcHandler } from 'common/parser/ApcParser'; -import { IBuffer } from 'common/buffer/Types'; -import { parseColor } from 'common/input/XParseColor'; -import { Emitter } from 'common/Event'; -import { XTERM_VERSION } from 'common/Version'; +import { IInputHandler, IDisposable, IWindowOptions, IColorEvent, IParseStack, ColorIndex, ColorRequestType, SpecialColorIndex } from './Types'; +import { IAttributeData, IBuffer } from './buffer/Types'; +import { C0, C1 } from './data/EscapeSequences'; +import { CHARSETS, DEFAULT_CHARSET } from './data/Charsets'; +import { EscapeSequenceParser } from './parser/EscapeSequenceParser'; +import { Disposable } from './Lifecycle'; +import { StringToUtf32, stringFromCodePoint, Utf8ToUtf32 } from './input/TextDecoder'; +import { BufferLine, DEFAULT_ATTR_DATA } from './buffer/BufferLine'; +import { IParsingState, IEscapeSequenceParser, IParams, IFunctionIdentifier } from './parser/Types'; +import { NULL_CELL_CODE, NULL_CELL_WIDTH, Attributes, FgFlags, BgFlags, Content, UnderlineStyle } from './buffer/Constants'; +import { CellData } from './buffer/CellData'; +import { AttributeData } from './buffer/AttributeData'; +import { ICoreService, IBufferService, IOptionsService, ILogService, IMouseStateService, ICharsetService, IUnicodeService, LogLevelEnum, IOscLinkService } from './services/Services'; +import { UnicodeService } from './services/UnicodeService'; +import { OscHandler } from './parser/OscParser'; +import { DcsHandler } from './parser/DcsParser'; +import { ApcHandler } from './parser/ApcParser'; +import { parseColor } from './input/XParseColor'; +import { Emitter } from './Event'; +import { XTERM_VERSION } from './Version'; /** * Map collect to glevel. Used in `selectCharset`. @@ -567,8 +567,9 @@ export class InputHandler extends Disposable implements IInputHandler { if (screenReaderMode) { this._onA11yChar.fire(stringFromCodePoint(code)); } - if (this._getCurrentLinkId()) { - this._oscLinkService.addLineToLink(this._getCurrentLinkId(), this._activeBuffer.ybase + this._activeBuffer.y); + const linkId = this._getCurrentLinkId(); + if (linkId) { + this._oscLinkService.addLineToLink(linkId, this._activeBuffer.ybase + this._activeBuffer.y); } // goto next line if ch would overflow @@ -2590,10 +2591,6 @@ export class InputHandler extends Disposable implements IInputHandler { * | 3 | CMY color. | #N | * | 4 | CMYK color. | #N | * | 5 | Indexed (256 colors) as `Ps ; 5 ; INDEX` or `Ps : 5 : INDEX`. | #Y | - * - * - * FIXME: blinking is implemented in attrs, but not working in renderers? - * FIXME: remove dead branch for p=100 */ public charAttributes(params: IParams): boolean { // Optimize a single SGR0. @@ -3068,7 +3065,7 @@ export class InputHandler extends Disposable implements IInputHandler { const idx = slots.shift() as string; const spec = slots.shift() as string; if (/^\d+$/.exec(idx)) { - const index = parseInt(idx); + const index = parseInt(idx, 10); if (isValidColorIndex(index)) { if (spec === '?') { event.push({ type: ColorRequestType.REPORT, index }); @@ -3231,7 +3228,7 @@ export class InputHandler extends Disposable implements IInputHandler { const slots = data.split(';'); for (let i = 0; i < slots.length; ++i) { if (/^\d+$/.exec(slots[i])) { - const index = parseInt(slots[i]); + const index = parseInt(slots[i], 10); if (isValidColorIndex(index)) { event.push({ type: ColorRequestType.RESTORE, index }); } diff --git a/src/common/MultiKeyMap.test.ts b/src/common/MultiKeyMap.test.ts index b908321c3..255cec1a1 100644 --- a/src/common/MultiKeyMap.test.ts +++ b/src/common/MultiKeyMap.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { FourKeyMap, TwoKeyMap } from 'common/MultiKeyMap'; +import { FourKeyMap, TwoKeyMap } from './MultiKeyMap'; const strictEqual = assert.strictEqual; diff --git a/src/common/Platform.ts b/src/common/Platform.ts index 09ba097e6..a034ca69c 100644 --- a/src/common/Platform.ts +++ b/src/common/Platform.ts @@ -41,10 +41,10 @@ export function getSafariVersion(): number { if (majorVersion === null || majorVersion.length < 2) { return 0; } - return parseInt(majorVersion[1]); + return parseInt(majorVersion[1], 10); } -// Find the users platform. We use this to interpret the meta key +// Find the user's platform. We use this to interpret the meta key // and ISO third level shifts. // http://stackoverflow.com/q/19877924/577598 export const isMac = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'].includes(platform); diff --git a/src/common/SortedList.test.ts b/src/common/SortedList.test.ts index 4718cf971..a446b7874 100644 --- a/src/common/SortedList.test.ts +++ b/src/common/SortedList.test.ts @@ -4,8 +4,8 @@ */ import { assert } from 'chai'; -import { SortedList } from 'common/SortedList'; -import { MockLogService } from 'common/TestUtils.test'; +import { SortedList } from './SortedList'; +import { MockLogService } from './TestUtils.test'; const deepStrictEqual = assert.deepStrictEqual; diff --git a/src/common/SortedList.ts b/src/common/SortedList.ts index c6dc62085..8a10076e3 100644 --- a/src/common/SortedList.ts +++ b/src/common/SortedList.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { IdleTaskQueue } from 'common/TaskQueue'; -import type { ILogService } from 'common/services/Services'; +import { IdleTaskQueue } from './TaskQueue'; +import type { ILogService } from './services/Services'; // Work variables to avoid garbage collection. let i = 0; diff --git a/src/common/StringBuilder.test.ts b/src/common/StringBuilder.test.ts new file mode 100644 index 000000000..da56c79c2 --- /dev/null +++ b/src/common/StringBuilder.test.ts @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { LimitedStringBuilder, StringBuilder } from './StringBuilder'; + +describe('StringBuilder', () => { + it('should start empty', () => { + const builder = new StringBuilder(); + assert.strictEqual(builder.length, 0); + assert.strictEqual(builder.toString(), ''); + }); + + it('should append a single chunk', () => { + const builder = new StringBuilder(); + builder.append('hello'); + assert.strictEqual(builder.length, 5); + assert.strictEqual(builder.toString(), 'hello'); + }); + + it('should join multiple chunks in order', () => { + const builder = new StringBuilder(); + builder.append('foo'); + builder.append('bar'); + builder.append('baz'); + assert.strictEqual(builder.length, 9); + assert.strictEqual(builder.toString(), 'foobarbaz'); + }); + + it('should handle empty chunks', () => { + const builder = new StringBuilder(); + builder.append(''); + builder.append('a'); + builder.append(''); + assert.strictEqual(builder.length, 1); + assert.strictEqual(builder.toString(), 'a'); + }); + + it('should reset accumulated data', () => { + const builder = new StringBuilder(); + builder.append('hello'); + builder.reset(); + assert.strictEqual(builder.length, 0); + assert.strictEqual(builder.toString(), ''); + }); + + it('should allow appending after reset', () => { + const builder = new StringBuilder(); + builder.append('old'); + builder.reset(); + builder.append('new'); + assert.strictEqual(builder.toString(), 'new'); + }); + + it('should accumulate many small chunks without quadratic concatenation', () => { + const builder = new StringBuilder(); + const chunk = 'x'; + const count = 10000; + for (let i = 0; i < count; i++) { + builder.append(chunk); + } + assert.strictEqual(builder.length, count); + assert.strictEqual(builder.toString(), 'x'.repeat(count)); + }); +}); + +describe('LimitedStringBuilder', () => { + it('should expose the configured limit', () => { + const builder = new LimitedStringBuilder(42); + assert.strictEqual(builder.limit, 42); + }); + + it('should start empty', () => { + const builder = new LimitedStringBuilder(10); + assert.strictEqual(builder.length, 0); + assert.strictEqual(builder.toString(), ''); + }); + + it('should accept data up to the limit', () => { + const builder = new LimitedStringBuilder(10); + assert.strictEqual(builder.append('12345'), false); + assert.strictEqual(builder.append('67890'), false); + assert.strictEqual(builder.length, 10); + assert.strictEqual(builder.toString(), '1234567890'); + }); + + it('should accept a single chunk exactly at the limit', () => { + const builder = new LimitedStringBuilder(5); + assert.strictEqual(builder.append('abcde'), false); + assert.strictEqual(builder.length, 5); + assert.strictEqual(builder.toString(), 'abcde'); + }); + + it('should reject data exceeding the limit and clear the buffer', () => { + const builder = new LimitedStringBuilder(5); + builder.append('abc'); + assert.strictEqual(builder.append('def'), true); + assert.strictEqual(builder.length, 0); + assert.strictEqual(builder.toString(), ''); + }); + + it('should reject a single chunk larger than the limit', () => { + const builder = new LimitedStringBuilder(3); + assert.strictEqual(builder.append('toolong'), true); + assert.strictEqual(builder.length, 0); + assert.strictEqual(builder.toString(), ''); + }); + + it('should allow appending again after reset following a limit breach', () => { + const builder = new LimitedStringBuilder(3); + assert.strictEqual(builder.append('abcd'), true); + builder.reset(); + assert.strictEqual(builder.append('ab'), false); + assert.strictEqual(builder.toString(), 'ab'); + }); + + it('should accumulate many chunks before hitting the limit', () => { + const limit = 100; + const builder = new LimitedStringBuilder(limit); + const chunk = 'A'; + for (let i = 0; i < limit; i++) { + assert.strictEqual(builder.append(chunk), false); + } + assert.strictEqual(builder.toString(), 'A'.repeat(limit)); + assert.strictEqual(builder.append('B'), true); + assert.strictEqual(builder.toString(), ''); + }); + + it('should reject when limit is zero and any data is appended', () => { + const builder = new LimitedStringBuilder(0); + assert.strictEqual(builder.append('a'), true); + assert.strictEqual(builder.length, 0); + }); + + it('should allow zero-length appends at the limit', () => { + const builder = new LimitedStringBuilder(0); + assert.strictEqual(builder.append(''), false); + assert.strictEqual(builder.length, 0); + assert.strictEqual(builder.toString(), ''); + }); +}); diff --git a/src/common/StringBuilder.ts b/src/common/StringBuilder.ts new file mode 100644 index 000000000..d9184ce31 --- /dev/null +++ b/src/common/StringBuilder.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +/** + * Accumulates string data from multiple chunks without O(n²) string concatenation. + */ +export class StringBuilder { + private _chunks: string[] = []; + private _length = 0; + + public get length(): number { + return this._length; + } + + public reset(): void { + this._chunks.length = 0; + this._length = 0; + } + + public append(chunk: string): void { + this._chunks.push(chunk); + this._length += chunk.length; + } + + public toString(): string { + return this._chunks.join(''); + } +} + +/** + * String builder that rejects payloads larger than a fixed limit. + */ +export class LimitedStringBuilder { + private readonly _builder = new StringBuilder(); + + constructor(private readonly _limit: number) { } + + public get length(): number { + return this._builder.length; + } + + public get limit(): number { + return this._limit; + } + + public reset(): void { + this._builder.reset(); + } + + /** + * @returns true if the limit was exceeded (buffer is cleared in that case) + */ + public append(chunk: string): boolean { + this._builder.append(chunk); + if (this._builder.length > this._limit) { + this._builder.reset(); + return true; + } + return false; + } + + public toString(): string { + return this._builder.toString(); + } +} diff --git a/src/common/TaskQueue.ts b/src/common/TaskQueue.ts index 3cad0a140..b1bcf023a 100644 --- a/src/common/TaskQueue.ts +++ b/src/common/TaskQueue.ts @@ -3,12 +3,12 @@ * @license MIT */ -import type { ILogService } from 'common/services/Services'; +import type { ILogService } from './services/Services'; interface ITaskQueue { /** * Adds a task to the queue which will run in a future idle callback. - * To avoid perceivable stalls on the mainthread, tasks with heavy workload + * To avoid perceivable stalls on the main thread, tasks with heavy workload * should split their work into smaller pieces and return `true` to get * called again until the work is done (on falsy return value). */ @@ -74,10 +74,10 @@ abstract class TaskQueue implements ITaskQueue { private _process(deadline: ITaskDeadline): void { this._idleCallback = undefined; - let taskDuration = 0; + let taskDuration: number; let longestTask = 0; let lastDeadlineRemaining = deadline.timeRemaining(); - let deadlineRemaining = 0; + let deadlineRemaining: number; while (this._i < this._tasks.length) { taskDuration = performance.now(); if (!this._tasks[this._i]()) { diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index 5940fa659..bedfa6ba1 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -3,18 +3,17 @@ * @license MIT */ -import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IMouseStateService, ICharsetService, UnicodeCharProperties, UnicodeCharWidth, IUnicodeService, IUnicodeVersionProvider, LogLevelEnum, IDecorationService, IInternalDecoration, IOscLinkService, type IBufferResizeEvent } from 'common/services/Services'; -import { UnicodeService } from 'common/services/UnicodeService'; -import { clone } from 'common/Clone'; -import { DEFAULT_OPTIONS } from 'common/services/OptionsService'; -import { IBufferSet, IBuffer } from 'common/buffer/Types'; -import { BufferSet } from 'common/buffer/BufferSet'; -import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEventType, ICharset, IModes, IAttributeData, IOscLinkData, IDisposable, IBufferLine, IExtendedAttrs } from 'common/Types'; -import { UnicodeV6 } from 'common/input/UnicodeV6'; +import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IMouseStateService, ICharsetService, UnicodeCharProperties, UnicodeCharWidth, IUnicodeService, IUnicodeVersionProvider, LogLevelEnum, IDecorationService, IInternalDecoration, IOscLinkService, type IBufferResizeEvent } from './services/Services'; +import { UnicodeService } from './services/UnicodeService'; +import { DEFAULT_OPTIONS } from './services/OptionsService'; +import { IAttributeData, IBuffer, IBufferLine, IBufferSet, IExtendedAttrs } from './buffer/Types'; +import { BufferSet } from './buffer/BufferSet'; +import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEventType, ICharset, IModes, IOscLinkData, IDisposable } from './Types'; +import { UnicodeV6 } from './input/UnicodeV6'; import { IDecorationOptions, IDecoration } from '@xterm/xterm'; -import { Emitter, type IEvent } from 'common/Event'; -import { CellData } from 'common/buffer/CellData'; -import { DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH } from 'common/buffer/Constants'; +import { Emitter, type IEvent } from './Event'; +import { CellData } from './buffer/CellData'; +import { DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH } from './buffer/Constants'; export function createCellData(attr: number, char: string, width: number): CellData { return CellData.fromCharData([attr, char, width, char.length === 0 ? 0 : char.charCodeAt(0)]); @@ -157,7 +156,7 @@ export class MockLogService implements ILogService { export class MockOptionsService implements IOptionsService { public serviceBrand: any; - public readonly rawOptions: Required = clone(DEFAULT_OPTIONS); + public readonly rawOptions: Required = structuredClone(DEFAULT_OPTIONS); public options: Required = this.rawOptions; public onOptionChange: IEvent = new Emitter().event; constructor(testOptions?: Partial) { diff --git a/src/common/Types.ts b/src/common/Types.ts index 1dea39fb3..b73fc8413 100644 --- a/src/common/Types.ts +++ b/src/common/Types.ts @@ -3,26 +3,32 @@ * @license MIT */ -import { IDeleteEvent, IInsertEvent } from 'common/CircularList'; -import { UnderlineStyle } from 'common/buffer/Constants'; -import { IBufferSet } from 'common/buffer/Types'; -import { IParams } from 'common/parser/Types'; -import { IMouseStateService, ICoreService, IOptionsService, IUnicodeService } from 'common/services/Services'; import { IFunctionIdentifier, ITerminalOptions as IPublicTerminalOptions } from '@xterm/xterm'; -import type { Emitter, IEvent } from 'common/Event'; +import type { IEvent } from './Event'; -export interface ICoreTerminal { - mouseStateService: IMouseStateService; - coreService: ICoreService; - optionsService: IOptionsService; - unicodeService: IUnicodeService; - buffers: IBufferSet; - options: Required; - registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise): IDisposable; - registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise): IDisposable; - registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise): IDisposable; - registerOscHandler(ident: number, callback: (data: string) => boolean | Promise): IDisposable; - registerApcHandler(id: IFunctionIdentifier, callback: (data: string) => boolean | Promise): IDisposable; +/** sequence params serialized to js arrays */ +export type ParamsArray = (number | number[])[]; + +/** Interface of Params storage class. */ +export interface IParams { + /** from ctor */ + maxLength: number; + maxSubParamsLength: number; + + /** param values and its length */ + params: Int32Array; + length: number; + + /** methods */ + clone(): IParams; + toArray(): ParamsArray; + reset(): void; + resetZdm(): void; + addParam(value: number): void; + addSubParam(value: number): void; + hasSubParams(idx: number): boolean; + getSubParams(idx: number): Int32Array | null; + getSubParamsAll(): {[idx: number]: Int32Array}; } export interface IDisposable { @@ -62,28 +68,6 @@ export interface IScrollEvent { position: number; } -export interface ICircularList { - length: number; - maxLength: number; - isFull: boolean; - - onDeleteEmitter: Emitter; - onDelete: IEvent; - onInsertEmitter: Emitter; - onInsert: IEvent; - onTrimEmitter: Emitter; - onTrim: IEvent; - - get(index: number): T | undefined; - set(index: number, value: T): void; - push(value: T): void; - recycle(): T; - pop(): T | undefined; - splice(start: number, deleteCount: number, ...items: T[]): void; - trimStart(count: number): void; - shiftElements(start: number, count: number, offset: number): void; -} - export const enum KeyboardResultType { SEND_KEY, SELECT_ALL, @@ -101,25 +85,12 @@ export interface ICharset { [key: string]: string | undefined; } -export type CharData = [attr: number, char: string, width: number, code: number]; - export interface IColor { readonly css: string; readonly rgba: number; // 32-bit int with rgba in each byte } export type IColorRGB = [red: number, green: number, blue: number]; -export interface IExtendedAttrs { - ext: number; - underlineStyle: UnderlineStyle; - underlineColor: number; - underlineVariantOffset: number; - urlId: number; - payload: Object | undefined; - clone(): IExtendedAttrs; - isEmpty(): boolean; -} - /** * Tracks the current hyperlink. Since these are treated as extended attirbutes, these get passed on * to the linkifier when anything is printed. Doing it this way ensures that even when the cursor @@ -131,136 +102,6 @@ export interface IOscLinkData { uri: string; } -/** - * An object that represents all attributes of a cell. - */ -export interface IAttributeData { - /** - * "fg" is a 32-bit unsigned integer that stores the foreground color of the cell in the 24 least - * significant bits and additional flags in the remaining 8 bits. - */ - fg: number; - /** - * "bg" is a 32-bit unsigned integer that stores the background color of the cell in the 24 least - * significant bits and additional flags in the remaining 8 bits. - */ - bg: number; - /** - * "extended", aka "ext", stores extended attributes beyond those available in fg and bg. This - * data is optional on a cell and encodes less common data. - */ - extended: IExtendedAttrs; - - clone(): IAttributeData; - - // flags - isInverse(): number; - isBold(): number; - isUnderline(): number; - isBlink(): number; - isInvisible(): number; - isItalic(): number; - isDim(): number; - isStrikethrough(): number; - isProtected(): number; - isOverline(): number; - - /** - * The color mode of the foreground color which determines how to decode {@link getFgColor}, - * possible values include {@link Attributes.CM_DEFAULT}, {@link Attributes.CM_P16}, - * {@link Attributes.CM_P256} and {@link Attributes.CM_RGB}. - */ - getFgColorMode(): number; - /** - * The color mode of the background color which determines how to decode {@link getBgColor}, - * possible values include {@link Attributes.CM_DEFAULT}, {@link Attributes.CM_P16}, - * {@link Attributes.CM_P256} and {@link Attributes.CM_RGB}. - */ - getBgColorMode(): number; - isFgRGB(): boolean; - isBgRGB(): boolean; - isFgPalette(): boolean; - isBgPalette(): boolean; - isFgDefault(): boolean; - isBgDefault(): boolean; - isAttributeDefault(): boolean; - - /** - * Gets an integer representation of the foreground color, how to decode the color depends on the - * color mode {@link getFgColorMode}. - */ - getFgColor(): number; - /** - * Gets an integer representation of the background color, how to decode the color depends on the - * color mode {@link getBgColorMode}. - */ - getBgColor(): number; - - // extended attrs - hasExtendedAttrs(): number; - updateExtended(): void; - getUnderlineColor(): number; - getUnderlineColorMode(): number; - isUnderlineColorRGB(): boolean; - isUnderlineColorPalette(): boolean; - isUnderlineColorDefault(): boolean; - getUnderlineStyle(): number; - getUnderlineVariantOffset(): number; -} - -/** Cell data */ -export interface ICellData extends IAttributeData { - content: number; - combinedData: string; - isCombined(): number; - getWidth(): number; - getChars(): string; - getCode(): number; - setFromCharData(value: CharData): void; - getAsCharData(): CharData; -} - -/** - * Interface for a line in the terminal buffer. - */ -export interface IBufferLine { - length: number; - isWrapped: boolean; - get(index: number): CharData; - set(index: number, value: CharData): void; - loadCell(index: number, cell: ICellData): ICellData; - setCell(index: number, cell: ICellData): void; - setCellFromCodepoint(index: number, codePoint: number, width: number, attrs: IAttributeData): void; - addCodepointToCell(index: number, codePoint: number, width: number): void; - insertCells(pos: number, n: number, ch: ICellData): void; - deleteCells(pos: number, n: number, fill: ICellData): void; - replaceCells(start: number, end: number, fill: ICellData, respectProtect?: boolean): void; - resize(cols: number, fill: ICellData): boolean; - cleanupMemory(): number; - fill(fillCellData: ICellData, respectProtect?: boolean): void; - copyFrom(line: IBufferLine): void; - clone(): IBufferLine; - getTrimmedLength(): number; - getNoBgTrimmedLength(): number; - translateToString(trimRight?: boolean, startCol?: number, endCol?: number, outColumns?: number[]): string; - - /* direct access to cell attrs */ - getWidth(index: number): number; - hasWidth(index: number): number; - getFg(index: number): number; - getBg(index: number): number; - hasContent(index: number): number; - getCodePoint(index: number): number; - isCombined(index: number): number; - getString(index: number): string; -} - -export interface IMarker extends IDisposable { - readonly id: number; - readonly isDisposed: boolean; - readonly line: number; - onDispose: IEvent; -} export interface IModes { insertMode: boolean; } @@ -340,7 +181,7 @@ export interface ICoreMouseEvent { x: number; y: number; /** - * Button the action occured. Due to restrictions of the tracking protocols + * Button the action occurred. Due to restrictions of the tracking protocols * it is not possible to report multiple buttons at once. * Wheel is treated as a button. * There are invalid combinations of buttons and actions possible @@ -529,8 +370,8 @@ export interface IInputHandler { /** CSI ' } */ insertColumns(params: IParams): boolean; /** CSI ' ~ */ deleteColumns(params: IParams): boolean; - /** OSC 0 - OSC 2 */ setTitle(data: string): boolean; + /** OSC 0 */ + /** OSC 2 */ setTitle(data: string): boolean; /** OSC 4 */ setOrReportIndexedColor(data: string): boolean; /** OSC 10 */ setOrReportFgColor(data: string): boolean; /** OSC 11 */ setOrReportBgColor(data: string): boolean; @@ -543,24 +384,24 @@ export interface IInputHandler { /** ESC E */ nextLine(): boolean; /** ESC = */ keypadApplicationMode(): boolean; /** ESC > */ keypadNumericMode(): boolean; - /** ESC % G - ESC % @ */ selectDefaultCharset(): boolean; - /** ESC ( C - ESC ) C - ESC * C - ESC + C - ESC - C - ESC . C - ESC / C */ selectCharset(collectAndFlag: string): boolean; + /** ESC % G */ + /** ESC % @ */ selectDefaultCharset(): boolean; + /** ESC ( C */ + /** ESC ) C */ + /** ESC * C */ + /** ESC + C */ + /** ESC - C */ + /** ESC . C */ + /** ESC / C */ selectCharset(collectAndFlag: string): boolean; /** ESC D */ index(): boolean; /** ESC H */ tabSet(): boolean; /** ESC M */ reverseIndex(): boolean; /** ESC c */ fullReset(): boolean; - /** ESC n - ESC o - ESC | - ESC } - ESC ~ */ setgLevel(level: number): boolean; + /** ESC n */ + /** ESC o */ + /** ESC | */ + /** ESC } */ + /** ESC ~ */ setgLevel(level: number): boolean; /** ESC # 8 */ screenAlignmentPattern(): boolean; } diff --git a/src/common/WindowsMode.test.ts b/src/common/WindowsMode.test.ts new file mode 100644 index 000000000..38daa52b7 --- /dev/null +++ b/src/common/WindowsMode.test.ts @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { DEFAULT_ATTR_DATA } from './buffer/BufferLine'; +import { updateWindowsModeWrappedState } from './WindowsMode'; +import { BufferService } from './services/BufferService'; +import { OptionsService } from './services/OptionsService'; +import { MockLogService } from './TestUtils.test'; + +describe('WindowsMode', () => { + describe('updateWindowsModeWrappedState', () => { + it('should mark the next line wrapped when the previous line ends in a non-whitespace character', () => { + const bufferService = new BufferService(new OptionsService({ rows: 5, cols: 10 }), new MockLogService()); + const buffer = bufferService.buffer; + const previousLine = buffer.lines.get(buffer.ybase)!; + for (let i = 0; i < bufferService.cols; i++) { + previousLine!.setCellFromCodepoint(i, 'a'.charCodeAt(0), 1, DEFAULT_ATTR_DATA); + } + buffer.y = 1; + + updateWindowsModeWrappedState(bufferService); + + assert.strictEqual(buffer.lines.get(buffer.ybase + 1)!.isWrapped, true); + }); + + it('should not mark the next line wrapped when the previous line ends in whitespace', () => { + const bufferService = new BufferService(new OptionsService({ rows: 5, cols: 10 }), new MockLogService()); + const buffer = bufferService.buffer; + const previousLine = buffer.lines.get(buffer.ybase)!; + for (let i = 0; i < bufferService.cols - 1; i++) { + previousLine!.setCellFromCodepoint(i, 'a'.charCodeAt(0), 1, DEFAULT_ATTR_DATA); + } + previousLine!.setCellFromCodepoint(bufferService.cols - 1, ' '.charCodeAt(0), 1, DEFAULT_ATTR_DATA); + buffer.y = 1; + + updateWindowsModeWrappedState(bufferService); + + assert.strictEqual(buffer.lines.get(buffer.ybase + 1)!.isWrapped, false); + }); + + it('should not mark the next line wrapped when the previous line ends in a null cell', () => { + const bufferService = new BufferService(new OptionsService({ rows: 5, cols: 10 }), new MockLogService()); + const buffer = bufferService.buffer; + buffer.y = 1; + + updateWindowsModeWrappedState(bufferService); + + assert.strictEqual(buffer.lines.get(buffer.ybase + 1)!.isWrapped, false); + }); + }); +}); diff --git a/src/common/WindowsMode.ts b/src/common/WindowsMode.ts index 7cff094b2..d4862e00e 100644 --- a/src/common/WindowsMode.ts +++ b/src/common/WindowsMode.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CODE } from 'common/buffer/Constants'; -import { IBufferService } from 'common/services/Services'; +import { CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CODE } from './buffer/Constants'; +import { IBufferService } from './services/Services'; export function updateWindowsModeWrappedState(bufferService: IBufferService): void { // Winpty does not support wraparound mode which means that lines will never diff --git a/src/common/buffer/AttributeData.ts b/src/common/buffer/AttributeData.ts index d81922105..b37c15508 100644 --- a/src/common/buffer/AttributeData.ts +++ b/src/common/buffer/AttributeData.ts @@ -3,8 +3,9 @@ * @license MIT */ -import { IAttributeData, IColorRGB, IExtendedAttrs } from 'common/Types'; -import { Attributes, FgFlags, BgFlags, UnderlineStyle, ExtFlags } from 'common/buffer/Constants'; +import { IColorRGB } from '../Types'; +import { IAttributeData, IExtendedAttrs } from './Types'; +import { Attributes, FgFlags, BgFlags, UnderlineStyle, ExtFlags } from './Constants'; export class AttributeData implements IAttributeData { public static toColorRGB(value: number): IColorRGB { diff --git a/src/common/buffer/Buffer.test.ts b/src/common/buffer/Buffer.test.ts index abfea7b06..cbb8cf9ed 100644 --- a/src/common/buffer/Buffer.test.ts +++ b/src/common/buffer/Buffer.test.ts @@ -4,13 +4,13 @@ */ import { assert } from 'chai'; -import { Buffer } from 'common/buffer/Buffer'; -import { CircularList } from 'common/CircularList'; -import { MockOptionsService, MockBufferService, MockLogService, createCellData } from 'common/TestUtils.test'; -import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache'; -import { CellData } from 'common/buffer/CellData'; -import { ExtendedAttrs } from 'common/buffer/AttributeData'; +import { Buffer } from './Buffer'; +import { CircularList } from '../CircularList'; +import { MockOptionsService, MockBufferService, MockLogService, createCellData } from '../TestUtils.test'; +import { BufferLine, DEFAULT_ATTR_DATA } from './BufferLine'; +import { BufferLineStringCache } from './BufferLineStringCache'; +import { CellData } from './CellData'; +import { ExtendedAttrs } from './AttributeData'; const INIT_COLS = 80; const INIT_ROWS = 24; @@ -233,6 +233,27 @@ describe('Buffer', () => { assert.equal(buffer.lines.length, INIT_ROWS + 10); }); }); + + describe('Windows ConPTY', () => { + beforeEach(() => { + optionsService.options.windowsPty = { backend: 'conpty', buildNumber: 19000 }; + }); + + it('should not adjust ybase or ydisp when growing rows', () => { + buffer.fillViewportRows(); + for (let i = 0; i < 10; i++) { + buffer.lines.push(buffer.getBlankLine(DEFAULT_ATTR_DATA)); + } + buffer.y = INIT_ROWS - 1; + buffer.ybase = 10; + buffer.ydisp = 10; + const linesBefore = buffer.lines.length; + buffer.resize(INIT_COLS, INIT_ROWS + 5); + assert.equal(buffer.ybase, 10); + assert.equal(buffer.ydisp, 10); + assert.equal(buffer.lines.length, linesBefore + 5); + }); + }); }); describe('row and column increased', () => { @@ -305,6 +326,71 @@ describe('Buffer', () => { assert.equal(buffer.lines.get(8)!.translateToString(), ' '); assert.equal(buffer.lines.get(9)!.translateToString(), ' '); }); + it('should gate reflow on ConPTY buildNumber 21376', () => { + const prepareWrappedShrink = () => { + buffer.fillViewportRows(); + buffer.resize(5, 10); + const firstLine = buffer.lines.get(0)!; + for (let i = 0; i < 5; i++) { + const code = 'a'.charCodeAt(0) + i; + firstLine.set(i, [0, String.fromCharCode(code), 1, code]); + } + buffer.y = 1; + buffer.resize(1, 10); + }; + + optionsService.options.windowsPty = { backend: 'conpty', buildNumber: 21375 }; + prepareWrappedShrink(); + assert.equal(buffer.lines.get(1)!.translateToString().trim(), ''); + + buffer = new TestBuffer(true, optionsService, bufferService, new MockLogService()); + optionsService.options.windowsPty = { backend: 'conpty', buildNumber: 21376 }; + prepareWrappedShrink(); + assert.equal(buffer.lines.get(1)!.translateToString().trim(), 'b'); + assert.ok(buffer.lines.get(1)!.isWrapped); + }); + it('should unwrap lines on ConPTY builds with reflow support', () => { + optionsService.options.windowsPty = { backend: 'conpty', buildNumber: 21376 }; + buffer.fillViewportRows(); + buffer.resize(5, 10); + const firstLine = buffer.lines.get(0)!; + for (let i = 0; i < 5; i++) { + const code = 'a'.charCodeAt(0) + i; + firstLine.set(i, [0, String.fromCharCode(code), 1, code]); + } + buffer.y = 1; + buffer.resize(1, 10); + buffer.resize(5, 10); + assert.equal(buffer.lines.get(0)!.translateToString(), 'abcde'); + assert.equal(buffer.lines.get(1)!.translateToString(), ' '); + }); + it('should reflow wrapped lines containing the cursor when reflowCursorLine is enabled', () => { + optionsService.options.reflowCursorLine = true; + buffer.fillViewportRows(); + buffer.resize(5, 10); + const firstLine = buffer.lines.get(0)!; + for (let i = 0; i < 5; i++) { + const code = 'a'.charCodeAt(0) + i; + firstLine.set(i, [0, String.fromCharCode(code), 1, code]); + } + buffer.resize(1, 10); + buffer.y = 2; + buffer.resize(5, 10); + assert.equal(buffer.lines.get(0)!.translateToString(), 'abcde'); + }); + it('should not reflow wrapped lines containing the cursor by default', () => { + buffer.fillViewportRows(); + buffer.resize(5, 10); + const firstLine = buffer.lines.get(0)!; + for (let i = 0; i < 5; i++) { + const code = 'a'.charCodeAt(0) + i; + firstLine.set(i, [0, String.fromCharCode(code), 1, code]); + } + buffer.resize(1, 10); + buffer.y = 2; + buffer.resize(5, 10); + assert.notEqual(buffer.lines.get(0)!.translateToString(), 'abcde'); + }); it('should discard parts of wrapped lines that go out of the scrollback', () => { buffer.fillViewportRows(); optionsService.options.scrollback = 1; diff --git a/src/common/buffer/Buffer.ts b/src/common/buffer/Buffer.ts index 34ef02f6a..c7d094a43 100644 --- a/src/common/buffer/Buffer.ts +++ b/src/common/buffer/Buffer.ts @@ -3,20 +3,20 @@ * @license MIT */ -import { CircularList, IInsertEvent } from 'common/CircularList'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IdleTaskQueue } from 'common/TaskQueue'; -import { IAttributeData, IBufferLine, ICellData, ICharset } from 'common/Types'; -import { ExtendedAttrs } from 'common/buffer/AttributeData'; -import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache'; -import { getWrappedLineTrimmedLength, reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths } from 'common/buffer/BufferReflow'; -import { CellData } from 'common/buffer/CellData'; -import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE, WHITESPACE_CELL_WIDTH } from 'common/buffer/Constants'; -import { Marker } from 'common/buffer/Marker'; -import { IBuffer } from 'common/buffer/Types'; -import { DEFAULT_CHARSET } from 'common/data/Charsets'; -import { IBufferService, ILogService, IOptionsService } from 'common/services/Services'; +import { CircularList, IInsertEvent } from '../CircularList'; +import { Disposable, toDisposable } from '../Lifecycle'; +import { IdleTaskQueue } from '../TaskQueue'; +import { ICharset } from '../Types'; +import { IAttributeData, IBuffer, IBufferLine, ICellData } from './Types'; +import { ExtendedAttrs } from './AttributeData'; +import { BufferLine, DEFAULT_ATTR_DATA } from './BufferLine'; +import { BufferLineStringCache } from './BufferLineStringCache'; +import { getWrappedLineTrimmedLength, reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths } from './BufferReflow'; +import { CellData } from './CellData'; +import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE, WHITESPACE_CELL_WIDTH } from './Constants'; +import { Marker } from './Marker'; +import { DEFAULT_CHARSET } from '../data/Charsets'; +import { IBufferService, ILogService, IOptionsService } from '../services/Services'; export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1 @@ -142,7 +142,7 @@ export class Buffer extends Disposable implements IBuffer { } /** - * Clears the buffer to it's initial state, discarding all previous data. + * Clears the buffer to its initial state, discarding all previous data. */ public clear(): void { this._stringCache.clear(); @@ -197,7 +197,7 @@ export class Buffer extends Disposable implements IBuffer { for (let y = this._rows; y < newRows; y++) { if (this.lines.length < newRows + this.ybase) { if (this._optionsService.rawOptions.windowsPty.backend !== undefined || this._optionsService.rawOptions.windowsPty.buildNumber !== undefined) { - // Just add the new missing rows on Windows as conpty reprints the screen with it's + // Just add the new missing rows on Windows as conpty reprints the screen with its // view of the world. Once a line enters scrollback for conpty it remains there this.lines.push(new BufferLine(this._stringCache, newCols, nullCell, false)); } else { diff --git a/src/common/buffer/BufferLine.test.ts b/src/common/buffer/BufferLine.test.ts index 3aec28872..7fc12ad76 100644 --- a/src/common/buffer/BufferLine.test.ts +++ b/src/common/buffer/BufferLine.test.ts @@ -2,14 +2,14 @@ * Copyright (c) 2018 The xterm.js authors. All rights reserved. * @license MIT */ -import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, DEFAULT_ATTR, Content, UnderlineStyle, BgFlags, Attributes, FgFlags } from 'common/buffer/Constants'; -import { BufferLine } from 'common/buffer//BufferLine'; -import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache'; -import { CellData } from 'common/buffer/CellData'; -import { CharData, IBufferLine, ICellData } from '../Types'; +import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, DEFAULT_ATTR, Content, UnderlineStyle, BgFlags, Attributes, FgFlags } from './Constants'; +import { BufferLine } from './BufferLine'; +import { BufferLineStringCache } from './BufferLineStringCache'; +import { CellData } from './CellData'; +import { CharData, IBufferLine, ICellData } from './Types'; import { assert } from 'chai'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { createCellData, NULL_CELL_DATA, extendedAttributes } from 'common/TestUtils.test'; +import { AttributeData } from './AttributeData'; +import { createCellData, NULL_CELL_DATA, extendedAttributes } from '../TestUtils.test'; const TEST_STRING_CACHE = new BufferLineStringCache(); diff --git a/src/common/buffer/BufferLine.ts b/src/common/buffer/BufferLine.ts index be200f112..30b4ed3bb 100644 --- a/src/common/buffer/BufferLine.ts +++ b/src/common/buffer/BufferLine.ts @@ -3,11 +3,12 @@ * @license MIT */ -import { CharData, IAttributeData, IBufferLine, ICellData, IExtendedAttrs } from 'common/Types'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { CellData } from 'common/buffer/CellData'; -import { Attributes, BgFlags, CHAR_DATA_ATTR_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, Content, NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants'; -import { stringFromCodePoint } from 'common/input/TextDecoder'; +import { CharData, IAttributeData, IBufferLine, ICellData, IExtendedAttrs } from './Types'; +import { AttributeData } from './AttributeData'; +import { CellData } from './CellData'; +import { Attributes, BgFlags, CHAR_DATA_ATTR_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, Content, NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, WHITESPACE_CELL_CHAR } from './Constants'; +import { stringFromCodePoint } from '../input/TextDecoder'; +import { StringBuilder } from '../StringBuilder'; // Buffer memory layout: // @@ -41,6 +42,7 @@ export const DEFAULT_ATTR_DATA = Object.freeze(new AttributeData()); // Work variables to avoid garbage collection let $startIndex = 0; const $workCell = new CellData(); +const $translateToStringBuilder = new StringBuilder(); export interface IBufferLineStringCacheEntry { value: string | undefined; @@ -71,7 +73,9 @@ export interface IBufferLineStringCache { */ export class BufferLine implements IBufferLine { protected _data: Uint32Array; + /** Sparse cache; only read when `IS_COMBINED_MASK` is set in `_data`. */ protected _combined: {[index: number]: string} = {}; + /** Sparse cache; only read when `HAS_EXTENDED` is set in `_data`. */ protected _extendedAttrs: {[index: number]: IExtendedAttrs | undefined} = {}; protected _stringCacheEntryRef: WeakRef | undefined; public length: number; @@ -203,9 +207,15 @@ export class BufferLine implements IBufferLine { cell.bg = this._data[$startIndex + Cell.BG]; if (cell.content & Content.IS_COMBINED_MASK) { cell.combinedData = this._combined[index]; + } else { + cell.combinedData = ''; } if (cell.bg & BgFlags.HAS_EXTENDED) { cell.extended = this._extendedAttrs[index]!; + } else { + // Do not mutate cell.extended in place: it may still reference this line's map entry from a + // prior loadCell into a reused CellData (e.g. $workCell during insert/delete). + cell.extended = DEFAULT_ATTR_DATA.extended.clone(); } return cell; } @@ -457,14 +467,7 @@ export class BufferLine implements IBufferLine { this._data.set(line._data); } this.length = line.length; - this._combined = {}; - for (const el in line._combined) { - this._combined[el] = line._combined[el]; - } - this._extendedAttrs = {}; - for (const el in line._extendedAttrs) { - this._extendedAttrs[el] = line._extendedAttrs[el]; - } + this._copySparseMapsFrom(line); this.isWrapped = line.isWrapped; } @@ -473,12 +476,7 @@ export class BufferLine implements IBufferLine { const newLine = new BufferLine(this._stringCache, 0, undefined, false); newLine._data = new Uint32Array(this._data); newLine.length = this.length; - for (const el in this._combined) { - newLine._combined[el] = this._combined[el]; - } - for (const el in this._extendedAttrs) { - newLine._extendedAttrs[el] = this._extendedAttrs[el]; - } + newLine._copySparseMapsFrom(this); newLine.isWrapped = this.isWrapped; return newLine; } @@ -509,27 +507,14 @@ export class BufferLine implements IBufferLine { for (let i = 0; i < Constants.CELL_INDICIES; i++) { this._data[(destCol + cell) * Constants.CELL_INDICIES + i] = srcData[(srcCol + cell) * Constants.CELL_INDICIES + i]; } - if (srcData[(srcCol + cell) * Constants.CELL_INDICIES + Cell.BG] & BgFlags.HAS_EXTENDED) { - this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell]; - } + this._copyCellMapsFrom(src, srcCol + cell, destCol + cell); } } else { for (let cell = 0; cell < length; cell++) { for (let i = 0; i < Constants.CELL_INDICIES; i++) { this._data[(destCol + cell) * Constants.CELL_INDICIES + i] = srcData[(srcCol + cell) * Constants.CELL_INDICIES + i]; } - if (srcData[(srcCol + cell) * Constants.CELL_INDICIES + Cell.BG] & BgFlags.HAS_EXTENDED) { - this._extendedAttrs[destCol + cell] = src._extendedAttrs[srcCol + cell]; - } - } - } - - // Move any combined data over as needed, FIXME: repeat for extended attrs - const srcCombinedKeys = Object.keys(src._combined); - for (let i = 0; i < srcCombinedKeys.length; i++) { - const key = parseInt(srcCombinedKeys[i], 10); - if (key >= srcCol) { - this._combined[key - srcCol + destCol] = src._combined[key]; + this._copyCellMapsFrom(src, srcCol + cell, destCol + cell); } } } @@ -570,12 +555,12 @@ export class BufferLine implements IBufferLine { if (outColumns) { outColumns.length = 0; } - let result = ''; + $translateToStringBuilder.reset(); while (startCol < endCol) { const content = this._data[startCol * Constants.CELL_INDICIES + Cell.CONTENT]; const cp = content & Content.CODEPOINT_MASK; const chars = (content & Content.IS_COMBINED_MASK) ? this._combined[startCol] : (cp) ? stringFromCodePoint(cp) : WHITESPACE_CELL_CHAR; - result += chars; + $translateToStringBuilder.append(chars); if (outColumns) { for (let i = 0; i < chars.length; ++i) { outColumns.push(startCol); @@ -586,6 +571,8 @@ export class BufferLine implements IBufferLine { if (outColumns) { outColumns.push(startCol); } + const result = $translateToStringBuilder.toString(); + $translateToStringBuilder.reset(); if (isCanonicalRequest) { const cacheEntry = this._getStringCacheEntry(true)!; cacheEntry.value = result; @@ -616,4 +603,24 @@ export class BufferLine implements IBufferLine { cacheEntry.isTrimmed = false; } } + + /** Copy sparse map entries for a single cell when `_data` flags require them. */ + private _copyCellMapsFrom(src: BufferLine, srcCol: number, destCol: number): void { + const srcStart = srcCol * Constants.CELL_INDICIES; + if (src._data[srcStart + Cell.CONTENT] & Content.IS_COMBINED_MASK) { + this._combined[destCol] = src._combined[srcCol]; + } + if (src._data[srcStart + Cell.BG] & BgFlags.HAS_EXTENDED) { + this._extendedAttrs[destCol] = src._extendedAttrs[srcCol]; + } + } + + /** Rebuild sparse maps from another line, keyed only by `_data` flags. */ + private _copySparseMapsFrom(line: BufferLine): void { + this._combined = {}; + this._extendedAttrs = {}; + for (let i = 0; i < line.length; i++) { + this._copyCellMapsFrom(line, i, i); + } + } } diff --git a/src/common/buffer/BufferLineStringCache.ts b/src/common/buffer/BufferLineStringCache.ts index b365eef70..54c97423a 100644 --- a/src/common/buffer/BufferLineStringCache.ts +++ b/src/common/buffer/BufferLineStringCache.ts @@ -3,9 +3,9 @@ * @license MIT */ -import type { IBufferLineStringCache, IBufferLineStringCacheEntry } from 'common/buffer/BufferLine'; -import { disposableTimeout } from 'common/Async'; -import { Disposable, MutableDisposable, toDisposable, type IDisposable } from 'common/Lifecycle'; +import type { IBufferLineStringCache, IBufferLineStringCacheEntry } from './BufferLine'; +import { disposableTimeout } from '../Async'; +import { Disposable, MutableDisposable, toDisposable, type IDisposable } from '../Lifecycle'; const enum Constants { CACHE_TTL_MS = 15000 diff --git a/src/common/buffer/BufferRange.test.ts b/src/common/buffer/BufferRange.test.ts index 15d1b8317..056e9c85a 100644 --- a/src/common/buffer/BufferRange.test.ts +++ b/src/common/buffer/BufferRange.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { getRangeLength } from 'common/buffer/BufferRange'; +import { getRangeLength } from './BufferRange'; import { IBufferRange } from '@xterm/xterm'; describe('BufferRange', () => { diff --git a/src/common/buffer/BufferReflow.test.ts b/src/common/buffer/BufferReflow.test.ts index d71186ddd..8bcf5bf9c 100644 --- a/src/common/buffer/BufferReflow.test.ts +++ b/src/common/buffer/BufferReflow.test.ts @@ -3,10 +3,13 @@ * @license MIT */ import { assert } from 'chai'; -import { BufferLine } from 'common/buffer/BufferLine'; -import { BufferLineStringCache } from 'common/buffer/BufferLineStringCache'; -import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from 'common/buffer/Constants'; -import { reflowSmallerGetNewLineLengths } from 'common/buffer/BufferReflow'; +import { CircularList } from '../CircularList'; +import { BufferLine } from './BufferLine'; +import { BufferLineStringCache } from './BufferLineStringCache'; +import { CellData } from './CellData'; +import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from './Constants'; +import { reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths } from './BufferReflow'; +import { IBufferLine } from './Types'; const TEST_STRING_CACHE = new BufferLineStringCache(); @@ -93,4 +96,31 @@ describe('BufferReflow', () => { assert.deepEqual(reflowSmallerGetNewLineLengths([line], 4, 2), [2, 2], 'line: 汉, 语'); }); }); + describe('reflowLargerGetLinesToRemove', () => { + const nullCell = CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]); + + function createWrappedLines(chars: string): CircularList { + const lines = new CircularList(chars.length); + for (let i = 0; i < chars.length; i++) { + const line = new BufferLine(TEST_STRING_CACHE, 1); + line.set(0, [0, chars[i], 1, chars.charCodeAt(i)]); + line.isWrapped = i > 0; + lines.push(line); + } + return lines; + } + + it('should skip reflow when the cursor is in a wrapped block and reflowCursorLine is false', () => { + const lines = createWrappedLines('abcde'); + const skipped = reflowLargerGetLinesToRemove(lines, 1, 5, 2, nullCell, false); + const reflowed = reflowLargerGetLinesToRemove(lines, 1, 5, 2, nullCell, true); + assert.deepEqual(skipped, []); + assert.notDeepEqual(reflowed, []); + }); + + it('should reflow wrapped blocks when the cursor is outside the block', () => { + const lines = createWrappedLines('abcde'); + assert.notDeepEqual(reflowLargerGetLinesToRemove(lines, 1, 5, 10, nullCell, false), []); + }); + }); }); diff --git a/src/common/buffer/BufferReflow.ts b/src/common/buffer/BufferReflow.ts index 44aa0976f..2c0fb74ba 100644 --- a/src/common/buffer/BufferReflow.ts +++ b/src/common/buffer/BufferReflow.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { BufferLine } from 'common/buffer/BufferLine'; -import { CircularList } from 'common/CircularList'; -import { IBufferLine, ICellData } from 'common/Types'; +import { BufferLine } from './BufferLine'; +import { CircularList } from '../CircularList'; +import { IBufferLine, ICellData } from './Types'; export interface INewLayoutResult { layout: number[]; @@ -178,7 +178,10 @@ export function reflowLargerApplyNewLayout(lines: CircularList, new */ export function reflowSmallerGetNewLineLengths(wrappedLines: BufferLine[], oldCols: number, newCols: number): number[] { const newLineLengths: number[] = []; - const cellsNeeded = wrappedLines.map((l, i) => getWrappedLineTrimmedLength(wrappedLines, i, oldCols)).reduce((p, c) => p + c); + let cellsNeeded = 0; + for (let i = 0; i < wrappedLines.length; i++) { + cellsNeeded += getWrappedLineTrimmedLength(wrappedLines, i, oldCols); + } // Use srcCol and srcLine to find the new wrapping point, use that to get the cellsAvailable and // linesNeeded diff --git a/src/common/buffer/BufferSet.test.ts b/src/common/buffer/BufferSet.test.ts index 8809a3cb6..71a1026dc 100644 --- a/src/common/buffer/BufferSet.test.ts +++ b/src/common/buffer/BufferSet.test.ts @@ -4,9 +4,9 @@ */ import { assert } from 'chai'; -import { BufferSet } from 'common/buffer/BufferSet'; -import { Buffer } from 'common/buffer/Buffer'; -import { MockOptionsService, MockBufferService, MockLogService, createCellData } from 'common/TestUtils.test'; +import { BufferSet } from './BufferSet'; +import { Buffer } from './Buffer'; +import { MockOptionsService, MockBufferService, MockLogService, createCellData } from '../TestUtils.test'; describe('BufferSet', () => { let bufferSet: BufferSet; diff --git a/src/common/buffer/BufferSet.ts b/src/common/buffer/BufferSet.ts index 32a4bf3b4..4ea2cee8d 100644 --- a/src/common/buffer/BufferSet.ts +++ b/src/common/buffer/BufferSet.ts @@ -3,12 +3,11 @@ * @license MIT */ -import { Disposable, MutableDisposable } from 'common/Lifecycle'; -import { IAttributeData } from 'common/Types'; -import { Buffer } from 'common/buffer/Buffer'; -import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IBufferService, ILogService, IOptionsService } from 'common/services/Services'; -import { Emitter } from 'common/Event'; +import { Disposable, MutableDisposable } from '../Lifecycle'; +import { Buffer } from './Buffer'; +import { IAttributeData, IBuffer, IBufferSet } from './Types'; +import { IBufferService, ILogService, IOptionsService } from '../services/Services'; +import { Emitter } from '../Event'; /** * The BufferSet represents the set of two buffers used by xterm terminals (normal and alt) and diff --git a/src/common/buffer/CellData.test.ts b/src/common/buffer/CellData.test.ts index 77d1ef9ed..f611f418b 100644 --- a/src/common/buffer/CellData.test.ts +++ b/src/common/buffer/CellData.test.ts @@ -2,8 +2,8 @@ * Copyright (c) 2026 The xterm.js authors. All rights reserved. * @license MIT */ -import { Attributes, BgFlags, FgFlags, UnderlineStyle } from 'common/buffer/Constants'; -import { CellData } from 'common/buffer/CellData'; +import { Attributes, BgFlags, FgFlags, UnderlineStyle } from './Constants'; +import { CellData } from './CellData'; import { assert } from 'chai'; function createStyledCell(char: string, underlineStyle: UnderlineStyle, underlineColor: number): CellData { diff --git a/src/common/buffer/CellData.ts b/src/common/buffer/CellData.ts index 43c4c594b..3c738f77f 100644 --- a/src/common/buffer/CellData.ts +++ b/src/common/buffer/CellData.ts @@ -3,10 +3,10 @@ * @license MIT */ -import { CharData, ICellData, IExtendedAttrs } from 'common/Types'; -import { stringFromCodePoint } from 'common/input/TextDecoder'; -import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_ATTR_INDEX, Content } from 'common/buffer/Constants'; -import { AttributeData, ExtendedAttrs } from 'common/buffer/AttributeData'; +import { CharData, ICellData, IExtendedAttrs } from './Types'; +import { stringFromCodePoint } from '../input/TextDecoder'; +import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_ATTR_INDEX, Content } from './Constants'; +import { AttributeData, ExtendedAttrs } from './AttributeData'; import type { IBufferCell as IBufferCellApi } from '@xterm/xterm'; /** diff --git a/src/common/buffer/Constants.ts b/src/common/buffer/Constants.ts index 5ce075cf7..c02dba50d 100644 --- a/src/common/buffer/Constants.ts +++ b/src/common/buffer/Constants.ts @@ -24,7 +24,7 @@ export const NULL_CELL_CODE = 0; /** * Whitespace cell. * This is meant as a replacement for empty cells when needed - * during rendering lines to preserve correct aligment. + * during rendering lines to preserve correct alignment. */ export const WHITESPACE_CELL_CHAR = ' '; export const WHITESPACE_CELL_WIDTH = 1; @@ -36,18 +36,18 @@ export const WHITESPACE_CELL_CODE = 32; export const enum Content { /** * bit 1..21 codepoint, max allowed in UTF32 is 0x10FFFF (21 bits taken) - * read: `codepoint = content & Content.codepointMask;` - * write: `content |= codepoint & Content.codepointMask;` + * read: `codepoint = content & Content.CODEPOINT_MASK;` + * write: `content |= codepoint & Content.CODEPOINT_MASK;` * shortcut if precondition `codepoint <= 0x10FFFF` is met: * `content |= codepoint;` */ CODEPOINT_MASK = 0x1FFFFF, /** - * bit 22 flag indication whether a cell contains combined content - * read: `isCombined = content & Content.isCombined;` - * set: `content |= Content.isCombined;` - * clear: `content &= ~Content.isCombined;` + * bit 22 flag indicating whether a cell contains combined content + * read: `isCombined = content & Content.IS_COMBINED_MASK;` + * set: `content |= Content.IS_COMBINED_MASK;` + * clear: `content &= ~Content.IS_COMBINED_MASK;` */ IS_COMBINED_MASK = 0x200000, // 1 << 21 @@ -55,19 +55,19 @@ export const enum Content { * bit 1..22 mask to check whether a cell contains any string data * we need to check for codepoint and isCombined bits to see * whether a cell contains anything - * read: `isEmpty = !(content & Content.hasContent)` + * read: `isEmpty = !(content & Content.HAS_CONTENT_MASK)` */ HAS_CONTENT_MASK = 0x3FFFFF, /** * bit 23..24 wcwidth value of cell, takes 2 bits (ranges from 0..2) - * read: `width = (content & Content.widthMask) >> Content.widthShift;` - * `hasWidth = content & Content.widthMask;` + * read: `width = (content & Content.WIDTH_MASK) >> Content.WIDTH_SHIFT;` + * `hasWidth = content & Content.WIDTH_MASK;` * as long as wcwidth is highest value in `content`: - * `width = content >> Content.widthShift;` - * write: `content |= (width << Content.widthShift) & Content.widthMask;` + * `width = content >> Content.WIDTH_SHIFT;` + * write: `content |= (width << Content.WIDTH_SHIFT) & Content.WIDTH_MASK;` * shortcut if precondition `0 <= width <= 3` is met: - * `content |= width << Content.widthShift;` + * `content |= width << Content.WIDTH_SHIFT;` */ WIDTH_MASK = 0xC00000, // 3 << 22 WIDTH_SHIFT = 22 diff --git a/src/common/buffer/Marker.ts b/src/common/buffer/Marker.ts index 59ad049b0..c21575919 100644 --- a/src/common/buffer/Marker.ts +++ b/src/common/buffer/Marker.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { IDisposable, IMarker } from 'common/Types'; -import { Emitter } from 'common/Event'; -import { dispose } from 'common/Lifecycle'; +import { dispose, IDisposable } from '../Lifecycle'; +import { IMarker } from './Types'; +import { Emitter } from '../Event'; export class Marker implements IMarker { private static _nextId = 1; @@ -30,7 +30,7 @@ export class Marker implements IMarker { } this.isDisposed = true; this.line = -1; - // Emit before super.dispose such that dispose listeners get a change to react + // Emit before super.dispose such that dispose listeners get a chance to react this._onDispose.fire(); dispose(this._disposables); this._disposables.length = 0; diff --git a/src/common/buffer/Types.ts b/src/common/buffer/Types.ts index 85dd68eec..18f76d86c 100644 --- a/src/common/buffer/Types.ts +++ b/src/common/buffer/Types.ts @@ -3,12 +3,159 @@ * @license MIT */ -import { IAttributeData, ICircularList, IBufferLine, ICellData, IMarker, ICharset, IDisposable } from 'common/Types'; -import type { IEvent } from 'common/Event'; +import type { IEvent } from '../Event'; +import type { ICircularList } from '../CircularList'; +import type { ICharset } from '../Types'; +import type { IDisposable } from '../Lifecycle'; +import type { UnderlineStyle } from './Constants'; // BufferIndex denotes a position in the buffer: [rowIndex, colIndex] export type BufferIndex = [number, number]; +export type CharData = [attr: number, char: string, width: number, code: number]; + +export interface IExtendedAttrs { + ext: number; + underlineStyle: UnderlineStyle; + underlineColor: number; + underlineVariantOffset: number; + urlId: number; + payload: Object | undefined; + clone(): IExtendedAttrs; + isEmpty(): boolean; +} + +/** + * An object that represents all attributes of a cell. + */ +export interface IAttributeData { + /** + * "fg" is a 32-bit unsigned integer that stores the foreground color of the cell in the 24 least + * significant bits and additional flags in the remaining 8 bits. + */ + fg: number; + /** + * "bg" is a 32-bit unsigned integer that stores the background color of the cell in the 24 least + * significant bits and additional flags in the remaining 8 bits. + */ + bg: number; + /** + * "extended", aka "ext", stores extended attributes beyond those available in fg and bg. This + * data is optional on a cell and encodes less common data. + */ + extended: IExtendedAttrs; + + clone(): IAttributeData; + + // flags + isInverse(): number; + isBold(): number; + isUnderline(): number; + isBlink(): number; + isInvisible(): number; + isItalic(): number; + isDim(): number; + isStrikethrough(): number; + isProtected(): number; + isOverline(): number; + + /** + * The color mode of the foreground color which determines how to decode {@link getFgColor}, + * possible values include {@link Attributes.CM_DEFAULT}, {@link Attributes.CM_P16}, + * {@link Attributes.CM_P256} and {@link Attributes.CM_RGB}. + */ + getFgColorMode(): number; + /** + * The color mode of the background color which determines how to decode {@link getBgColor}, + * possible values include {@link Attributes.CM_DEFAULT}, {@link Attributes.CM_P16}, + * {@link Attributes.CM_P256} and {@link Attributes.CM_RGB}. + */ + getBgColorMode(): number; + isFgRGB(): boolean; + isBgRGB(): boolean; + isFgPalette(): boolean; + isBgPalette(): boolean; + isFgDefault(): boolean; + isBgDefault(): boolean; + isAttributeDefault(): boolean; + + /** + * Gets an integer representation of the foreground color, how to decode the color depends on the + * color mode {@link getFgColorMode}. + */ + getFgColor(): number; + /** + * Gets an integer representation of the background color, how to decode the color depends on the + * color mode {@link getBgColorMode}. + */ + getBgColor(): number; + + // extended attrs + hasExtendedAttrs(): number; + updateExtended(): void; + getUnderlineColor(): number; + getUnderlineColorMode(): number; + isUnderlineColorRGB(): boolean; + isUnderlineColorPalette(): boolean; + isUnderlineColorDefault(): boolean; + getUnderlineStyle(): number; + getUnderlineVariantOffset(): number; +} + +/** Cell data */ +export interface ICellData extends IAttributeData { + content: number; + combinedData: string; + isCombined(): number; + getWidth(): number; + getChars(): string; + getCode(): number; + setFromCharData(value: CharData): void; + getAsCharData(): CharData; +} + +/** + * Interface for a line in the terminal buffer. + */ +export interface IBufferLine { + length: number; + isWrapped: boolean; + get(index: number): CharData; + set(index: number, value: CharData): void; + loadCell(index: number, cell: ICellData): ICellData; + setCell(index: number, cell: ICellData): void; + setCellFromCodepoint(index: number, codePoint: number, width: number, attrs: IAttributeData): void; + addCodepointToCell(index: number, codePoint: number, width: number): void; + insertCells(pos: number, n: number, ch: ICellData): void; + deleteCells(pos: number, n: number, fill: ICellData): void; + replaceCells(start: number, end: number, fill: ICellData, respectProtect?: boolean): void; + resize(cols: number, fill: ICellData): boolean; + cleanupMemory(): number; + fill(fillCellData: ICellData, respectProtect?: boolean): void; + copyFrom(line: IBufferLine): void; + clone(): IBufferLine; + getTrimmedLength(): number; + getNoBgTrimmedLength(): number; + translateToString(trimRight?: boolean, startCol?: number, endCol?: number, outColumns?: number[]): string; + + /* direct access to cell attrs */ + getWidth(index: number): number; + hasWidth(index: number): number; + getFg(index: number): number; + getBg(index: number): number; + hasContent(index: number): number; + getCodePoint(index: number): number; + isCombined(index: number): number; + getString(index: number): string; +} + +export interface IMarker extends IDisposable { + readonly id: number; + readonly isDisposed: boolean; + readonly line: number; + onDispose: IEvent; +} + export interface IBuffer { readonly lines: ICircularList; ydisp: number; diff --git a/src/common/data/Charsets.ts b/src/common/data/Charsets.ts index 9a9a4e552..9680f4c05 100644 --- a/src/common/data/Charsets.ts +++ b/src/common/data/Charsets.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { ICharset } from 'common/Types'; +import { ICharset } from '../Types'; /** * The character sets supported by the terminal. These enable several languages @@ -98,8 +98,7 @@ CHARSETS['4'] = { * ESC (C or ESC (5 * Reference: http://vt100.net/docs/vt220-rm/table2-7.html */ -CHARSETS['C'] = -CHARSETS['5'] = { +CHARSETS['C'] = CHARSETS['5'] = { '[': 'Ä', '\\': 'Ö', ']': 'Å', @@ -185,8 +184,7 @@ CHARSETS['Y'] = { * ESC (E or ESC (6 * Reference: http://vt100.net/docs/vt220-rm/table2-12.html */ -CHARSETS['E'] = -CHARSETS['6'] = { +CHARSETS['E'] = CHARSETS['6'] = { '@': 'Ä', '[': 'Æ', '\\': 'Ø', @@ -220,8 +218,7 @@ CHARSETS['Z'] = { * ESC (H or ESC (7 * Reference: http://vt100.net/docs/vt220-rm/table2-14.html */ -CHARSETS['H'] = -CHARSETS['7'] = { +CHARSETS['H'] = CHARSETS['7'] = { '@': 'É', '[': 'Ä', '\\': 'Ö', diff --git a/src/common/input/Keyboard.test.ts b/src/common/input/Keyboard.test.ts index 47f516f0f..02c2c4380 100644 --- a/src/common/input/Keyboard.test.ts +++ b/src/common/input/Keyboard.test.ts @@ -1,7 +1,7 @@ import { assert } from 'chai'; -import { evaluateKeyboardEvent } from 'common/input/Keyboard'; -import { IKeyboardResult, IKeyboardEvent } from 'common/Types'; +import { evaluateKeyboardEvent } from './Keyboard'; +import { IKeyboardResult, IKeyboardEvent } from '../Types'; /** * A helper function for testing which allows passing in a partial event and defaults will be filled diff --git a/src/common/input/Keyboard.ts b/src/common/input/Keyboard.ts index 545b436c8..2f8de1963 100644 --- a/src/common/input/Keyboard.ts +++ b/src/common/input/Keyboard.ts @@ -4,8 +4,8 @@ * @license MIT */ -import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from 'common/Types'; -import { C0 } from 'common/data/EscapeSequences'; +import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from '../Types'; +import { C0 } from '../data/EscapeSequences'; // reg + shift key mappings for digits and special chars const KEYCODE_KEY_MAPPINGS: { [key: number]: [string, string]} = { @@ -46,7 +46,7 @@ export function evaluateKeyboardEvent( // Whether to cancel event propagation (NOTE: this may not be needed since the event is // canceled at the end of keyDown cancel: false, - // The new key even to emit + // The new key event to emit key: undefined }; const modifiers = (ev.shiftKey ? 1 : 0) | (ev.altKey ? 2 : 0) | (ev.ctrlKey ? 4 : 0) | (ev.metaKey ? 8 : 0); diff --git a/src/common/input/KittyKeyboard.test.ts b/src/common/input/KittyKeyboard.test.ts index 2a832d75f..fe1bc30e2 100644 --- a/src/common/input/KittyKeyboard.test.ts +++ b/src/common/input/KittyKeyboard.test.ts @@ -1,7 +1,7 @@ import { assert } from 'chai'; -import { KittyKeyboard, KittyKeyboardEventType, KittyKeyboardFlags } from 'common/input/KittyKeyboard'; -import { IKeyboardEvent } from 'common/Types'; +import { KittyKeyboard, KittyKeyboardEventType, KittyKeyboardFlags } from './KittyKeyboard'; +import { IKeyboardEvent } from '../Types'; function createEvent(partialEvent: Partial = {}): IKeyboardEvent { return { diff --git a/src/common/input/KittyKeyboard.ts b/src/common/input/KittyKeyboard.ts index ff57b4f89..ec813e5b2 100644 --- a/src/common/input/KittyKeyboard.ts +++ b/src/common/input/KittyKeyboard.ts @@ -6,8 +6,8 @@ * @see https://sw.kovidgoyal.net/kitty/keyboard-protocol/ */ -import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from 'common/Types'; -import { C0 } from 'common/data/EscapeSequences'; +import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from '../Types'; +import { C0 } from '../data/EscapeSequences'; /** * Kitty keyboard protocol enhancement flags (bitfield). diff --git a/src/common/input/TextDecoder.test.ts b/src/common/input/TextDecoder.test.ts index 1959e1591..0276fc8c8 100644 --- a/src/common/input/TextDecoder.test.ts +++ b/src/common/input/TextDecoder.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { StringToUtf32, stringFromCodePoint, Utf8ToUtf32, utf32ToString } from 'common/input/TextDecoder'; +import { StringToUtf32, stringFromCodePoint, Utf8ToUtf32, utf32ToString } from './TextDecoder'; // convert UTF32 codepoints to string @@ -79,7 +79,7 @@ function assertDecodedRange( } const target = new Uint32Array(count); const length = decode(input, target); - assert.equal(length, count); + assert.strictEqual(length, count); let mismatchIndex = -1; let index = 0; for (let i = min; i < max; ++i) { @@ -92,8 +92,8 @@ function assertDecodedRange( } index++; } - assert.equal(mismatchIndex, -1); - assert.equal(outputToString(target, length), input); + assert.strictEqual(mismatchIndex, -1); + assert.strictEqual(outputToString(target, length), input); } const BATCH_SIZE = 8192; @@ -116,9 +116,9 @@ describe('text encodings', () => { const data = new Uint32Array(s.length); for (let i = 0; i < s.length; ++i) { data[i] = s.charCodeAt(i); - assert.equal(stringFromCodePoint(data[i]), s[i]); + assert.strictEqual(stringFromCodePoint(data[i]), s[i]); } - assert.equal(utf32ToString(data), s); + assert.strictEqual(utf32ToString(data), s); }); describe('StringToUtf32 decoder', () => { @@ -159,7 +159,7 @@ describe('text encodings', () => { const decoder = new StringToUtf32(); const target = new Uint32Array(5); const length = decoder.decode(String.fromCharCode(0xFEFF), target); - assert.equal(length, 0); + assert.strictEqual(length, 0); decoder.clear(); }); }); @@ -169,7 +169,7 @@ describe('text encodings', () => { const target = new Uint32Array(500); for (let i = 0; i < TEST_STRINGS.length; ++i) { const length = decoder.decode(TEST_STRINGS[i], target); - assert.equal(toString(target, length), TEST_STRINGS[i]); + assert.strictEqual(toString(target, length), TEST_STRINGS[i]); decoder.clear(); } }); @@ -184,7 +184,7 @@ describe('text encodings', () => { const written = decoder.decode(input[i], target); decoded += toString(target, written); } - assert(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€'); + assert.strictEqual(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€'); }); }); }); @@ -226,7 +226,7 @@ describe('text encodings', () => { const target = new Uint32Array(5); const utf8Data = stringToUtf8Bytes(String.fromCharCode(0xFEFF)); const length = decoder.decode(utf8Data, target); - assert.equal(length, 0); + assert.strictEqual(length, 0); decoder.clear(); }); }); @@ -237,7 +237,7 @@ describe('text encodings', () => { for (let i = 0; i < TEST_STRINGS.length; ++i) { const utf8Data = stringToUtf8Bytes(TEST_STRINGS[i]); const length = decoder.decode(utf8Data, target); - assert.equal(toString(target, length), TEST_STRINGS[i]); + assert.strictEqual(toString(target, length), TEST_STRINGS[i]); decoder.clear(); } }); @@ -252,7 +252,7 @@ describe('text encodings', () => { const written = decoder.decode(utf8Data.slice(i, i + 1), target); decoded += toString(target, written); } - assert(decoded, 'ÄÖÜßöäü'); + assert.strictEqual(decoded, 'ÄÖÜßöäü'); }); it('2/3 byte sequences - advance by 1', () => { @@ -264,7 +264,7 @@ describe('text encodings', () => { const written = decoder.decode(utf8Data.slice(i, i + 1), target); decoded += toString(target, written); } - assert(decoded, 'Āր܀߀ö€ä€ü'); + assert.strictEqual(decoded, 'Āր܀߀ö€ä€ü'); }); it('2/3/4 byte sequences - advance by 1', () => { @@ -276,7 +276,7 @@ describe('text encodings', () => { const written = decoder.decode(utf8Data.slice(i, i + 1), target); decoded += toString(target, written); } - assert(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€'); + assert.strictEqual(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€'); }); it('2/3/4 byte sequences - advance by 2', () => { @@ -288,7 +288,7 @@ describe('text encodings', () => { const written = decoder.decode(utf8Data.slice(i, i + 2), target); decoded += toString(target, written); } - assert(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€'); + assert.strictEqual(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€'); }); it('2/3/4 byte sequences - advance by 3', () => { @@ -300,7 +300,7 @@ describe('text encodings', () => { const written = decoder.decode(utf8Data.slice(i, i + 3), target); decoded += toString(target, written); } - assert(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€'); + assert.strictEqual(decoded, 'Ä€𝄞Ö𝄞€Ü𝄞€'); }); it('BOMs (3 byte sequences) - advance by 2', () => { @@ -312,7 +312,7 @@ describe('text encodings', () => { const written = decoder.decode(utf8Data.slice(i, i + 2), target); decoded += toString(target, written); } - assert.equal(decoded, ''); + assert.strictEqual(decoded, ''); }); it('test break after 3 bytes - issue #2495', () => { @@ -320,11 +320,37 @@ describe('text encodings', () => { const target = new Uint32Array(5); const utf8Data = fromByteString('\xf0\xa0\x9c\x8e'); let written = decoder.decode(utf8Data.slice(0, 3), target); - assert.equal(written, 0); + assert.strictEqual(written, 0); written = decoder.decode(utf8Data.slice(3), target); - assert.equal(written, 1); - assert(toString(target, written), '𠜎'); + assert.strictEqual(written, 1); + assert.strictEqual(toString(target, written), '𠜎'); }); + + describe('0x80 not swallowed in continuation', () => { + it('A—B', () => { + const decoder = new Utf8ToUtf32(); + const target = new Uint32Array(5); + const utf8Data = new TextEncoder().encode('A—BA—BA—BA—BA—B'); + let decoded = ''; + for (let i = 0; i < utf8Data.length; i += 2) { + const written = decoder.decode(utf8Data.slice(i, i + 2), target); + decoded += toString(target, written); + } + assert.strictEqual(decoded, 'A—BA—BA—BA—BA—B'); + }); + it('A𐀀B', () => { + const decoder = new Utf8ToUtf32(); + const target = new Uint32Array(5); + const utf8Data = new TextEncoder().encode('A𐀀BA𐀀BA𐀀BA𐀀BA𐀀B'); + let decoded = ''; + for (let i = 0; i < utf8Data.length; i += 2) { + const written = decoder.decode(utf8Data.slice(i, i + 2), target); + decoded += toString(target, written); + } + assert.strictEqual(decoded, 'A𐀀BA𐀀BA𐀀BA𐀀BA𐀀B'); + }); + }); + }); }); }); diff --git a/src/common/input/TextDecoder.ts b/src/common/input/TextDecoder.ts index 7ec9c7cd2..7e0495630 100644 --- a/src/common/input/TextDecoder.ts +++ b/src/common/input/TextDecoder.ts @@ -148,7 +148,7 @@ export class Utf8ToUtf32 { let byte2: number; let byte3: number; let byte4: number; - let codepoint = 0; + let codepoint; let startPos = 0; // handle leftover bytes @@ -158,9 +158,9 @@ export class Utf8ToUtf32 { cp &= ((((cp & 0xE0) === 0xC0)) ? 0x1F : (((cp & 0xF0) === 0xE0)) ? 0x0F : 0x07); let pos = 0; let tmp: number; - while ((tmp = this.interim[++pos] & 0x3F) && pos < 4) { + while ((tmp = this.interim[++pos]) && pos < 4) { cp <<= 6; - cp |= tmp; + cp |= tmp & 0x3F; } // missing bytes - read ahead from input const type = (((this.interim[0] & 0xE0) === 0xC0)) ? 2 : (((this.interim[0] & 0xF0) === 0xE0)) ? 3 : 4; diff --git a/src/common/input/UnicodeV6.test.ts b/src/common/input/UnicodeV6.test.ts index 98dc97dc2..a009ee5eb 100644 --- a/src/common/input/UnicodeV6.test.ts +++ b/src/common/input/UnicodeV6.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { UnicodeV6 } from 'common/input/UnicodeV6'; +import { UnicodeV6 } from './UnicodeV6'; it('wcwidth should match all values from the old implementation', function(): void { // new implementation diff --git a/src/common/input/UnicodeV6.ts b/src/common/input/UnicodeV6.ts index 83265f705..617b49006 100644 --- a/src/common/input/UnicodeV6.ts +++ b/src/common/input/UnicodeV6.ts @@ -2,8 +2,8 @@ * Copyright (c) 2019 The xterm.js authors. All rights reserved. * @license MIT */ -import { IUnicodeVersionProvider, UnicodeCharProperties, UnicodeCharWidth } from 'common/services/Services'; -import { UnicodeService } from 'common/services/UnicodeService'; +import { IUnicodeVersionProvider, UnicodeCharProperties, UnicodeCharWidth } from '../services/Services'; +import { UnicodeService } from '../services/UnicodeService'; const BMP_COMBINING = [ [0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489], @@ -132,6 +132,7 @@ export class UnicodeV6 implements IUnicodeVersionProvider { public charProperties(codepoint: number, preceding: UnicodeCharProperties): UnicodeCharProperties { let width = this.wcwidth(codepoint); let shouldJoin = width === 0 && preceding !== 0; + // HACK: Ideally this file would not depend on the service which uses it if (shouldJoin) { const oldWidth = UnicodeService.extractWidth(preceding); if (oldWidth === 0) { diff --git a/src/common/input/Win32InputMode.test.ts b/src/common/input/Win32InputMode.test.ts index d0f333591..fdcc7459d 100644 --- a/src/common/input/Win32InputMode.test.ts +++ b/src/common/input/Win32InputMode.test.ts @@ -4,8 +4,8 @@ */ import { assert } from 'chai'; -import { Win32InputMode, Win32ControlKeyState } from 'common/input/Win32InputMode'; -import { IKeyboardEvent, KeyboardResultType } from 'common/Types'; +import { Win32InputMode, Win32ControlKeyState } from './Win32InputMode'; +import { IKeyboardEvent, KeyboardResultType } from '../Types'; type EventOpts = Partial; const ev = (opts: EventOpts): IKeyboardEvent => ({ diff --git a/src/common/input/Win32InputMode.ts b/src/common/input/Win32InputMode.ts index 72907836d..9f73440d5 100644 --- a/src/common/input/Win32InputMode.ts +++ b/src/common/input/Win32InputMode.ts @@ -14,8 +14,8 @@ * Rc: Repeat count (usually 1) */ -import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from 'common/Types'; -import { C0 } from 'common/data/EscapeSequences'; +import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from '../Types'; +import { C0 } from '../data/EscapeSequences'; /** * Win32 control key state flags (from Windows API). diff --git a/src/common/input/WriteBuffer.test.ts b/src/common/input/WriteBuffer.test.ts index f366a6320..8d8c81fc2 100644 --- a/src/common/input/WriteBuffer.test.ts +++ b/src/common/input/WriteBuffer.test.ts @@ -125,5 +125,86 @@ describe('WriteBuffer', () => { assert.deepEqual(stack, []); assert.deepEqual(cbStack, []); }); + it('flushSync fires onWriteParsed', () => { + let parsed = 0; + wb.onWriteParsed(() => parsed++); + wb.write('a'); + wb.write('b'); + assert.equal(parsed, 0); + wb.flushSync(); + assert.equal(parsed, 1); + }); + it('flushSync with no pending writes does not fire onWriteParsed', () => { + let parsed = 0; + wb.onWriteParsed(() => parsed++); + wb.flushSync(); + assert.equal(parsed, 0); + }); + it('dispose cancels scheduled innerWrite', done => { + wb.write('a'); + wb.dispose(); + setTimeout(() => { + assert.deepEqual(stack, []); + done(); + }, 20); + }); + it('dispose does not fire onWriteParsed for pending writes', done => { + let parsed = 0; + wb.onWriteParsed(() => parsed++); + wb.write('a'); + wb.dispose(); + setTimeout(() => { + assert.equal(parsed, 0); + done(); + }, 20); + }); + it('write after dispose is a no-op', done => { + wb.dispose(); + wb.write('a'); + setTimeout(() => { + assert.deepEqual(stack, []); + done(); + }, 20); + }); + it('dispose is idempotent', done => { + wb.write('a'); + wb.dispose(); + wb.dispose(); + setTimeout(() => { + assert.deepEqual(stack, []); + done(); + }, 20); + }); + it('async handler continuation is skipped after dispose', done => { + let resolve!: (value: boolean) => void; + const pending = new Promise(r => { resolve = r; }); + wb = new WriteBuffer(() => pending); + wb.write('a'); + wb.dispose(); + resolve(true); + setTimeout(() => { + assert.deepEqual(stack, []); + done(); + }, 20); + }); + it('handleUserInput still processes first chunk synchronously', () => { + wb.handleUserInput(); + wb.write('a'); + assert.deepEqual(stack, ['a']); + }); + it('flushSync after dispose is a no-op', done => { + wb.write('a'); + wb.dispose(); + wb.flushSync(); + setTimeout(() => { + assert.deepEqual(stack, []); + done(); + }, 20); + }); + it('writeSync after dispose is a no-op', () => { + wb.dispose(); + wb.writeSync('a'); + assert.deepEqual(stack, []); + }); }); }); diff --git a/src/common/input/WriteBuffer.ts b/src/common/input/WriteBuffer.ts index b936c9dbf..0b4619690 100644 --- a/src/common/input/WriteBuffer.ts +++ b/src/common/input/WriteBuffer.ts @@ -4,10 +4,9 @@ * @license MIT */ -import { Disposable } from 'common/Lifecycle'; -import { Emitter } from 'common/Event'; - -declare const setTimeout: (handler: () => void, timeout?: number) => void; +import { TimeoutTimer } from '../Async'; +import { Disposable, toDisposable } from '../Lifecycle'; +import { Emitter } from '../Event'; const enum Constants { /** @@ -43,11 +42,18 @@ export class WriteBuffer extends Disposable { private _syncCalls = 0; private _didUserInput = false; + private readonly _innerWriteTimer = this._register(new TimeoutTimer()); private readonly _onWriteParsed = this._register(new Emitter()); public readonly onWriteParsed = this._onWriteParsed.event; constructor(private _action: (data: string | Uint8Array, promiseResult?: boolean) => void | Promise) { super(); + this._register(toDisposable(() => { + this._writeBuffer.length = 0; + this._callbacks.length = 0; + this._pendingData = 0; + this._bufferOffset = 0; + })); } public handleUserInput(): void { @@ -63,6 +69,9 @@ export class WriteBuffer extends Disposable { * promises to resolve. */ public flushSync(): void { + if (this._store.isDisposed) { + return; + } // exit early if another sync write loop is active if (this._isSyncWriting) { return; @@ -71,7 +80,9 @@ export class WriteBuffer extends Disposable { // Process all pending chunks synchronously let chunk: string | Uint8Array | undefined; + let didProcess = false; while (chunk = this._writeBuffer.shift()) { + didProcess = true; this._action(chunk); const cb = this._callbacks.shift(); if (cb) cb(); @@ -84,12 +95,18 @@ export class WriteBuffer extends Disposable { this._callbacks.length = 0; this._isSyncWriting = false; + if (didProcess) { + this._onWriteParsed.fire(); + } } /** * @deprecated Unreliable, to be removed soon. */ public writeSync(data: string | Uint8Array, maxSubsequentCalls?: number): void { + if (this._store.isDisposed) { + return; + } // stop writeSync recursions with maxSubsequentCalls argument // This is dangerous to use as it will lose the current data chunk // and return immediately. @@ -133,6 +150,9 @@ export class WriteBuffer extends Disposable { } public write(data: string | Uint8Array, callback?: () => void): void { + if (this._store.isDisposed) { + return; + } if (this._pendingData > Constants.DISCARD_WATERMARK) { throw new Error('write data discarded, use flow control to avoid losing data'); } @@ -153,7 +173,7 @@ export class WriteBuffer extends Disposable { return; } - setTimeout(() => this._innerWrite()); + this._scheduleInnerWrite(); } this._pendingData += data.length; @@ -189,7 +209,17 @@ export class WriteBuffer extends Disposable { * * Note, for pure sync code `lastTime` and `promiseResult` have no meaning. */ + private _scheduleInnerWrite(lastTime: number = 0, promiseResult: boolean = true): void { + if (this._store.isDisposed) { + return; + } + this._innerWriteTimer.cancelAndSet(() => this._innerWrite(lastTime, promiseResult), 0); + } + protected _innerWrite(lastTime: number = 0, promiseResult: boolean = true): void { + if (this._store.isDisposed) { + return; + } const startTime = lastTime || performance.now(); while (this._writeBuffer.length > this._bufferOffset) { const data = this._writeBuffer[this._bufferOffset]; @@ -218,9 +248,16 @@ export class WriteBuffer extends Disposable { * responsibility to slice hard work), but we can at least schedule a screen update as we * gain control. */ - const continuation: (r: boolean) => void = (r: boolean) => performance.now() - startTime >= Constants.WRITE_TIMEOUT_MS - ? setTimeout(() => this._innerWrite(0, r)) - : this._innerWrite(startTime, r); + const continuation: (r: boolean) => void = (r: boolean) => { + if (this._store.isDisposed) { + return; + } + if (performance.now() - startTime >= Constants.WRITE_TIMEOUT_MS) { + this._scheduleInnerWrite(0, r); + } else { + this._innerWrite(startTime, r); + } + }; /** * Optimization considerations: @@ -230,7 +267,7 @@ export class WriteBuffer extends Disposable { * this condition here, also the renderer has no way to spot nonsense updates either. * FIXME: A proper fix for this would track the FPS at the renderer entry level separately. * - * If favoring of FPS shows bad throughtput impact, use the following instead. It favors + * If favoring of FPS shows bad throughput impact, use the following instead. It favors * throughput by eval'ing `startTime` upfront pulling at least one more chunk into the * current microtask queue (executed before setTimeout). */ @@ -267,7 +304,7 @@ export class WriteBuffer extends Disposable { this._callbacks = this._callbacks.slice(this._bufferOffset); this._bufferOffset = 0; } - setTimeout(() => this._innerWrite()); + this._scheduleInnerWrite(); } else { this._writeBuffer.length = 0; this._callbacks.length = 0; diff --git a/src/common/input/XParseColor.test.ts b/src/common/input/XParseColor.test.ts index 4a73cdbbf..9e7b03abe 100644 --- a/src/common/input/XParseColor.test.ts +++ b/src/common/input/XParseColor.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { parseColor, toRgbString } from 'common/input/XParseColor'; +import { parseColor, toRgbString } from './XParseColor'; describe('XParseColor', () => { describe('parseColor', () => { diff --git a/src/common/parser/ApcParser.test.ts b/src/common/parser/ApcParser.test.ts index c2200d918..49fd26132 100644 --- a/src/common/parser/ApcParser.test.ts +++ b/src/common/parser/ApcParser.test.ts @@ -3,9 +3,9 @@ * @license MIT */ import { assert } from 'chai'; -import { ApcParser, ApcHandler } from 'common/parser/ApcParser'; -import { StringToUtf32, utf32ToString } from 'common/input/TextDecoder'; -import { IApcHandler, IFunctionIdentifier } from 'common/parser/Types'; +import { ApcParser, ApcHandler } from './ApcParser'; +import { StringToUtf32, utf32ToString } from '../input/TextDecoder'; +import { IApcHandler, IFunctionIdentifier } from './Types'; function toUtf32(s: string): Uint32Array { const utf32 = new Uint32Array(s.length); @@ -21,7 +21,7 @@ function identifier(id: IFunctionIdentifier): number { throw new Error('only one byte as prefix supported'); } res = id.prefix.charCodeAt(0); - if (res && 0x3c > res || res > 0x3f) { + if (res < 0x3c || res > 0x3f) { throw new Error('prefix must be in range 0x3c .. 0x3f'); } } @@ -459,4 +459,29 @@ describe('ApcParser - async tests', () => { }); }); }); + describe('reset', () => { + it('should abort active handlers with end(false) when reset during payload', () => { + const ident = identifier({ intermediates: '+', final: 'p' }); + parser.registerHandler(ident, new TestHandler(reports, 'th')); + parser.start(ident); + let data = toUtf32('partial'); + parser.put(data, 0, data.length); + parser.reset(); + assert.deepEqual(reports, [ + ['th', 'START'], + ['th', 'PUT', 'partial'], + ['th', 'END', false] + ]); + reports.length = 0; + parser.start(ident); + data = toUtf32('complete'); + parser.put(data, 0, data.length); + parser.end(true); + assert.deepEqual(reports, [ + ['th', 'START'], + ['th', 'PUT', 'complete'], + ['th', 'END', true] + ]); + }); + }); }); diff --git a/src/common/parser/ApcParser.ts b/src/common/parser/ApcParser.ts index 8f921f8cb..f0d465efc 100644 --- a/src/common/parser/ApcParser.ts +++ b/src/common/parser/ApcParser.ts @@ -3,10 +3,11 @@ * @license MIT */ -import { IApcHandler, IHandlerCollection, ApcFallbackHandlerType, IApcParser, ISubParserStackState } from 'common/parser/Types'; -import { ParserConstants } from 'common/parser/Constants'; -import { utf32ToString } from 'common/input/TextDecoder'; -import { IDisposable } from 'common/Types'; +import { IApcHandler, IHandlerCollection, ApcFallbackHandlerType, IApcParser, ISubParserStackState } from './Types'; +import { ParserConstants } from './Constants'; +import { utf32ToString } from '../input/TextDecoder'; +import { IDisposable } from '../Types'; +import { LimitedStringBuilder } from '../StringBuilder'; const EMPTY_HANDLERS: IApcHandler[] = []; @@ -153,13 +154,13 @@ export class ApcParser implements IApcParser { export class ApcHandler implements IApcHandler { private static _payloadLimit = ParserConstants.PAYLOAD_LIMIT; - private _data = ''; + private _data = new LimitedStringBuilder(ApcHandler._payloadLimit); private _hitLimit: boolean = false; constructor(private _handler: (data: string) => boolean | Promise) { } public start(): void { - this._data = ''; + this._data.reset(); this._hitLimit = false; } @@ -167,9 +168,7 @@ export class ApcHandler implements IApcHandler { if (this._hitLimit) { return; } - this._data += utf32ToString(data, start, end); - if (this._data.length > ApcHandler._payloadLimit) { - this._data = ''; + if (this._data.append(utf32ToString(data, start, end))) { this._hitLimit = true; } } @@ -179,18 +178,18 @@ export class ApcHandler implements IApcHandler { if (this._hitLimit) { ret = false; } else if (success) { - ret = this._handler(this._data); + ret = this._handler(this._data.toString()); if (ret instanceof Promise) { // need to hold data until `ret` got resolved // dont care for errors, data will be freed anyway on next start return ret.then(res => { - this._data = ''; + this._data.reset(); this._hitLimit = false; return res; }); } } - this._data = ''; + this._data.reset(); this._hitLimit = false; return ret; } diff --git a/src/common/parser/DcsParser.test.ts b/src/common/parser/DcsParser.test.ts index 0296fa88e..6732a18f3 100644 --- a/src/common/parser/DcsParser.test.ts +++ b/src/common/parser/DcsParser.test.ts @@ -3,10 +3,10 @@ * @license MIT */ import { assert } from 'chai'; -import { DcsParser, DcsHandler } from 'common/parser/DcsParser'; -import { IDcsHandler, IParams, IFunctionIdentifier } from 'common/parser/Types'; -import { utf32ToString, StringToUtf32 } from 'common/input/TextDecoder'; -import { Params } from 'common/parser/Params'; +import { DcsParser, DcsHandler } from './DcsParser'; +import { IDcsHandler, IParams, IFunctionIdentifier } from './Types'; +import { utf32ToString, StringToUtf32 } from '../input/TextDecoder'; +import { Params } from './Params'; function toUtf32(s: string): Uint32Array { const utf32 = new Uint32Array(s.length); @@ -22,7 +22,7 @@ function identifier(id: IFunctionIdentifier): number { throw new Error('only one byte as prefix supported'); } res = id.prefix.charCodeAt(0); - if (res && 0x3c > res || res > 0x3f) { + if (res < 0x3c || res > 0x3f) { throw new Error('prefix must be in range 0x3c .. 0x3f'); } } @@ -470,4 +470,30 @@ describe('DcsParser - async tests', () => { }); }); }); + describe('reset', () => { + it('should abort active handlers with unhook(false) when reset during payload', () => { + const ident = identifier({ intermediates: '+', final: 'p' }); + const params = Params.fromArray([1, 2, 3]); + parser.registerHandler(ident, new TestHandler(reports, 'th')); + parser.hook(ident, params); + let data = toUtf32('partial'); + parser.put(data, 0, data.length); + parser.reset(); + assert.deepEqual(reports, [ + ['th', 'HOOK', [1, 2, 3]], + ['th', 'PUT', 'partial'], + ['th', 'UNHOOK', false] + ]); + reports.length = 0; + parser.hook(ident, params); + data = toUtf32('complete'); + parser.put(data, 0, data.length); + parser.unhook(true); + assert.deepEqual(reports, [ + ['th', 'HOOK', [1, 2, 3]], + ['th', 'PUT', 'complete'], + ['th', 'UNHOOK', true] + ]); + }); + }); }); diff --git a/src/common/parser/DcsParser.ts b/src/common/parser/DcsParser.ts index 692200230..1b2d34835 100644 --- a/src/common/parser/DcsParser.ts +++ b/src/common/parser/DcsParser.ts @@ -3,11 +3,12 @@ * @license MIT */ -import { IDisposable } from 'common/Types'; -import { IDcsHandler, IParams, IHandlerCollection, IDcsParser, DcsFallbackHandlerType, ISubParserStackState } from 'common/parser/Types'; -import { utf32ToString } from 'common/input/TextDecoder'; -import { Params } from 'common/parser/Params'; -import { ParserConstants } from 'common/parser/Constants'; +import { IDisposable } from '../Types'; +import { IDcsHandler, IParams, IHandlerCollection, IDcsParser, DcsFallbackHandlerType, ISubParserStackState } from './Types'; +import { utf32ToString } from '../input/TextDecoder'; +import { Params } from './Params'; +import { ParserConstants } from './Constants'; +import { LimitedStringBuilder } from '../StringBuilder'; const EMPTY_HANDLERS: IDcsHandler[] = []; @@ -140,7 +141,7 @@ EMPTY_PARAMS.addParam(0); export class DcsHandler implements IDcsHandler { private static _payloadLimit = ParserConstants.PAYLOAD_LIMIT; - private _data = ''; + private _data = new LimitedStringBuilder(DcsHandler._payloadLimit); private _params: IParams = EMPTY_PARAMS; private _hitLimit: boolean = false; @@ -152,7 +153,7 @@ export class DcsHandler implements IDcsHandler { // perf optimization: // clone only, if we have non empty params, otherwise stick with default this._params = (params.length > 1 || params.params[0]) ? params.clone() : EMPTY_PARAMS; - this._data = ''; + this._data.reset(); this._hitLimit = false; } @@ -160,9 +161,7 @@ export class DcsHandler implements IDcsHandler { if (this._hitLimit) { return; } - this._data += utf32ToString(data, start, end); - if (this._data.length > DcsHandler._payloadLimit) { - this._data = ''; + if (this._data.append(utf32ToString(data, start, end))) { this._hitLimit = true; } } @@ -172,20 +171,20 @@ export class DcsHandler implements IDcsHandler { if (this._hitLimit) { ret = false; } else if (success) { - ret = this._handler(this._data, this._params); + ret = this._handler(this._data.toString(), this._params); if (ret instanceof Promise) { // need to hold data and params until `ret` got resolved // dont care for errors, data will be freed anyway on next start return ret.then(res => { this._params = EMPTY_PARAMS; - this._data = ''; + this._data.reset(); this._hitLimit = false; return res; }); } } this._params = EMPTY_PARAMS; - this._data = ''; + this._data.reset(); this._hitLimit = false; return ret; } diff --git a/src/common/parser/EscapeSequenceParser.test.ts b/src/common/parser/EscapeSequenceParser.test.ts index 2d5a04df7..5f12137df 100644 --- a/src/common/parser/EscapeSequenceParser.test.ts +++ b/src/common/parser/EscapeSequenceParser.test.ts @@ -3,16 +3,16 @@ * @license MIT */ -import { IParsingState, IParams, ParamsArray, IOscParser, IOscHandler, OscFallbackHandlerType, IFunctionIdentifier, IParserStackState, ParserStackType } from 'common/parser/Types'; -import { EscapeSequenceParser, TransitionTable, VT500_TRANSITION_TABLE } from 'common/parser/EscapeSequenceParser'; +import { IParsingState, IParams, ParamsArray, IOscParser, IOscHandler, OscFallbackHandlerType, IFunctionIdentifier, IParserStackState, ParserStackType } from './Types'; +import { EscapeSequenceParser, TransitionTable, VT500_TRANSITION_TABLE } from './EscapeSequenceParser'; import { assert } from 'chai'; -import { StringToUtf32, stringFromCodePoint, utf32ToString } from 'common/input/TextDecoder'; -import { ParserState } from 'common/parser/Constants'; -import { Params } from 'common/parser/Params'; -import { OscHandler } from 'common/parser/OscParser'; -import { IDisposable } from 'common/Types'; -import { DcsHandler } from 'common/parser/DcsParser'; -import { ApcHandler } from 'common/parser/ApcParser'; +import { StringToUtf32, stringFromCodePoint, utf32ToString } from '../input/TextDecoder'; +import { ParserState } from './Constants'; +import { Params } from './Params'; +import { OscHandler } from './OscParser'; +import { IDisposable } from '../Types'; +import { DcsHandler } from './DcsParser'; +import { ApcHandler } from './ApcParser'; function r(a: number, b: number): string[] { @@ -243,7 +243,7 @@ describe('EscapeSequenceParser', () => { p = new TestEscapeSequenceParser(tansitions); assert.deepEqual(p.transitions, tansitions); }); - it('inital states', () => { + it('initial states', () => { assert.equal(parser.initialState, ParserState.GROUND); assert.equal(parser.currentState, ParserState.GROUND); assert.equal(parser.osc, ''); @@ -2177,6 +2177,38 @@ describe('EscapeSequenceParser - async', () => { parser.reset(); await parseP(parser, INPUT); // does not throw anymore }); + it('reset during async pause continues at next codepoint in chunk', async () => { + const localParser = new TestEscapeSequenceParser(); + const localStack: any[] = []; + localParser.setPrintHandler((data, start, end) => { + let result = ''; + for (let i = start; i < end; ++i) { + result += stringFromCodePoint(data[i]); + } + localStack.push(['PRINT', result]); + }); + localParser.registerCsiHandler({ final: 'm' }, async params => { + localStack.push(['SGR', params.toArray()]); + return new Promise(resolve => setTimeout(() => resolve(true), 0)); + }); + const data = '\x1b[1mXY'; + const container = new Uint32Array(data.length); + const decoder = new StringToUtf32(); + const len = decoder.decode(data, container); + + assert.ok(localParser.parse(container, len) instanceof Promise); + localParser.reset(); + assert.equal(localParser.parseStack.state, ParserStackType.RESET); + + let prev: boolean | undefined = true; + let result: void | Promise | undefined; + while (result = localParser.parse(container, len, prev)) { + prev = await result; + } + + assert.deepEqual(localStack, [['SGR', [1]], ['PRINT', 'XY']]); + assert.equal(localParser.parseStack.state, ParserStackType.NONE); + }); it('correct result on awaited parse call', async () => { await parseP(parser, INPUT); assert.deepEqual(callstack, RESULT); diff --git a/src/common/parser/EscapeSequenceParser.ts b/src/common/parser/EscapeSequenceParser.ts index d944112db..009ed6ccb 100644 --- a/src/common/parser/EscapeSequenceParser.ts +++ b/src/common/parser/EscapeSequenceParser.ts @@ -3,14 +3,14 @@ * @license MIT */ -import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandlerType, OscFallbackHandlerType, IOscParser, EscHandlerType, IDcsParser, DcsFallbackHandlerType, IFunctionIdentifier, ExecuteFallbackHandlerType, CsiFallbackHandlerType, EscFallbackHandlerType, PrintHandlerType, PrintFallbackHandlerType, ExecuteHandlerType, IParserStackState, ParserStackType, ResumableHandlersType, IApcHandler, IApcParser, ApcFallbackHandlerType } from 'common/parser/Types'; -import { ParserState, ParserAction } from 'common/parser/Constants'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IDisposable } from 'common/Types'; -import { Params } from 'common/parser/Params'; -import { OscParser } from 'common/parser/OscParser'; -import { DcsParser } from 'common/parser/DcsParser'; -import { ApcParser } from 'common/parser/ApcParser'; +import { IParsingState, IDcsHandler, IEscapeSequenceParser, IParams, IOscHandler, IHandlerCollection, CsiHandlerType, OscFallbackHandlerType, IOscParser, EscHandlerType, IDcsParser, DcsFallbackHandlerType, IFunctionIdentifier, ExecuteFallbackHandlerType, CsiFallbackHandlerType, EscFallbackHandlerType, PrintHandlerType, PrintFallbackHandlerType, ExecuteHandlerType, IParserStackState, ParserStackType, ResumableHandlersType, IApcHandler, IApcParser, ApcFallbackHandlerType } from './Types'; +import { ParserState, ParserAction } from './Constants'; +import { Disposable, toDisposable } from '../Lifecycle'; +import { IDisposable } from '../Types'; +import { Params } from './Params'; +import { OscParser } from './OscParser'; +import { DcsParser } from './DcsParser'; +import { ApcParser } from './ApcParser'; /** * VT commands done by the parser @@ -18,7 +18,7 @@ import { ApcParser } from 'common/parser/ApcParser'; // @vt: #Y ESC CSI "Control Sequence Introducer" "ESC [" "Start of a CSI sequence." // @vt: #Y ESC OSC "Operating System Command" "ESC ]" "Start of an OSC sequence." // @vt: #Y ESC DCS "Device Control String" "ESC P" "Start of a DCS sequence." -// @vt: #Y ESC ST "String Terminator" "ESC \" "Terminator used for string type sequences." +// @vt: #Y ESC ST "String Terminator" "ESC \\" "Terminator used for string type sequences." // @vt: #Y ESC PM "Privacy Message" "ESC ^" "Start of a privacy message." // @vt: #Y ESC APC "Application Program Command" "ESC _" "Start of an APC sequence." // @vt: #Y C1 CSI "Control Sequence Introducer" "\x9B" "Start of a CSI sequence." @@ -243,7 +243,7 @@ export const VT500_TRANSITION_TABLE = (function (): TransitionTable { * * This parser is currently hardcoded to operate in ZDM (Zero Default Mode) * as suggested by the original parser, thus empty parameters are set to 0. - * This this is not in line with the latest ECMA-48 specification + * This is not in line with the latest ECMA-48 specification * (ZDM was part of the early specs and got completely removed later on). * * Other than the original parser from vt100.net this parser supports @@ -342,7 +342,7 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP throw new Error('only one byte as prefix supported'); } res = id.prefix.charCodeAt(0); - if (res && 0x3c > res || res > 0x3f) { + if (res < 0x3c || res > 0x3f) { throw new Error('prefix must be in range 0x3c .. 0x3f'); } } @@ -572,8 +572,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP * ``` */ public parse(data: Uint32Array, length: number, promiseResult?: boolean): void | Promise { - let code = 0; - let transition = 0; + let code: number; + let transition: number; let start = 0; let handlerResult: void | boolean | Promise; diff --git a/src/common/parser/OscParser.test.ts b/src/common/parser/OscParser.test.ts index b6b96cbad..9a58f617c 100644 --- a/src/common/parser/OscParser.test.ts +++ b/src/common/parser/OscParser.test.ts @@ -3,9 +3,9 @@ * @license MIT */ import { assert } from 'chai'; -import { OscParser, OscHandler } from 'common/parser/OscParser'; -import { StringToUtf32, utf32ToString } from 'common/input/TextDecoder'; -import { IOscHandler } from 'common/parser/Types'; +import { OscParser, OscHandler } from './OscParser'; +import { StringToUtf32, utf32ToString } from '../input/TextDecoder'; +import { IOscHandler } from './Types'; function toUtf32(s: string): Uint32Array { const utf32 = new Uint32Array(s.length); @@ -464,4 +464,28 @@ describe('OscParser - async tests', () => { }); }); }); + describe('reset', () => { + it('should abort active handlers with end(false) when reset during payload', () => { + parser.registerHandler(1234, new TestHandler(1234, reports, 'th')); + parser.start(); + let data = toUtf32('1234;partial'); + parser.put(data, 0, data.length); + parser.reset(); + assert.deepEqual(reports, [ + ['th', 1234, 'START'], + ['th', 1234, 'PUT', 'partial'], + ['th', 1234, 'END', false] + ]); + reports.length = 0; + parser.start(); + data = toUtf32('1234;complete'); + parser.put(data, 0, data.length); + parser.end(true); + assert.deepEqual(reports, [ + ['th', 1234, 'START'], + ['th', 1234, 'PUT', 'complete'], + ['th', 1234, 'END', true] + ]); + }); + }); }); diff --git a/src/common/parser/OscParser.ts b/src/common/parser/OscParser.ts index 1f0c8cb23..0d2a06534 100644 --- a/src/common/parser/OscParser.ts +++ b/src/common/parser/OscParser.ts @@ -3,10 +3,11 @@ * @license MIT */ -import { IOscHandler, IHandlerCollection, OscFallbackHandlerType, IOscParser, ISubParserStackState } from 'common/parser/Types'; -import { OscState, ParserConstants } from 'common/parser/Constants'; -import { utf32ToString } from 'common/input/TextDecoder'; -import { IDisposable } from 'common/Types'; +import { IOscHandler, IHandlerCollection, OscFallbackHandlerType, IOscParser, ISubParserStackState } from './Types'; +import { OscState, ParserConstants } from './Constants'; +import { utf32ToString } from '../input/TextDecoder'; +import { IDisposable } from '../Types'; +import { LimitedStringBuilder } from '../StringBuilder'; const EMPTY_HANDLERS: IOscHandler[] = []; @@ -194,13 +195,13 @@ export class OscParser implements IOscParser { export class OscHandler implements IOscHandler { private static _payloadLimit = ParserConstants.PAYLOAD_LIMIT; - private _data = ''; + private _data = new LimitedStringBuilder(OscHandler._payloadLimit); private _hitLimit: boolean = false; constructor(private _handler: (data: string) => boolean | Promise) { } public start(): void { - this._data = ''; + this._data.reset(); this._hitLimit = false; } @@ -208,9 +209,7 @@ export class OscHandler implements IOscHandler { if (this._hitLimit) { return; } - this._data += utf32ToString(data, start, end); - if (this._data.length > OscHandler._payloadLimit) { - this._data = ''; + if (this._data.append(utf32ToString(data, start, end))) { this._hitLimit = true; } } @@ -220,18 +219,18 @@ export class OscHandler implements IOscHandler { if (this._hitLimit) { ret = false; } else if (success) { - ret = this._handler(this._data); + ret = this._handler(this._data.toString()); if (ret instanceof Promise) { // need to hold data until `ret` got resolved // dont care for errors, data will be freed anyway on next start return ret.then(res => { - this._data = ''; + this._data.reset(); this._hitLimit = false; return res; }); } } - this._data = ''; + this._data.reset(); this._hitLimit = false; return ret; } diff --git a/src/common/parser/Params.test.ts b/src/common/parser/Params.test.ts index 2418fa452..a30b1376c 100644 --- a/src/common/parser/Params.test.ts +++ b/src/common/parser/Params.test.ts @@ -3,8 +3,8 @@ * @license MIT */ import { assert } from 'chai'; -import { Params } from 'common/parser/Params'; -import { ParamsArray } from 'common/parser/Types'; +import { Params } from './Params'; +import { ParamsArray } from './Types'; class TestParams extends Params { public get subParams(): Int32Array { @@ -199,13 +199,13 @@ describe('Params', () => { it('reject params lesser -1', () => { const params = new Params(); params.addParam(-1); - assert.throws(() => params.addParam(-2), 'values lesser than -1 are not allowed'); + assert.throws(() => params.addParam(-2), 'values less than -1 are not allowed'); }); it('reject subparams lesser -1', () => { const params = new Params(); params.addParam(-1); params.addSubParam(-1); - assert.throws(() => params.addSubParam(-2), 'values lesser than -1 are not allowed'); + assert.throws(() => params.addSubParam(-2), 'values less than -1 are not allowed'); assert.deepEqual(params.toArray(), [-1, [-1]]); }); it('clamp parsed params', () => { diff --git a/src/common/parser/Params.ts b/src/common/parser/Params.ts index 8a77c78a4..76c6bee5a 100644 --- a/src/common/parser/Params.ts +++ b/src/common/parser/Params.ts @@ -2,7 +2,7 @@ * Copyright (c) 2019 The xterm.js authors. All rights reserved. * @license MIT */ -import { IParams, ParamsArray } from 'common/parser/Types'; +import { IParams, ParamsArray } from './Types'; const enum Constants { /** @@ -162,7 +162,7 @@ export class Params implements IParams { return; } if (value < -1) { - throw new Error('values lesser than -1 are not allowed'); + throw new Error('values less than -1 are not allowed'); } this._subParamsIdx[this.length] = this._subParamsLength << 8 | this._subParamsLength; this.params[this.length++] = value > Constants.MAX_VALUE ? Constants.MAX_VALUE : value; @@ -172,7 +172,7 @@ export class Params implements IParams { * Add a sub parameter value. * The sub parameter is automatically associated with the last parameter value. * Thus it is not possible to add a subparameter without any parameter added yet. - * `Params` only stores up to `subParamsLength` sub parameters, any later + * `Params` only stores up to `maxSubParamsLength` sub parameters, any later * sub parameter will be ignored. */ public addSubParam(value: number): void { @@ -185,7 +185,7 @@ export class Params implements IParams { return; } if (value < -1) { - throw new Error('values lesser than -1 are not allowed'); + throw new Error('values less than -1 are not allowed'); } this._subParams[this._subParamsLength++] = value > Constants.MAX_VALUE ? Constants.MAX_VALUE : value; this._subParamsIdx[this.length - 1]++; diff --git a/src/common/parser/Types.ts b/src/common/parser/Types.ts index c04788f7e..f7c8ae2d4 100644 --- a/src/common/parser/Types.ts +++ b/src/common/parser/Types.ts @@ -3,12 +3,10 @@ * @license MIT */ -import { IDisposable } from 'common/Types'; -import { ParserState } from 'common/parser/Constants'; +import { IDisposable, IParams, ParamsArray } from '../Types'; +import { ParserState } from './Constants'; - -/** sequence params serialized to js arrays */ -export type ParamsArray = (number | number[])[]; +export type { IParams, ParamsArray }; /** Params constructor type. */ export interface IParamsConstructor { @@ -18,28 +16,6 @@ export interface IParamsConstructor { fromArray(values: ParamsArray): IParams; } -/** Interface of Params storage class. */ -export interface IParams { - /** from ctor */ - maxLength: number; - maxSubParamsLength: number; - - /** param values and its length */ - params: Int32Array; - length: number; - - /** methods */ - clone(): IParams; - toArray(): ParamsArray; - reset(): void; - resetZdm(): void; - addParam(value: number): void; - addSubParam(value: number): void; - hasSubParams(idx: number): boolean; - getSubParams(idx: number): Int32Array | null; - getSubParamsAll(): {[idx: number]: Int32Array}; -} - /** * Internal state of EscapeSequenceParser. * Used as argument of the error handler to allow @@ -258,8 +234,8 @@ export interface IApcParser extends ISubParser this._onBufferChange.fire(this.active)); + this._register(this._core.buffers.onBufferActivate(() => this._onBufferChange.fire(this.active))); } public get active(): IBufferApi { if (this._core.buffers.active === this._core.buffers.normal) { return this.normal; } diff --git a/src/common/public/ParserApi.ts b/src/common/public/ParserApi.ts index 4c482d7ca..0b886c058 100644 --- a/src/common/public/ParserApi.ts +++ b/src/common/public/ParserApi.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { IParams } from 'common/parser/Types'; +import { IParams } from '../parser/Types'; import { IDisposable, IFunctionIdentifier, IParser } from '@xterm/xterm'; -import { ICoreTerminal } from 'common/Types'; +import { ICoreTerminal } from '../CoreTerminal'; export class ParserApi implements IParser { constructor(private _core: ICoreTerminal) { } diff --git a/src/common/public/UnicodeApi.ts b/src/common/public/UnicodeApi.ts index ec9bd1f77..9527dbd6d 100644 --- a/src/common/public/UnicodeApi.ts +++ b/src/common/public/UnicodeApi.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { ICoreTerminal } from 'common/Types'; +import { ICoreTerminal } from '../CoreTerminal'; import { IUnicodeHandling, IUnicodeVersionProvider } from '@xterm/xterm'; export class UnicodeApi implements IUnicodeHandling { diff --git a/src/common/services/BufferService.test.ts b/src/common/services/BufferService.test.ts new file mode 100644 index 000000000..90716cdb4 --- /dev/null +++ b/src/common/services/BufferService.test.ts @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { AttributeData } from '../buffer/AttributeData'; +import { BufferService } from './BufferService'; +import { OptionsService } from './OptionsService'; +import { MockLogService } from '../TestUtils.test'; + +describe('BufferService', () => { + describe('scroll', () => { + const eraseAttr = new AttributeData(); + + it('should decrement ydisp when the buffer is full and the user has scrolled up', () => { + const optionsService = new OptionsService({ rows: 3, cols: 10, scrollback: 2 }); + const bufferService = new BufferService(optionsService, new MockLogService()); + const buffer = bufferService.buffer; + + while (!buffer.lines.isFull) { + bufferService.scroll(eraseAttr); + } + assert.strictEqual(buffer.lines.length, 5); + + bufferService.isUserScrolling = true; + buffer.ydisp = 2; + const ybaseBefore = buffer.ybase; + + bufferService.scroll(eraseAttr); + + assert.strictEqual(buffer.ybase, ybaseBefore); + assert.strictEqual(buffer.ydisp, 1); + }); + + it('should not advance ydisp with ybase while the user has scrolled up and the buffer is not full', () => { + const optionsService = new OptionsService({ rows: 3, cols: 10, scrollback: 2 }); + const bufferService = new BufferService(optionsService, new MockLogService()); + const buffer = bufferService.buffer; + + bufferService.isUserScrolling = true; + buffer.ydisp = 0; + const ybaseBefore = buffer.ybase; + + bufferService.scroll(eraseAttr); + + assert.strictEqual(buffer.ybase, ybaseBefore + 1); + assert.strictEqual(buffer.ydisp, 0); + }); + + it('should follow ybase with ydisp when the user is not scrolling', () => { + const optionsService = new OptionsService({ rows: 3, cols: 10, scrollback: 2 }); + const bufferService = new BufferService(optionsService, new MockLogService()); + const buffer = bufferService.buffer; + + while (!buffer.lines.isFull) { + bufferService.scroll(eraseAttr); + } + + bufferService.isUserScrolling = false; + bufferService.scroll(eraseAttr); + + assert.strictEqual(buffer.ydisp, buffer.ybase); + }); + + it('should scroll within DECSTBM margins without affecting lines outside the region', () => { + const optionsService = new OptionsService({ rows: 5, cols: 10, scrollback: 10 }); + const bufferService = new BufferService(optionsService, new MockLogService()); + const buffer = bufferService.buffer; + + const markRow = (row: number, ch: string) => { + buffer.lines.get(buffer.ybase + row)!.setCellFromCodepoint(0, ch.charCodeAt(0), 1, eraseAttr); + }; + markRow(0, 'A'); + markRow(1, 'B'); + markRow(2, 'C'); + markRow(3, 'D'); + markRow(4, 'E'); + buffer.scrollTop = 1; + buffer.scrollBottom = 3; + + bufferService.scroll(eraseAttr); + + assert.strictEqual(buffer.lines.get(buffer.ybase + 0)!.translateToString().trim(), 'A'); + assert.strictEqual(buffer.lines.get(buffer.ybase + 1)!.translateToString().trim(), 'C'); + assert.strictEqual(buffer.lines.get(buffer.ybase + 2)!.translateToString().trim(), 'D'); + assert.strictEqual(buffer.lines.get(buffer.ybase + 3)!.translateToString(true).trim(), ''); + assert.strictEqual(buffer.lines.get(buffer.ybase + 4)!.translateToString().trim(), 'E'); + }); + }); + + describe('scrollLines', () => { + it('should move ydisp and set isUserScrolling when scrolling up', () => { + const optionsService = new OptionsService({ rows: 10, cols: 80, scrollback: 10 }); + const bufferService = new BufferService(optionsService, new MockLogService()); + const buffer = bufferService.buffer; + buffer.ybase = 5; + buffer.ydisp = 5; + + let scrollEvent: number | undefined; + bufferService.onScroll(e => { scrollEvent = e; }); + + bufferService.scrollLines(-2); + + assert.strictEqual(buffer.ydisp, 3); + assert.strictEqual(bufferService.isUserScrolling, true); + assert.strictEqual(scrollEvent, 3); + }); + + it('should not scroll above the top of the buffer', () => { + const optionsService = new OptionsService({ rows: 10, cols: 80, scrollback: 10 }); + const bufferService = new BufferService(optionsService, new MockLogService()); + const buffer = bufferService.buffer; + buffer.ybase = 5; + buffer.ydisp = 0; + + bufferService.scrollLines(-1); + + assert.strictEqual(buffer.ydisp, 0); + assert.strictEqual(bufferService.isUserScrolling, false); + }); + + it('should clear isUserScrolling when scrolling to the bottom', () => { + const optionsService = new OptionsService({ rows: 10, cols: 80, scrollback: 10 }); + const bufferService = new BufferService(optionsService, new MockLogService()); + const buffer = bufferService.buffer; + buffer.ybase = 5; + buffer.ydisp = 2; + bufferService.isUserScrolling = true; + + bufferService.scrollLines(10); + + assert.strictEqual(buffer.ydisp, 5); + assert.strictEqual(bufferService.isUserScrolling, false); + }); + }); +}); diff --git a/src/common/services/BufferService.ts b/src/common/services/BufferService.ts index 06ac6b10a..21b0a163a 100644 --- a/src/common/services/BufferService.ts +++ b/src/common/services/BufferService.ts @@ -3,12 +3,11 @@ * @license MIT */ -import { Disposable } from 'common/Lifecycle'; -import { IAttributeData, IBufferLine } from 'common/Types'; -import { BufferSet } from 'common/buffer/BufferSet'; -import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IBufferService, ILogService, IOptionsService, type IBufferResizeEvent } from 'common/services/Services'; -import { Emitter } from 'common/Event'; +import { Disposable } from '../Lifecycle'; +import { IAttributeData, IBuffer, IBufferLine, IBufferSet } from '../buffer/Types'; +import { BufferSet } from '../buffer/BufferSet'; +import { IBufferService, ILogService, IOptionsService, type IBufferResizeEvent } from './Services'; +import { Emitter } from '../Event'; export const enum BufferServiceConstants { MINIMUM_COLS = 2, // Less than 2 can mess with wide chars diff --git a/src/common/services/CharsetService.test.ts b/src/common/services/CharsetService.test.ts new file mode 100644 index 000000000..a4c3646b7 --- /dev/null +++ b/src/common/services/CharsetService.test.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { CHARSETS } from '../data/Charsets'; +import { CharsetService } from './CharsetService'; + +describe('CharsetService', () => { + let service: CharsetService; + + beforeEach(() => { + service = new CharsetService(); + }); + + it('should not update active charset when designating an inactive glevel', () => { + service.setgCharset(1, CHARSETS['0']); + assert.strictEqual(service.glevel, 0); + assert.ok(service.charset === undefined); + }); + + it('should expose the designated charset after setgLevel', () => { + service.setgCharset(1, CHARSETS['0']); + service.setgLevel(1); + assert.strictEqual(service.charset, CHARSETS['0']); + }); + + it('should update active charset when designating the current glevel', () => { + service.setgLevel(1); + service.setgCharset(1, CHARSETS['0']); + assert.strictEqual(service.charset, CHARSETS['0']); + }); + + it('should reset glevel, charsets, and active charset', () => { + service.setgCharset(1, CHARSETS['0']); + service.setgLevel(1); + service.reset(); + assert.strictEqual(service.glevel, 0); + assert.deepEqual(service.charsets, []); + assert.ok(service.charset === undefined); + }); +}); diff --git a/src/common/services/CharsetService.ts b/src/common/services/CharsetService.ts index bcd027a64..ffc68514e 100644 --- a/src/common/services/CharsetService.ts +++ b/src/common/services/CharsetService.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { ICharsetService } from 'common/services/Services'; -import { ICharset } from 'common/Types'; +import { ICharsetService } from './Services'; +import { ICharset } from '../Types'; export class CharsetService implements ICharsetService { public serviceBrand: any; diff --git a/src/common/services/CoreService.test.ts b/src/common/services/CoreService.test.ts index 7ae8bf185..c71d627d9 100644 --- a/src/common/services/CoreService.test.ts +++ b/src/common/services/CoreService.test.ts @@ -3,9 +3,9 @@ * @license MIT */ -import { ICoreService } from 'common/services/Services'; -import { CoreService } from 'common/services/CoreService'; -import { MockBufferService, MockLogService, MockOptionsService } from 'common/TestUtils.test'; +import { ICoreService } from './Services'; +import { CoreService } from './CoreService'; +import { MockBufferService, MockLogService, MockOptionsService } from '../TestUtils.test'; import { assert } from 'chai'; describe('CoreService', () => { diff --git a/src/common/services/CoreService.ts b/src/common/services/CoreService.ts index d8962ec88..b3e04ebe6 100644 --- a/src/common/services/CoreService.ts +++ b/src/common/services/CoreService.ts @@ -3,11 +3,10 @@ * @license MIT */ -import { clone } from 'common/Clone'; -import { Disposable } from 'common/Lifecycle'; -import { IDecPrivateModes, IKittyKeyboardState, IModes } from 'common/Types'; -import { IBufferService, ICoreService, ILogService, IOptionsService } from 'common/services/Services'; -import { Emitter } from 'common/Event'; +import { Disposable } from '../Lifecycle'; +import { IDecPrivateModes, IKittyKeyboardState, IModes } from '../Types'; +import { IBufferService, ICoreService, ILogService, IOptionsService } from './Services'; +import { Emitter } from '../Event'; const DEFAULT_MODES: IModes = Object.freeze({ insertMode: false @@ -61,14 +60,14 @@ export class CoreService extends Disposable implements ICoreService { ) { super(); this.isCursorInitialized = _optionsService.rawOptions.showCursorImmediately ?? false; - this.modes = clone(DEFAULT_MODES); - this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES); + this.modes = structuredClone(DEFAULT_MODES); + this.decPrivateModes = structuredClone(DEFAULT_DEC_PRIVATE_MODES); this.kittyKeyboard = DEFAULT_KITTY_KEYBOARD_STATE(); } public reset(): void { - this.modes = clone(DEFAULT_MODES); - this.decPrivateModes = clone(DEFAULT_DEC_PRIVATE_MODES); + this.modes = structuredClone(DEFAULT_MODES); + this.decPrivateModes = structuredClone(DEFAULT_DEC_PRIVATE_MODES); this.kittyKeyboard = DEFAULT_KITTY_KEYBOARD_STATE(); } diff --git a/src/common/services/DecorationService.test.ts b/src/common/services/DecorationService.test.ts index 95c7c0e24..c40913ca7 100644 --- a/src/common/services/DecorationService.test.ts +++ b/src/common/services/DecorationService.test.ts @@ -4,28 +4,26 @@ */ import { assert } from 'chai'; -import { DecorationService } from './DecorationService'; -import { IMarker } from 'common/Types'; -import { Disposable } from 'common/Lifecycle'; -import { Emitter } from 'common/Event'; -import { MockLogService } from 'common/TestUtils.test'; - -function createFakeMarker(line: number): IMarker { - return Object.freeze(new class extends Disposable { - public readonly id = 1; - public readonly line = line; - public readonly isDisposed = false; - public readonly onDispose = new Emitter().event; - }()); -} - -const fakeMarker: IMarker = createFakeMarker(1); +import { DecorationLineCache, DecorationService } from './DecorationService'; +import { IMarker } from '../buffer/Types'; +import { Disposable } from '../Lifecycle'; +import { Emitter } from '../Event'; +import { MockLogService, MockBufferService, MockOptionsService } from '../TestUtils.test'; +import { Buffer } from '../buffer/Buffer'; +import { DEFAULT_ATTR_DATA } from '../buffer/BufferLine'; describe('DecorationService', () => { + let bufferService: MockBufferService; + let service: DecorationService; + + beforeEach(() => { + bufferService = new MockBufferService(80, 24, new MockOptionsService()); + service = new DecorationService(new MockLogService(), bufferService); + }); + it('should set isDisposed to true after dispose', () => { - const service = new DecorationService(new MockLogService()); const decoration = service.registerDecoration({ - marker: fakeMarker + marker: bufferService.buffer.addMarker(1) }); assert.ok(decoration); assert.isFalse(decoration!.isDisposed); @@ -35,22 +33,19 @@ describe('DecorationService', () => { describe('forEachDecorationAtCell', () => { it('should find decoration at its marker line', () => { - const service = new DecorationService(new MockLogService()); const decoration = service.registerDecoration({ - marker: createFakeMarker(5), + marker: bufferService.buffer.addMarker(5), width: 10 }); assert.ok(decoration); - const found: typeof decoration[] = []; service.forEachDecorationAtCell(0, 5, undefined, d => found.push(d)); assert.strictEqual(found.length, 1); }); it('should find decoration with height > 1 on subsequent lines', () => { - const service = new DecorationService(new MockLogService()); const decoration = service.registerDecoration({ - marker: createFakeMarker(5), + marker: bufferService.buffer.addMarker(5), width: 10, height: 3 }); @@ -74,15 +69,13 @@ describe('DecorationService', () => { }); it('should not find decoration outside its x range', () => { - const service = new DecorationService(new MockLogService()); const decoration = service.registerDecoration({ - marker: createFakeMarker(5), + marker: bufferService.buffer.addMarker(5), x: 5, width: 3, height: 2 }); assert.ok(decoration); - const foundAtX4: typeof decoration[] = []; service.forEachDecorationAtCell(4, 5, undefined, d => foundAtX4.push(d)); assert.strictEqual(foundAtX4.length, 0); @@ -99,13 +92,34 @@ describe('DecorationService', () => { service.forEachDecorationAtCell(8, 5, undefined, d => foundAtX8.push(d)); assert.strictEqual(foundAtX8.length, 0); }); + + it('should find multi-line decoration when single-line decorations exist on other lines', () => { + const buffer = bufferService.buffer; + (buffer as Buffer).fillViewportRows(); + + for (let i = 0; i < buffer.lines.length; i++) { + service.registerDecoration({ + marker: buffer.addMarker(i), + width: 5 + }); + } + const multiLine = service.registerDecoration({ + marker: buffer.addMarker(10), + width: 10, + height: 3 + }); + assert.ok(multiLine); + + const found: typeof multiLine[] = []; + service.forEachDecorationAtCell(0, 11, undefined, d => found.push(d)); + assert.include(found, multiLine); + }); }); describe('getDecorationsAtCell', () => { it('should find decoration with height > 1 on subsequent lines', () => { - const service = new DecorationService(new MockLogService()); const decoration = service.registerDecoration({ - marker: createFakeMarker(5), + marker: bufferService.buffer.addMarker(5), width: 10, height: 3 }); @@ -117,4 +131,67 @@ describe('DecorationService', () => { assert.strictEqual([...service.getDecorationsAtCell(0, 8)].length, 0); }); }); + + describe('DecorationLineCache', () => { + it('should return undefined for lines with no indexed decorations', () => { + const cache = new DecorationLineCache(); + assert.isUndefined(cache.getDecorationsOnLine(0)); + }); + }); + + describe('line index maintenance', () => { + it('should keep lookups correct after buffer trim', () => { + const buffer = bufferService.buffer; + (buffer as Buffer).fillViewportRows(); + + const marker = buffer.addMarker(buffer.lines.length - 1); + const decoration = service.registerDecoration({ marker, width: 10 }); + assert.ok(decoration); + + buffer.lines.onTrimEmitter.fire(1); + + const found: typeof decoration[] = []; + service.forEachDecorationAtCell(0, marker.line, undefined, d => found.push(d)); + assert.strictEqual(found.length, 1); + }); + + it('should remove decoration from line index when marker is trimmed off buffer', () => { + const buffer = bufferService.buffer; + (buffer as Buffer).fillViewportRows(); + + const marker = buffer.addMarker(0); + const decoration = service.registerDecoration({ marker, width: 10 }); + assert.ok(decoration); + + buffer.lines.onTrimEmitter.fire(1); + assert.isTrue(marker.isDisposed); + assert.isTrue(decoration!.isDisposed); + + const found: typeof decoration[] = []; + service.forEachDecorationAtCell(0, 0, undefined, d => found.push(d)); + assert.strictEqual(found.length, 0); + }); + + it('should keep multi-line decoration indexed after line insert', async () => { + const buffer = bufferService.buffer; + (buffer as Buffer).fillViewportRows(); + + const marker = buffer.addMarker(3); + const decoration = service.registerDecoration({ marker, width: 10, height: 3 }); + assert.ok(decoration); + + buffer.lines.splice(5, 0, buffer.getBlankLine(DEFAULT_ATTR_DATA)); + await new Promise(resolve => queueMicrotask(resolve)); + + const foundOnSpan: typeof decoration[] = []; + for (let line = marker.line; line < marker.line + 3; line++) { + service.forEachDecorationAtCell(0, line, undefined, d => foundOnSpan.push(d)); + } + assert.include(foundOnSpan, decoration); + + const foundOutsideSpan: typeof decoration[] = []; + service.forEachDecorationAtCell(0, marker.line + 3, undefined, d => foundOutsideSpan.push(d)); + assert.strictEqual(foundOutsideSpan.length, 0); + }); + }); }); diff --git a/src/common/services/DecorationService.ts b/src/common/services/DecorationService.ts index 133e1a985..ea9b7fb14 100644 --- a/src/common/services/DecorationService.ts +++ b/src/common/services/DecorationService.ts @@ -3,19 +3,19 @@ * @license MIT */ -import { css } from 'common/Color'; -import { Disposable, DisposableStore, toDisposable } from 'common/Lifecycle'; -import { IDecorationService, IInternalDecoration, ILogService } from 'common/services/Services'; -import { SortedList } from 'common/SortedList'; -import { IColor } from 'common/Types'; +import type { ICircularList, IDeleteEvent, IInsertEvent } from '../CircularList'; +import { MicrotaskTimer } from '../Async'; +import { css } from '../Color'; +import { Disposable, DisposableStore, MutableDisposable, toDisposable } from '../Lifecycle'; +import { IBufferService, IDecorationService, IInternalDecoration, ILogService } from './Services'; +import { SortedList } from '../SortedList'; +import { IColor } from '../Types'; import { IDecoration, IDecorationOptions, IMarker } from '@xterm/xterm'; -import { Emitter } from 'common/Event'; +import { Emitter } from '../Event'; // Work variables to avoid garbage collection let $xmin = 0; let $xmax = 0; -let $ymin = 0; -let $ymax = 0; export class DecorationService extends Disposable implements IDecorationService { public serviceBrand: any; @@ -27,6 +27,8 @@ export class DecorationService extends Disposable implements IDecorationService */ private readonly _decorations: SortedList; + private readonly _lineCache = this._register(new DecorationLineCache()); + private readonly _onDecorationRegistered = this._register(new Emitter()); public readonly onDecorationRegistered = this._onDecorationRegistered.event; private readonly _onDecorationRemoved = this._register(new Emitter()); @@ -34,12 +36,19 @@ export class DecorationService extends Disposable implements IDecorationService public get decorations(): IterableIterator { return this._decorations.values(); } - constructor(@ILogService private readonly _logService: ILogService) { + constructor( + @ILogService private readonly _logService: ILogService, + @IBufferService private readonly _bufferService: IBufferService + ) { super(); this._decorations = new SortedList(e => e?.marker.line, this._logService); this._register(toDisposable(() => this.reset())); + this._register(this._bufferService.buffers.onBufferActivate(() => { + this._lineCache.attachToBufferLines(this._bufferService.buffer.lines); + })); + this._lineCache.attachToBufferLines(this._bufferService.buffer.lines); } public registerDecoration(options: IDecorationOptions): IDecoration | undefined { @@ -53,12 +62,14 @@ export class DecorationService extends Disposable implements IDecorationService listener.dispose(); if (decoration) { if (this._decorations.delete(decoration)) { + this._lineCache.remove(decoration); this._onDecorationRemoved.fire(decoration); } markerDispose.dispose(); } }); this._decorations.insert(decoration); + this._lineCache.add(decoration); this._onDecorationRegistered.fire(decoration); } return decoration; @@ -69,34 +80,29 @@ export class DecorationService extends Disposable implements IDecorationService d.dispose(); } this._decorations.clear(); + this._lineCache.clear(); } public *getDecorationsAtCell(x: number, line: number, layer?: 'bottom' | 'top'): IterableIterator { - let xmin = 0; - let xmax = 0; - let ymin = 0; - let ymax = 0; - for (const d of this._decorations.values()) { - ymin = d.marker.line; - ymax = ymin + (d.options.height ?? 1); - if (line < ymin || line >= ymax) { - continue; - } - xmin = d.options.x ?? 0; - xmax = xmin + (d.options.width ?? 1); - if (x >= xmin && x < xmax && (!layer || (d.options.layer ?? 'bottom') === layer)) { + const bucket = this._lineCache.getDecorationsOnLine(line); + if (!bucket) { + return; + } + for (const d of bucket) { + $xmin = d.options.x ?? 0; + $xmax = $xmin + (d.options.width ?? 1); + if (x >= $xmin && x < $xmax && (!layer || (d.options.layer ?? 'bottom') === layer)) { yield d; } } } public forEachDecorationAtCell(x: number, line: number, layer: 'bottom' | 'top' | undefined, callback: (decoration: IInternalDecoration) => void): void { - for (const d of this._decorations.values()) { - $ymin = d.marker.line; - $ymax = $ymin + (d.options.height ?? 1); - if (line < $ymin || line >= $ymax) { - continue; - } + const bucket = this._lineCache.getDecorationsOnLine(line); + if (!bucket) { + return; + } + for (const d of bucket) { $xmin = d.options.x ?? 0; $xmax = $xmin + (d.options.width ?? 1); if (x >= $xmin && x < $xmax && (!layer || (d.options.layer ?? 'bottom') === layer)) { @@ -106,10 +112,232 @@ export class DecorationService extends Disposable implements IDecorationService } } +/** + * Per-logical-line index of decorations for fast cell lookup. + * + * Keys are marker.line coordinates (logical buffer lines), not CircularList ring slots. + * Multi-line decorations appear in every line bucket they span. The index is kept aligned + * with marker.line updates via buffer line trim/insert/delete events. + */ +export class DecorationLineCache extends Disposable { + private readonly _decorationsByLine: Map = new Map(); + private readonly _decorations = new Set(); + private readonly _bufferLineListeners = this._register(new MutableDisposable()); + private readonly _lineIndexSyncTimer = this._register(new MicrotaskTimer()); + private _lineIndexSyncCallbacks: (() => void)[] = []; + + public clear(): void { + this._lineIndexSyncCallbacks.length = 0; + this._lineIndexSyncTimer.cancel(); + this._decorationsByLine.clear(); + this._decorations.clear(); + } + + public add(decoration: IInternalDecoration): void { + this._decorations.add(decoration); + this._addToLineBuckets(decoration); + } + + public remove(decoration: IInternalDecoration): void { + this._decorations.delete(decoration); + this._removeFromLineBuckets(decoration); + } + + public getDecorationsOnLine(line: number): ReadonlyArray | undefined { + return this._decorationsByLine.get(line); + } + + public attachToBufferLines(lines: ICircularList): void { + const store = new DisposableStore(); + this._bufferLineListeners.value = store; + store.add(lines.onTrim(amount => this._handleBufferLinesTrim(amount))); + store.add(lines.onInsert(event => this._handleBufferLinesInsert(event))); + store.add(lines.onDelete(event => this._handleBufferLinesDelete(event))); + } + + private _getDecorationHeight(decoration: IInternalDecoration): number { + return decoration.options.height ?? 1; + } + + private _addToLineBuckets(decoration: IInternalDecoration): void { + const start = decoration.marker.line; + if (start < 0) { + return; + } + decoration._indexedStartLine = start; + const height = this._getDecorationHeight(decoration); + for (let line = start; line < start + height; line++) { + let bucket = this._decorationsByLine.get(line); + if (!bucket) { + bucket = []; + this._decorationsByLine.set(line, bucket); + } + bucket.push(decoration); + } + } + + private _removeFromLineBuckets(decoration: IInternalDecoration): void { + const start = decoration._indexedStartLine; + const height = this._getDecorationHeight(decoration); + for (let line = start; line < start + height; line++) { + const bucket = this._decorationsByLine.get(line); + if (!bucket) { + continue; + } + const index = bucket.indexOf(decoration); + if (index !== -1) { + bucket.splice(index, 1); + } + if (bucket.length === 0) { + this._decorationsByLine.delete(line); + } + } + } + + private _reindexDecoration(decoration: IInternalDecoration): void { + this._removeFromLineBuckets(decoration); + if (!decoration.marker.isDisposed && decoration.marker.line >= 0) { + this._addToLineBuckets(decoration); + } + } + + /** Re-index after marker line updates (buffer listeners may run before markers). */ + private _scheduleLineIndexSync(callback: () => void): void { + this._lineIndexSyncCallbacks.push(callback); + this._lineIndexSyncTimer.set(() => { + const callbacks = this._lineIndexSyncCallbacks; + this._lineIndexSyncCallbacks = []; + for (const cb of callbacks) { + cb(); + } + }); + } + + private _handleBufferLinesTrim(amount: number): void { + if (amount <= 0) { + return; + } + const newMap = new Map(); + for (const [line, bucket] of this._decorationsByLine) { + const newLine = line - amount; + if (newLine < 0) { + continue; + } + this._mergeLineBucket(newMap, newLine, bucket); + } + this._decorationsByLine.clear(); + for (const [line, bucket] of newMap) { + this._decorationsByLine.set(line, bucket); + } + for (const d of this._decorations) { + if (!d.marker.isDisposed) { + d._indexedStartLine -= amount; + } + } + } + + private _handleBufferLinesInsert(event: IInsertEvent): void { + this._scheduleLineIndexSync(() => this._applyBufferLinesInsert(event)); + } + + private _handleBufferLinesDelete(event: IDeleteEvent): void { + this._scheduleLineIndexSync(() => this._applyBufferLinesDelete(event)); + } + + private _mergeLineBucket(newMap: Map, line: number, bucket: IInternalDecoration[]): void { + const existing = newMap.get(line); + if (existing) { + for (let i = 0, len = bucket.length; i < len; i++) { + existing.push(bucket[i]); + } + } else { + newMap.set(line, bucket.slice()); + } + } + + /** + * Shift indexed line keys and sync start lines. O(unique indexed lines), not O(decoration count). + * Decorations that span the insert point are re-indexed individually (rare vs single-line hits). + */ + private _applyBufferLinesInsert(event: IInsertEvent): void { + const { index, amount } = event; + const spanCrossers: IInternalDecoration[] = []; + for (const d of this._decorations) { + if (d.marker.isDisposed) { + continue; + } + const start = d._indexedStartLine; + if (start < index && start + this._getDecorationHeight(d) > index) { + spanCrossers.push(d); + this._removeFromLineBuckets(d); + } + } + const newMap = new Map(); + for (const [line, bucket] of this._decorationsByLine) { + const newLine = line >= index ? line + amount : line; + this._mergeLineBucket(newMap, newLine, bucket); + } + this._decorationsByLine.clear(); + for (const [line, bucket] of newMap) { + this._decorationsByLine.set(line, bucket); + } + for (const d of this._decorations) { + if (d.marker.isDisposed) { + continue; + } + if (d._indexedStartLine >= index) { + d._indexedStartLine = d.marker.line; + } + } + for (const d of spanCrossers) { + this._addToLineBuckets(d); + } + } + + /** + * Drop deleted line keys, shift keys below, sync start lines. Full re-index only when a + * multi-line decoration spans across the deleted range but survives. + */ + private _applyBufferLinesDelete(event: IDeleteEvent): void { + const deleteEnd = event.index + event.amount; + const newMap = new Map(); + for (const [line, bucket] of this._decorationsByLine) { + if (line >= event.index && line < deleteEnd) { + continue; + } + const newLine = line >= deleteEnd ? line - event.amount : line; + this._mergeLineBucket(newMap, newLine, bucket); + } + this._decorationsByLine.clear(); + for (const [line, bucket] of newMap) { + this._decorationsByLine.set(line, bucket); + } + const toReindex: IInternalDecoration[] = []; + for (const d of this._decorations) { + if (d.marker.isDisposed) { + continue; + } + const start = d._indexedStartLine; + const height = this._getDecorationHeight(d); + if (start >= deleteEnd) { + d._indexedStartLine = d.marker.line; + } else if (start < event.index && start + height > deleteEnd) { + toReindex.push(d); + } + } + for (const d of toReindex) { + this._reindexDecoration(d); + } + } +} + class Decoration extends DisposableStore implements IInternalDecoration { public readonly marker: IMarker; public element: HTMLElement | undefined; + /** Start line used for line-index removal when marker.line is cleared on dispose. */ + public _indexedStartLine: number; + public readonly onRenderEmitter = this.add(new Emitter()); public readonly onRender = this.onRenderEmitter.event; private readonly _onDispose = this.add(new Emitter()); @@ -144,6 +372,7 @@ class Decoration extends DisposableStore implements IInternalDecoration { ) { super(); this.marker = options.marker; + this._indexedStartLine = options.marker.line; if (this.options.overviewRulerOptions && !this.options.overviewRulerOptions.position) { this.options.overviewRulerOptions.position = 'full'; } diff --git a/src/common/services/InstantiationService.ts b/src/common/services/InstantiationService.ts index 7e7695485..5d2489a86 100644 --- a/src/common/services/InstantiationService.ts +++ b/src/common/services/InstantiationService.ts @@ -9,8 +9,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IInstantiationService, IServiceIdentifier } from 'common/services/Services'; -import { getServiceDependencies } from 'common/services/ServiceRegistry'; +import { IInstantiationService } from './Services'; +import { IServiceIdentifier, getServiceDependencies } from './ServiceRegistry'; export class ServiceCollection { diff --git a/src/common/services/LogService.ts b/src/common/services/LogService.ts index 8bc1e0aaa..75ff68e29 100644 --- a/src/common/services/LogService.ts +++ b/src/common/services/LogService.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { Disposable } from 'common/Lifecycle'; -import { ILogService, IOptionsService, LogLevelEnum } from 'common/services/Services'; +import { Disposable } from '../Lifecycle'; +import { ILogService, IOptionsService, LogLevelEnum } from './Services'; type LogType = (message?: any, ...optionalParams: any[]) => void; diff --git a/src/common/services/MouseStateService.test.ts b/src/common/services/MouseStateService.test.ts index 0f2cd489a..7daf7d1e8 100644 --- a/src/common/services/MouseStateService.test.ts +++ b/src/common/services/MouseStateService.test.ts @@ -2,9 +2,9 @@ * Copyright (c) 2019 The xterm.js authors. All rights reserved. * @license MIT */ -import { MouseStateService } from 'common/services/MouseStateService'; +import { MouseStateService } from './MouseStateService'; import { assert } from 'chai'; -import { ICoreMouseEvent, CoreMouseEventType } from 'common/Types'; +import { ICoreMouseEvent, CoreMouseEventType } from '../Types'; function toBytes(s: string | undefined): number[] { if (!s) { diff --git a/src/common/services/MouseStateService.ts b/src/common/services/MouseStateService.ts index 21420460a..40a448f57 100644 --- a/src/common/services/MouseStateService.ts +++ b/src/common/services/MouseStateService.ts @@ -2,10 +2,10 @@ * Copyright (c) 2019 The xterm.js authors. All rights reserved. * @license MIT */ -import { IMouseStateService } from 'common/services/Services'; -import { ICoreMouseProtocol, ICoreMouseEvent, CoreMouseEncoding, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types'; -import { Disposable } from 'common/Lifecycle'; -import { Emitter } from 'common/Event'; +import { IMouseStateService } from './Services'; +import { ICoreMouseProtocol, ICoreMouseEvent, CoreMouseEncoding, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from '../Types'; +import { Disposable } from '../Lifecycle'; +import { Emitter } from '../Event'; /** * Supported default protocols. diff --git a/src/common/services/OptionsService.test.ts b/src/common/services/OptionsService.test.ts index 004f73168..95e2058e9 100644 --- a/src/common/services/OptionsService.test.ts +++ b/src/common/services/OptionsService.test.ts @@ -4,8 +4,8 @@ */ import { assert } from 'chai'; -import { OptionsService, DEFAULT_OPTIONS } from 'common/services/OptionsService'; -import { IDisposable } from 'common/Types'; +import { OptionsService, DEFAULT_OPTIONS } from './OptionsService'; +import { IDisposable } from '../Types'; describe('OptionsService', () => { describe('constructor', () => { diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index ec647aaa5..d14982e3f 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -3,11 +3,11 @@ * @license MIT */ -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { isMac } from 'common/Platform'; -import { CursorStyle, IDisposable } from 'common/Types'; -import { FontWeight, IOptionsService, ITerminalOptions } from 'common/services/Services'; -import { Emitter } from 'common/Event'; +import { Disposable, toDisposable } from '../Lifecycle'; +import { isMac } from '../Platform'; +import { CursorStyle, IDisposable } from '../Types'; +import { FontWeight, IOptionsService, ITerminalOptions } from './Services'; +import { Emitter } from '../Event'; export const DEFAULT_OPTIONS: Readonly> = { cols: 80, @@ -41,6 +41,7 @@ export const DEFAULT_OPTIONS: Readonly> = { macOptionIsMeta: false, macOptionClickForcesSelection: false, minimumContrastRatio: 1, + mouseEventsRequireAlt: false, disableStdin: false, allowProposedApi: false, allowTransparency: false, diff --git a/src/common/services/OscLinkService.test.ts b/src/common/services/OscLinkService.test.ts index cc6c2228a..c49928b51 100644 --- a/src/common/services/OscLinkService.test.ts +++ b/src/common/services/OscLinkService.test.ts @@ -4,12 +4,12 @@ */ import { assert } from 'chai'; -import { AttributeData } from 'common/buffer/AttributeData'; -import { BufferService } from 'common/services/BufferService'; -import { OptionsService } from 'common/services/OptionsService'; -import { OscLinkService } from 'common/services/OscLinkService'; -import { IBufferService, IOptionsService, IOscLinkService } from 'common/services/Services'; -import { MockLogService } from 'common/TestUtils.test'; +import { AttributeData } from '../buffer/AttributeData'; +import { BufferService } from './BufferService'; +import { OptionsService } from './OptionsService'; +import { OscLinkService } from './OscLinkService'; +import { IBufferService, IOptionsService, IOscLinkService } from './Services'; +import { MockLogService } from '../TestUtils.test'; describe('OscLinkService', () => { describe('constructor', () => { diff --git a/src/common/services/OscLinkService.ts b/src/common/services/OscLinkService.ts index 13bd8aa4b..605e85002 100644 --- a/src/common/services/OscLinkService.ts +++ b/src/common/services/OscLinkService.ts @@ -2,8 +2,9 @@ * Copyright (c) 2022 The xterm.js authors. All rights reserved. * @license MIT */ -import { IBufferService, IOscLinkService } from 'common/services/Services'; -import { IMarker, IOscLinkData } from 'common/Types'; +import { IBufferService, IOscLinkService } from './Services'; +import { IOscLinkData } from '../Types'; +import { IMarker } from '../buffer/Types'; export class OscLinkService implements IOscLinkService { public serviceBrand: any; diff --git a/src/common/services/ServiceRegistry.ts b/src/common/services/ServiceRegistry.ts index af51d1641..282a7bbe1 100644 --- a/src/common/services/ServiceRegistry.ts +++ b/src/common/services/ServiceRegistry.ts @@ -9,7 +9,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IServiceIdentifier } from 'common/services/Services'; +export interface IServiceIdentifier { + (...args: any[]): void; + type: T; + _id: string; +} const enum Constants { DI_TARGET = 'di$target', diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index a15dc23dc..8f0aeeed1 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -4,10 +4,10 @@ */ import type { IDecoration, IDecorationOptions, ILinkHandler, ILogger, IWindowsPty, IOverviewRulerOptions } from '@xterm/xterm'; -import { CoreMouseEncoding, CoreMouseEventType, CursorInactiveStyle, CursorStyle, IAttributeData, ICharset, IColor, ICoreMouseEvent, ICoreMouseProtocol, IDecPrivateModes, IDisposable, IKittyKeyboardState, IModes, IOscLinkData, IWindowOptions } from 'common/Types'; -import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { createDecorator } from 'common/services/ServiceRegistry'; -import type { Emitter, IEvent } from 'common/Event'; +import { CoreMouseEncoding, CoreMouseEventType, CursorInactiveStyle, CursorStyle, ICharset, IColor, ICoreMouseEvent, ICoreMouseProtocol, IDecPrivateModes, IDisposable, IKittyKeyboardState, IModes, IOscLinkData, IWindowOptions } from '../Types'; +import { IAttributeData, IBuffer, IBufferSet } from '../buffer/Types'; +import { createDecorator, IServiceIdentifier } from './ServiceRegistry'; +import type { Emitter, IEvent } from '../Event'; export const IBufferService = createDecorator('BufferService'); export interface IBufferService { @@ -119,12 +119,6 @@ export interface ICharsetService { setgCharset(g: number, charset: ICharset | undefined): void; } -export interface IServiceIdentifier { - (...args: any[]): void; - type: T; - _id: string; -} - export interface IBrandedService { serviceBrand: undefined; } @@ -234,6 +228,7 @@ export interface ITerminalOptions { macOptionIsMeta?: boolean; macOptionClickForcesSelection?: boolean; minimumContrastRatio?: number; + mouseEventsRequireAlt?: boolean; reflowCursorLine?: boolean; rescaleOverlappingGlyphs?: boolean; rightClickSelectsWord?: boolean; @@ -349,13 +344,13 @@ export type UnicodeCharWidth = 0 | 1 | 2; export const IUnicodeService = createDecorator('UnicodeService'); export interface IUnicodeService { serviceBrand: undefined; - /** Register an Unicode version provider. */ + /** Register a Unicode version provider. */ register(provider: IUnicodeVersionProvider): void; /** Registered Unicode versions. */ readonly versions: string[]; /** Currently active version. */ activeVersion: string; - /** Event triggered, when activate version changed. */ + /** Event triggered when the active version changes. */ readonly onChange: IEvent; /** @@ -396,4 +391,6 @@ export interface IInternalDecoration extends IDecoration { readonly backgroundColorRGB: IColor | undefined; readonly foregroundColorRGB: IColor | undefined; readonly onRenderEmitter: Emitter; + /** @internal Start line for line-index removal; kept in sync on buffer line shifts. */ + _indexedStartLine: number; } diff --git a/src/common/services/UnicodeService.test.ts b/src/common/services/UnicodeService.test.ts index 01e3c0862..6d5903fb0 100644 --- a/src/common/services/UnicodeService.test.ts +++ b/src/common/services/UnicodeService.test.ts @@ -4,8 +4,9 @@ */ import { assert } from 'chai'; -import { UnicodeService } from 'common/services/UnicodeService'; -import { IUnicodeVersionProvider } from 'common/services/Services'; +import { UnicodeV6 } from '../input/UnicodeV6'; +import { UnicodeService } from './UnicodeService'; +import { IUnicodeVersionProvider } from './Services'; class DummyProvider implements IUnicodeVersionProvider { public version = '123'; @@ -21,6 +22,7 @@ describe('unicode provider', () => { let us: UnicodeService; beforeEach(() => { us = new UnicodeService(); + us.register(new UnicodeV6()); }); it('default to V6', () => { assert.equal(us.activeVersion, '6'); diff --git a/src/common/services/UnicodeService.ts b/src/common/services/UnicodeService.ts index d0dd8584d..61283c466 100644 --- a/src/common/services/UnicodeService.ts +++ b/src/common/services/UnicodeService.ts @@ -3,16 +3,15 @@ * @license MIT */ -import { UnicodeV6 } from 'common/input/UnicodeV6'; -import { IUnicodeService, IUnicodeVersionProvider, UnicodeCharProperties, UnicodeCharWidth } from 'common/services/Services'; -import { Emitter } from 'common/Event'; +import { IUnicodeService, IUnicodeVersionProvider, UnicodeCharProperties, UnicodeCharWidth } from './Services'; +import { Emitter } from '../Event'; export class UnicodeService implements IUnicodeService { public serviceBrand: any; private _providers: {[key: string]: IUnicodeVersionProvider} = Object.create(null); private _active: string = ''; - private _activeProvider: IUnicodeVersionProvider; + private _activeProvider!: IUnicodeVersionProvider; private readonly _onChange = new Emitter(); public readonly onChange = this._onChange.event; @@ -30,13 +29,6 @@ export class UnicodeService implements IUnicodeService { return ((state & 0xffffff) << 3) | ((width & 3) << 1) | (shouldJoin?1:0); } - constructor() { - const defaultProvider = new UnicodeV6(); - this.register(defaultProvider); - this._active = defaultProvider.version; - this._activeProvider = defaultProvider; - } - public dispose(): void { this._onChange.dispose(); } @@ -60,6 +52,9 @@ export class UnicodeService implements IUnicodeService { public register(provider: IUnicodeVersionProvider): void { this._providers[provider.version] = provider; + if (!this._active) { + this.activeVersion = provider.version; + } } /** diff --git a/src/common/tsconfig.json b/src/common/tsconfig.json index 31a893756..c7488a89e 100644 --- a/src/common/tsconfig.json +++ b/src/common/tsconfig.json @@ -10,11 +10,7 @@ "outDir": "../../out", "types": [ "../../node_modules/@types/mocha" - ], - "paths": { - "common/*": [ "./../common/*" ], - "*": [ "./../*" ] - } + ] }, "include": [ "./**/*", diff --git a/src/headless/Terminal.ts b/src/headless/Terminal.ts index cc8b152b2..16dc932be 100644 --- a/src/headless/Terminal.ts +++ b/src/headless/Terminal.ts @@ -21,11 +21,11 @@ * http://linux.die.net/man/7/urxvt */ -import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { IBuffer } from 'common/buffer/Types'; -import { CoreTerminal } from 'common/CoreTerminal'; -import { IMarker, ITerminalOptions } from 'common/Types'; -import { Emitter, EventUtils } from 'common/Event'; +import { DEFAULT_ATTR_DATA } from '../common/buffer/BufferLine'; +import { IBuffer, IMarker } from '../common/buffer/Types'; +import { CoreTerminal } from '../common/CoreTerminal'; +import { ITerminalOptions } from '../common/Types'; +import { Emitter, EventUtils } from '../common/Event'; export class Terminal extends CoreTerminal { private readonly _onBell = this._register(new Emitter()); @@ -69,12 +69,7 @@ export class Terminal extends CoreTerminal { return this.buffer.markers; } - public addMarker(cursorYOffset: number): IMarker | undefined { - // Disallow markers on the alt buffer - if (this.buffer !== this.buffers.normal) { - return; - } - + public registerMarker(cursorYOffset: number): IMarker { return this.buffer.addMarker(this.buffer.ybase + this.buffer.y + cursorYOffset); } @@ -104,10 +99,7 @@ export class Terminal extends CoreTerminal { * Clear the entire buffer, making the prompt line the new first line. */ public clear(): void { - if (this.buffer.ybase === 0 && this.buffer.y === 0) { - // Don't clear if it's already clear - return; - } + this.buffer.clearAllMarkers(); this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y)!); this.buffer.lines.length = 1; this.buffer.ydisp = 0; diff --git a/src/headless/public/Terminal.test.ts b/src/headless/public/Terminal.test.ts index 0b35fb0e7..6fa9d32e1 100644 --- a/src/headless/public/Terminal.test.ts +++ b/src/headless/public/Terminal.test.ts @@ -4,7 +4,7 @@ */ import { deepStrictEqual, strictEqual, throws } from 'assert'; -import { Terminal } from 'headless/public/Terminal'; +import { Terminal } from './Terminal'; import { ITerminalOptions } from '@xterm/headless'; let term: Terminal; @@ -114,6 +114,29 @@ describe('Headless API Tests', function (): void { } }); + it('clear disposes markers', async () => { + term = new Terminal({ rows: 5, allowProposedApi: true }); + for (let i = 0; i < 10; i++) { + await writeSync('\n\rtest' + i); + } + const markers = [ + term.registerMarker(1), + term.registerMarker(2), + term.registerMarker(3), + term.registerMarker(4) + ]; + let disposeCount = 0; + for (const marker of markers) { + marker.onDispose(() => disposeCount++); + } + term.clear(); + strictEqual(disposeCount, markers.length); + for (const marker of markers) { + strictEqual(marker.isDisposed, true); + } + strictEqual(term.markers.length, 0); + }); + describe('options', () => { const termOptions = { cols: 80, @@ -396,6 +419,15 @@ describe('Headless API Tests', function (): void { strictEqual(term.buffer.normal.getLine(0)!.translateToString(), 'norm '); strictEqual(term.buffer.alternate.getLine(0), undefined); }); + + it('registerMarker on alternate buffer', async () => { + term = new Terminal({ cols: 5, allowProposedApi: true }); + await writeSync('\x1b[?47h'); + const marker = term.registerMarker(0); + strictEqual(term.buffer.active.type, 'alternate'); + strictEqual(term.markers.length, 1); + strictEqual(term.markers[0], marker); + }); }); describe('modes', () => { diff --git a/src/headless/public/Terminal.ts b/src/headless/public/Terminal.ts index 0d4e6e93b..22dabb02a 100644 --- a/src/headless/public/Terminal.ts +++ b/src/headless/public/Terminal.ts @@ -3,15 +3,15 @@ * @license MIT */ -import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi'; -import { ParserApi } from 'common/public/ParserApi'; -import { UnicodeApi } from 'common/public/UnicodeApi'; +import { BufferNamespaceApi } from '../../common/public/BufferNamespaceApi'; +import { ParserApi } from '../../common/public/ParserApi'; +import { UnicodeApi } from '../../common/public/UnicodeApi'; import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, ITerminalInitOnlyOptions, IUnicodeHandling, Terminal as ITerminalApi } from '@xterm/headless'; -import { Terminal as TerminalCore } from 'headless/Terminal'; -import { AddonManager } from 'common/public/AddonManager'; -import { ITerminalOptions } from 'common/Types'; -import { Disposable } from 'common/Lifecycle'; -import type { IEvent } from 'common/Event'; +import { Terminal as TerminalCore } from '../Terminal'; +import { AddonManager } from '../../common/public/AddonManager'; +import { ITerminalOptions } from '../../common/Types'; +import { Disposable } from '../../common/Lifecycle'; +import type { IEvent } from '../../common/Event'; /** * The set of options that only have an effect when set in the Terminal constructor. */ @@ -40,15 +40,6 @@ export class Terminal extends Disposable implements ITerminalApi { }; for (const propName in this._core.options) { - Object.defineProperty(this._publicOptions, propName, { - get: () => { - return this._core.options[propName]; - }, - set: (value: any) => { - this._checkReadonlyOptions(propName); - this._core.options[propName] = value; - } - }); const desc = { get: getter.bind(this, propName), set: setter.bind(this, propName) @@ -139,11 +130,11 @@ export class Terminal extends Disposable implements ITerminalApi { this._verifyIntegers(columns, rows); this._core.resize(columns, rows); } - public registerMarker(cursorYOffset: number = 0): IMarker | undefined { + public registerMarker(cursorYOffset: number = 0): IMarker { this._verifyIntegers(cursorYOffset); - return this._core.addMarker(cursorYOffset); + return this._core.registerMarker(cursorYOffset); } - public addMarker(cursorYOffset: number): IMarker | undefined { + public addMarker(cursorYOffset: number): IMarker { return this.registerMarker(cursorYOffset); } public dispose(): void { diff --git a/src/headless/tsconfig.json b/src/headless/tsconfig.json index 0c445bcfc..96b0cc39b 100644 --- a/src/headless/tsconfig.json +++ b/src/headless/tsconfig.json @@ -10,11 +10,7 @@ "types": [ "../../node_modules/@types/mocha", "../../node_modules/@types/node" - ], - "paths": { - "common/*": [ "./../common/*" ], - "*": [ "./../*" ] - } + ] }, "include": [ "./**/*", diff --git a/src/tsconfig-library-base.json b/src/tsconfig-library-base.json index 00cecc066..e08695d75 100644 --- a/src/tsconfig-library-base.json +++ b/src/tsconfig-library-base.json @@ -4,7 +4,6 @@ "composite": true, "strict": true, "declarationMap": true, - "experimentalDecorators": true, - "downlevelIteration": true + "experimentalDecorators": true } } diff --git a/test/benchmark/DecorationService.benchmark.ts b/test/benchmark/DecorationService.benchmark.ts new file mode 100644 index 000000000..1a2033de1 --- /dev/null +++ b/test/benchmark/DecorationService.benchmark.ts @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { perfContext, before, RuntimeCase } from 'xterm-benchmark'; +import { DecorationService } from 'common/services/DecorationService'; +import { MockLogService, MockBufferService, MockOptionsService } from 'common/TestUtils.test'; +const enum Constants { + COLS = 80, + ROWS = 30, + SINGLE_LINE_DECORATION_COUNT = 20_000, + MULTI_LINE_DECORATION_COUNT = 19_999, + MULTI_LINE_HEIGHT = 2, + VIEWPORT_SCAN_ITERATIONS = 20 +} + +function registerSingleLineDecorations(service: DecorationService, bufferService: MockBufferService, count: number): void { + const buffer = bufferService.buffer; + for (let i = 0; i < count; i++) { + const line = i % 5000; + const marker = buffer.addMarker(line); + service.registerDecoration({ marker, width: Constants.COLS }); + } +} + +function registerMixedDecorations(service: DecorationService, bufferService: MockBufferService): void { + const buffer = bufferService.buffer; + for (let i = 0; i < Constants.MULTI_LINE_DECORATION_COUNT; i++) { + const line = i % 5000; + const marker = buffer.addMarker(line); + service.registerDecoration({ marker, width: Constants.COLS }); + } + const multiLineMarker = buffer.addMarker(10); + service.registerDecoration({ + marker: multiLineMarker, + width: Constants.COLS, + height: Constants.MULTI_LINE_HEIGHT + }); +} + +function scanVisibleGrid(service: DecorationService, rows: number, cols: number): number { + let hitCount = 0; + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + service.forEachDecorationAtCell(col, row, undefined, () => { + hitCount++; + }); + } + } + return hitCount; +} + +perfContext('DecorationService.forEachDecorationAtCell', () => { + perfContext('single-line dense / sparse line hit', () => { + let service: DecorationService; + let bufferService: MockBufferService; + before(() => { + bufferService = new MockBufferService(Constants.COLS, Constants.ROWS, new MockOptionsService()); + service = new DecorationService(new MockLogService(), bufferService); + registerSingleLineDecorations(service, bufferService, Constants.SINGLE_LINE_DECORATION_COUNT); + }); + new RuntimeCase('', () => { + let hitCount = 0; + for (let i = 0; i < Constants.VIEWPORT_SCAN_ITERATIONS; i++) { + service.forEachDecorationAtCell(0, 0, undefined, () => { + hitCount++; + }); + } + return { payloadSize: Constants.VIEWPORT_SCAN_ITERATIONS, hitCount }; + }, { fork: false }).showAverageRuntime(); + }); + + perfContext('mixed single-line + multi-line / sparse line hit', () => { + let service: DecorationService; + let bufferService: MockBufferService; + before(() => { + bufferService = new MockBufferService(Constants.COLS, Constants.ROWS, new MockOptionsService()); + service = new DecorationService(new MockLogService(), bufferService); + registerMixedDecorations(service, bufferService); + }); + new RuntimeCase('', () => { + let hitCount = 0; + for (let i = 0; i < Constants.VIEWPORT_SCAN_ITERATIONS; i++) { + service.forEachDecorationAtCell(0, 10, undefined, () => { + hitCount++; + }); + } + return { payloadSize: Constants.VIEWPORT_SCAN_ITERATIONS, hitCount }; + }, { fork: false }).showAverageRuntime(); + }); + + perfContext('viewport grid scan', () => { + let service: DecorationService; + let bufferService: MockBufferService; + before(() => { + bufferService = new MockBufferService(Constants.COLS, Constants.ROWS, new MockOptionsService()); + service = new DecorationService(new MockLogService(), bufferService); + registerSingleLineDecorations(service, bufferService, Constants.SINGLE_LINE_DECORATION_COUNT); + }); + new RuntimeCase('', () => { + let totalHits = 0; + for (let i = 0; i < Constants.VIEWPORT_SCAN_ITERATIONS; i++) { + totalHits += scanVisibleGrid(service, Constants.ROWS, Constants.COLS); + } + return { payloadSize: Constants.VIEWPORT_SCAN_ITERATIONS * Constants.ROWS * Constants.COLS, totalHits }; + }, { fork: false }).showAverageRuntime(); + }); +}); diff --git a/test/benchmark/tsconfig.json b/test/benchmark/tsconfig.json index 2f24f0762..c8e17ee61 100644 --- a/test/benchmark/tsconfig.json +++ b/test/benchmark/tsconfig.json @@ -8,15 +8,14 @@ "types": [ "../../node_modules/@types/node" ], - "moduleResolution": "node", + "moduleResolution": "nodenext", "strict": false, "target": "es2021", - "module": "commonjs", + "module": "nodenext", "paths": { - "common/*": [ "../../src/common/*" ], - "browser/*": [ "../../src/browser/*" ], - "Terminal": ["../../src/Terminal"] - }, + "common/*": ["../../src/common/*"], + "browser/*": ["../../src/browser/*"] + } }, "include": [ "./**/*", diff --git a/fixtures/escape_sequence_files/NOTES b/test/fixtures/escape_sequence_files/NOTES similarity index 100% rename from fixtures/escape_sequence_files/NOTES rename to test/fixtures/escape_sequence_files/NOTES diff --git a/fixtures/escape_sequence_files/run_tests.py b/test/fixtures/escape_sequence_files/run_tests.py similarity index 100% rename from fixtures/escape_sequence_files/run_tests.py rename to test/fixtures/escape_sequence_files/run_tests.py diff --git a/fixtures/escape_sequence_files/t0001-all_printable.in b/test/fixtures/escape_sequence_files/t0001-all_printable.in similarity index 100% rename from fixtures/escape_sequence_files/t0001-all_printable.in rename to test/fixtures/escape_sequence_files/t0001-all_printable.in diff --git a/fixtures/escape_sequence_files/t0001-all_printable.text b/test/fixtures/escape_sequence_files/t0001-all_printable.text similarity index 100% rename from fixtures/escape_sequence_files/t0001-all_printable.text rename to test/fixtures/escape_sequence_files/t0001-all_printable.text diff --git a/fixtures/escape_sequence_files/t0002-history.in b/test/fixtures/escape_sequence_files/t0002-history.in similarity index 100% rename from fixtures/escape_sequence_files/t0002-history.in rename to test/fixtures/escape_sequence_files/t0002-history.in diff --git a/fixtures/escape_sequence_files/t0002-history.text b/test/fixtures/escape_sequence_files/t0002-history.text similarity index 100% rename from fixtures/escape_sequence_files/t0002-history.text rename to test/fixtures/escape_sequence_files/t0002-history.text diff --git a/fixtures/escape_sequence_files/t0002j-simple_string.in b/test/fixtures/escape_sequence_files/t0002j-simple_string.in similarity index 100% rename from fixtures/escape_sequence_files/t0002j-simple_string.in rename to test/fixtures/escape_sequence_files/t0002j-simple_string.in diff --git a/fixtures/escape_sequence_files/t0002j-simple_string.text b/test/fixtures/escape_sequence_files/t0002j-simple_string.text similarity index 100% rename from fixtures/escape_sequence_files/t0002j-simple_string.text rename to test/fixtures/escape_sequence_files/t0002j-simple_string.text diff --git a/fixtures/escape_sequence_files/t0003-line_wrap.in b/test/fixtures/escape_sequence_files/t0003-line_wrap.in similarity index 100% rename from fixtures/escape_sequence_files/t0003-line_wrap.in rename to test/fixtures/escape_sequence_files/t0003-line_wrap.in diff --git a/fixtures/escape_sequence_files/t0003-line_wrap.text b/test/fixtures/escape_sequence_files/t0003-line_wrap.text similarity index 100% rename from fixtures/escape_sequence_files/t0003-line_wrap.text rename to test/fixtures/escape_sequence_files/t0003-line_wrap.text diff --git a/fixtures/escape_sequence_files/t0003j-LF.in b/test/fixtures/escape_sequence_files/t0003j-LF.in similarity index 100% rename from fixtures/escape_sequence_files/t0003j-LF.in rename to test/fixtures/escape_sequence_files/t0003j-LF.in diff --git a/fixtures/escape_sequence_files/t0003j-LF.text b/test/fixtures/escape_sequence_files/t0003j-LF.text similarity index 100% rename from fixtures/escape_sequence_files/t0003j-LF.text rename to test/fixtures/escape_sequence_files/t0003j-LF.text diff --git a/fixtures/escape_sequence_files/t0004-LF.in b/test/fixtures/escape_sequence_files/t0004-LF.in similarity index 100% rename from fixtures/escape_sequence_files/t0004-LF.in rename to test/fixtures/escape_sequence_files/t0004-LF.in diff --git a/fixtures/escape_sequence_files/t0004-LF.text b/test/fixtures/escape_sequence_files/t0004-LF.text similarity index 100% rename from fixtures/escape_sequence_files/t0004-LF.text rename to test/fixtures/escape_sequence_files/t0004-LF.text diff --git a/fixtures/escape_sequence_files/t0004j-CR.in b/test/fixtures/escape_sequence_files/t0004j-CR.in similarity index 100% rename from fixtures/escape_sequence_files/t0004j-CR.in rename to test/fixtures/escape_sequence_files/t0004j-CR.in diff --git a/fixtures/escape_sequence_files/t0004j-CR.text b/test/fixtures/escape_sequence_files/t0004j-CR.text similarity index 100% rename from fixtures/escape_sequence_files/t0004j-CR.text rename to test/fixtures/escape_sequence_files/t0004j-CR.text diff --git a/fixtures/escape_sequence_files/t0005-CR.in b/test/fixtures/escape_sequence_files/t0005-CR.in similarity index 100% rename from fixtures/escape_sequence_files/t0005-CR.in rename to test/fixtures/escape_sequence_files/t0005-CR.in diff --git a/fixtures/escape_sequence_files/t0005-CR.text b/test/fixtures/escape_sequence_files/t0005-CR.text similarity index 100% rename from fixtures/escape_sequence_files/t0005-CR.text rename to test/fixtures/escape_sequence_files/t0005-CR.text diff --git a/fixtures/escape_sequence_files/t0006-IND.in b/test/fixtures/escape_sequence_files/t0006-IND.in similarity index 100% rename from fixtures/escape_sequence_files/t0006-IND.in rename to test/fixtures/escape_sequence_files/t0006-IND.in diff --git a/fixtures/escape_sequence_files/t0006-IND.text b/test/fixtures/escape_sequence_files/t0006-IND.text similarity index 100% rename from fixtures/escape_sequence_files/t0006-IND.text rename to test/fixtures/escape_sequence_files/t0006-IND.text diff --git a/fixtures/escape_sequence_files/t0007-space_at_end.in b/test/fixtures/escape_sequence_files/t0007-space_at_end.in similarity index 100% rename from fixtures/escape_sequence_files/t0007-space_at_end.in rename to test/fixtures/escape_sequence_files/t0007-space_at_end.in diff --git a/fixtures/escape_sequence_files/t0007-space_at_end.text b/test/fixtures/escape_sequence_files/t0007-space_at_end.text similarity index 100% rename from fixtures/escape_sequence_files/t0007-space_at_end.text rename to test/fixtures/escape_sequence_files/t0007-space_at_end.text diff --git a/fixtures/escape_sequence_files/t0008-BS.in b/test/fixtures/escape_sequence_files/t0008-BS.in similarity index 100% rename from fixtures/escape_sequence_files/t0008-BS.in rename to test/fixtures/escape_sequence_files/t0008-BS.in diff --git a/fixtures/escape_sequence_files/t0008-BS.text b/test/fixtures/escape_sequence_files/t0008-BS.text similarity index 100% rename from fixtures/escape_sequence_files/t0008-BS.text rename to test/fixtures/escape_sequence_files/t0008-BS.text diff --git a/fixtures/escape_sequence_files/t0009-NEL.in b/test/fixtures/escape_sequence_files/t0009-NEL.in similarity index 100% rename from fixtures/escape_sequence_files/t0009-NEL.in rename to test/fixtures/escape_sequence_files/t0009-NEL.in diff --git a/fixtures/escape_sequence_files/t0009-NEL.text b/test/fixtures/escape_sequence_files/t0009-NEL.text similarity index 100% rename from fixtures/escape_sequence_files/t0009-NEL.text rename to test/fixtures/escape_sequence_files/t0009-NEL.text diff --git a/fixtures/escape_sequence_files/t0010-RI.in b/test/fixtures/escape_sequence_files/t0010-RI.in similarity index 100% rename from fixtures/escape_sequence_files/t0010-RI.in rename to test/fixtures/escape_sequence_files/t0010-RI.in diff --git a/fixtures/escape_sequence_files/t0010-RI.text b/test/fixtures/escape_sequence_files/t0010-RI.text similarity index 100% rename from fixtures/escape_sequence_files/t0010-RI.text rename to test/fixtures/escape_sequence_files/t0010-RI.text diff --git a/fixtures/escape_sequence_files/t0011-RI_scroll.in b/test/fixtures/escape_sequence_files/t0011-RI_scroll.in similarity index 100% rename from fixtures/escape_sequence_files/t0011-RI_scroll.in rename to test/fixtures/escape_sequence_files/t0011-RI_scroll.in diff --git a/fixtures/escape_sequence_files/t0011-RI_scroll.text b/test/fixtures/escape_sequence_files/t0011-RI_scroll.text similarity index 100% rename from fixtures/escape_sequence_files/t0011-RI_scroll.text rename to test/fixtures/escape_sequence_files/t0011-RI_scroll.text diff --git a/fixtures/escape_sequence_files/t0012-VT.in b/test/fixtures/escape_sequence_files/t0012-VT.in similarity index 100% rename from fixtures/escape_sequence_files/t0012-VT.in rename to test/fixtures/escape_sequence_files/t0012-VT.in diff --git a/fixtures/escape_sequence_files/t0012-VT.text b/test/fixtures/escape_sequence_files/t0012-VT.text similarity index 100% rename from fixtures/escape_sequence_files/t0012-VT.text rename to test/fixtures/escape_sequence_files/t0012-VT.text diff --git a/fixtures/escape_sequence_files/t0013-FF.in b/test/fixtures/escape_sequence_files/t0013-FF.in similarity index 100% rename from fixtures/escape_sequence_files/t0013-FF.in rename to test/fixtures/escape_sequence_files/t0013-FF.in diff --git a/fixtures/escape_sequence_files/t0013-FF.text b/test/fixtures/escape_sequence_files/t0013-FF.text similarity index 100% rename from fixtures/escape_sequence_files/t0013-FF.text rename to test/fixtures/escape_sequence_files/t0013-FF.text diff --git a/fixtures/escape_sequence_files/t0014-CAN.in b/test/fixtures/escape_sequence_files/t0014-CAN.in similarity index 100% rename from fixtures/escape_sequence_files/t0014-CAN.in rename to test/fixtures/escape_sequence_files/t0014-CAN.in diff --git a/fixtures/escape_sequence_files/t0014-CAN.text b/test/fixtures/escape_sequence_files/t0014-CAN.text similarity index 100% rename from fixtures/escape_sequence_files/t0014-CAN.text rename to test/fixtures/escape_sequence_files/t0014-CAN.text diff --git a/fixtures/escape_sequence_files/t0015-SUB.in b/test/fixtures/escape_sequence_files/t0015-SUB.in similarity index 100% rename from fixtures/escape_sequence_files/t0015-SUB.in rename to test/fixtures/escape_sequence_files/t0015-SUB.in diff --git a/fixtures/escape_sequence_files/t0015-SUB.text b/test/fixtures/escape_sequence_files/t0015-SUB.text similarity index 100% rename from fixtures/escape_sequence_files/t0015-SUB.text rename to test/fixtures/escape_sequence_files/t0015-SUB.text diff --git a/fixtures/escape_sequence_files/t0016-SU.in b/test/fixtures/escape_sequence_files/t0016-SU.in similarity index 100% rename from fixtures/escape_sequence_files/t0016-SU.in rename to test/fixtures/escape_sequence_files/t0016-SU.in diff --git a/fixtures/escape_sequence_files/t0016-SU.text b/test/fixtures/escape_sequence_files/t0016-SU.text similarity index 100% rename from fixtures/escape_sequence_files/t0016-SU.text rename to test/fixtures/escape_sequence_files/t0016-SU.text diff --git a/fixtures/escape_sequence_files/t0017-SD.in b/test/fixtures/escape_sequence_files/t0017-SD.in similarity index 100% rename from fixtures/escape_sequence_files/t0017-SD.in rename to test/fixtures/escape_sequence_files/t0017-SD.in diff --git a/fixtures/escape_sequence_files/t0017-SD.text b/test/fixtures/escape_sequence_files/t0017-SD.text similarity index 100% rename from fixtures/escape_sequence_files/t0017-SD.text rename to test/fixtures/escape_sequence_files/t0017-SD.text diff --git a/fixtures/escape_sequence_files/t0020-CUF.in b/test/fixtures/escape_sequence_files/t0020-CUF.in similarity index 100% rename from fixtures/escape_sequence_files/t0020-CUF.in rename to test/fixtures/escape_sequence_files/t0020-CUF.in diff --git a/fixtures/escape_sequence_files/t0020-CUF.text b/test/fixtures/escape_sequence_files/t0020-CUF.text similarity index 100% rename from fixtures/escape_sequence_files/t0020-CUF.text rename to test/fixtures/escape_sequence_files/t0020-CUF.text diff --git a/fixtures/escape_sequence_files/t0021-CUB.in b/test/fixtures/escape_sequence_files/t0021-CUB.in similarity index 100% rename from fixtures/escape_sequence_files/t0021-CUB.in rename to test/fixtures/escape_sequence_files/t0021-CUB.in diff --git a/fixtures/escape_sequence_files/t0021-CUB.text b/test/fixtures/escape_sequence_files/t0021-CUB.text similarity index 100% rename from fixtures/escape_sequence_files/t0021-CUB.text rename to test/fixtures/escape_sequence_files/t0021-CUB.text diff --git a/fixtures/escape_sequence_files/t0022-CUU.in b/test/fixtures/escape_sequence_files/t0022-CUU.in similarity index 100% rename from fixtures/escape_sequence_files/t0022-CUU.in rename to test/fixtures/escape_sequence_files/t0022-CUU.in diff --git a/fixtures/escape_sequence_files/t0022-CUU.text b/test/fixtures/escape_sequence_files/t0022-CUU.text similarity index 100% rename from fixtures/escape_sequence_files/t0022-CUU.text rename to test/fixtures/escape_sequence_files/t0022-CUU.text diff --git a/fixtures/escape_sequence_files/t0023-CUU_scroll.in b/test/fixtures/escape_sequence_files/t0023-CUU_scroll.in similarity index 100% rename from fixtures/escape_sequence_files/t0023-CUU_scroll.in rename to test/fixtures/escape_sequence_files/t0023-CUU_scroll.in diff --git a/fixtures/escape_sequence_files/t0023-CUU_scroll.text b/test/fixtures/escape_sequence_files/t0023-CUU_scroll.text similarity index 100% rename from fixtures/escape_sequence_files/t0023-CUU_scroll.text rename to test/fixtures/escape_sequence_files/t0023-CUU_scroll.text diff --git a/fixtures/escape_sequence_files/t0024-CUD.in b/test/fixtures/escape_sequence_files/t0024-CUD.in similarity index 100% rename from fixtures/escape_sequence_files/t0024-CUD.in rename to test/fixtures/escape_sequence_files/t0024-CUD.in diff --git a/fixtures/escape_sequence_files/t0024-CUD.text b/test/fixtures/escape_sequence_files/t0024-CUD.text similarity index 100% rename from fixtures/escape_sequence_files/t0024-CUD.text rename to test/fixtures/escape_sequence_files/t0024-CUD.text diff --git a/fixtures/escape_sequence_files/t0025-CUP.in b/test/fixtures/escape_sequence_files/t0025-CUP.in similarity index 100% rename from fixtures/escape_sequence_files/t0025-CUP.in rename to test/fixtures/escape_sequence_files/t0025-CUP.in diff --git a/fixtures/escape_sequence_files/t0025-CUP.text b/test/fixtures/escape_sequence_files/t0025-CUP.text similarity index 100% rename from fixtures/escape_sequence_files/t0025-CUP.text rename to test/fixtures/escape_sequence_files/t0025-CUP.text diff --git a/fixtures/escape_sequence_files/t0026-CNL.in b/test/fixtures/escape_sequence_files/t0026-CNL.in similarity index 100% rename from fixtures/escape_sequence_files/t0026-CNL.in rename to test/fixtures/escape_sequence_files/t0026-CNL.in diff --git a/fixtures/escape_sequence_files/t0026-CNL.text b/test/fixtures/escape_sequence_files/t0026-CNL.text similarity index 100% rename from fixtures/escape_sequence_files/t0026-CNL.text rename to test/fixtures/escape_sequence_files/t0026-CNL.text diff --git a/fixtures/escape_sequence_files/t0027-CPL.in b/test/fixtures/escape_sequence_files/t0027-CPL.in similarity index 100% rename from fixtures/escape_sequence_files/t0027-CPL.in rename to test/fixtures/escape_sequence_files/t0027-CPL.in diff --git a/fixtures/escape_sequence_files/t0027-CPL.text b/test/fixtures/escape_sequence_files/t0027-CPL.text similarity index 100% rename from fixtures/escape_sequence_files/t0027-CPL.text rename to test/fixtures/escape_sequence_files/t0027-CPL.text diff --git a/fixtures/escape_sequence_files/t0030-HPR.in b/test/fixtures/escape_sequence_files/t0030-HPR.in similarity index 100% rename from fixtures/escape_sequence_files/t0030-HPR.in rename to test/fixtures/escape_sequence_files/t0030-HPR.in diff --git a/fixtures/escape_sequence_files/t0030-HPR.text b/test/fixtures/escape_sequence_files/t0030-HPR.text similarity index 100% rename from fixtures/escape_sequence_files/t0030-HPR.text rename to test/fixtures/escape_sequence_files/t0030-HPR.text diff --git a/fixtures/escape_sequence_files/t0031-HPB.in_ b/test/fixtures/escape_sequence_files/t0031-HPB.in_ similarity index 100% rename from fixtures/escape_sequence_files/t0031-HPB.in_ rename to test/fixtures/escape_sequence_files/t0031-HPB.in_ diff --git a/fixtures/escape_sequence_files/t0031-HPB.text b/test/fixtures/escape_sequence_files/t0031-HPB.text similarity index 100% rename from fixtures/escape_sequence_files/t0031-HPB.text rename to test/fixtures/escape_sequence_files/t0031-HPB.text diff --git a/fixtures/escape_sequence_files/t0032-VPB.in b/test/fixtures/escape_sequence_files/t0032-VPB.in similarity index 100% rename from fixtures/escape_sequence_files/t0032-VPB.in rename to test/fixtures/escape_sequence_files/t0032-VPB.in diff --git a/fixtures/escape_sequence_files/t0032-VPB.text b/test/fixtures/escape_sequence_files/t0032-VPB.text similarity index 100% rename from fixtures/escape_sequence_files/t0032-VPB.text rename to test/fixtures/escape_sequence_files/t0032-VPB.text diff --git a/fixtures/escape_sequence_files/t0033-VPB_scroll.in b/test/fixtures/escape_sequence_files/t0033-VPB_scroll.in similarity index 100% rename from fixtures/escape_sequence_files/t0033-VPB_scroll.in rename to test/fixtures/escape_sequence_files/t0033-VPB_scroll.in diff --git a/fixtures/escape_sequence_files/t0033-VPB_scroll.text b/test/fixtures/escape_sequence_files/t0033-VPB_scroll.text similarity index 100% rename from fixtures/escape_sequence_files/t0033-VPB_scroll.text rename to test/fixtures/escape_sequence_files/t0033-VPB_scroll.text diff --git a/fixtures/escape_sequence_files/t0034-VPR.in b/test/fixtures/escape_sequence_files/t0034-VPR.in similarity index 100% rename from fixtures/escape_sequence_files/t0034-VPR.in rename to test/fixtures/escape_sequence_files/t0034-VPR.in diff --git a/fixtures/escape_sequence_files/t0034-VPR.text b/test/fixtures/escape_sequence_files/t0034-VPR.text similarity index 100% rename from fixtures/escape_sequence_files/t0034-VPR.text rename to test/fixtures/escape_sequence_files/t0034-VPR.text diff --git a/fixtures/escape_sequence_files/t0035-HVP.in b/test/fixtures/escape_sequence_files/t0035-HVP.in similarity index 100% rename from fixtures/escape_sequence_files/t0035-HVP.in rename to test/fixtures/escape_sequence_files/t0035-HVP.in diff --git a/fixtures/escape_sequence_files/t0035-HVP.text b/test/fixtures/escape_sequence_files/t0035-HVP.text similarity index 100% rename from fixtures/escape_sequence_files/t0035-HVP.text rename to test/fixtures/escape_sequence_files/t0035-HVP.text diff --git a/fixtures/escape_sequence_files/t0040-REP.in b/test/fixtures/escape_sequence_files/t0040-REP.in similarity index 100% rename from fixtures/escape_sequence_files/t0040-REP.in rename to test/fixtures/escape_sequence_files/t0040-REP.in diff --git a/fixtures/escape_sequence_files/t0040-REP.text b/test/fixtures/escape_sequence_files/t0040-REP.text similarity index 100% rename from fixtures/escape_sequence_files/t0040-REP.text rename to test/fixtures/escape_sequence_files/t0040-REP.text diff --git a/fixtures/escape_sequence_files/t0050-ICH.in b/test/fixtures/escape_sequence_files/t0050-ICH.in similarity index 100% rename from fixtures/escape_sequence_files/t0050-ICH.in rename to test/fixtures/escape_sequence_files/t0050-ICH.in diff --git a/fixtures/escape_sequence_files/t0050-ICH.text b/test/fixtures/escape_sequence_files/t0050-ICH.text similarity index 100% rename from fixtures/escape_sequence_files/t0050-ICH.text rename to test/fixtures/escape_sequence_files/t0050-ICH.text diff --git a/fixtures/escape_sequence_files/t0051-IL.in b/test/fixtures/escape_sequence_files/t0051-IL.in similarity index 100% rename from fixtures/escape_sequence_files/t0051-IL.in rename to test/fixtures/escape_sequence_files/t0051-IL.in diff --git a/fixtures/escape_sequence_files/t0051-IL.text b/test/fixtures/escape_sequence_files/t0051-IL.text similarity index 100% rename from fixtures/escape_sequence_files/t0051-IL.text rename to test/fixtures/escape_sequence_files/t0051-IL.text diff --git a/fixtures/escape_sequence_files/t0052-DL.in b/test/fixtures/escape_sequence_files/t0052-DL.in similarity index 100% rename from fixtures/escape_sequence_files/t0052-DL.in rename to test/fixtures/escape_sequence_files/t0052-DL.in diff --git a/fixtures/escape_sequence_files/t0052-DL.text b/test/fixtures/escape_sequence_files/t0052-DL.text similarity index 100% rename from fixtures/escape_sequence_files/t0052-DL.text rename to test/fixtures/escape_sequence_files/t0052-DL.text diff --git a/fixtures/escape_sequence_files/t0053-DCH.in b/test/fixtures/escape_sequence_files/t0053-DCH.in similarity index 100% rename from fixtures/escape_sequence_files/t0053-DCH.in rename to test/fixtures/escape_sequence_files/t0053-DCH.in diff --git a/fixtures/escape_sequence_files/t0053-DCH.text b/test/fixtures/escape_sequence_files/t0053-DCH.text similarity index 100% rename from fixtures/escape_sequence_files/t0053-DCH.text rename to test/fixtures/escape_sequence_files/t0053-DCH.text diff --git a/fixtures/escape_sequence_files/t0054-ECH.in b/test/fixtures/escape_sequence_files/t0054-ECH.in similarity index 100% rename from fixtures/escape_sequence_files/t0054-ECH.in rename to test/fixtures/escape_sequence_files/t0054-ECH.in diff --git a/fixtures/escape_sequence_files/t0054-ECH.text b/test/fixtures/escape_sequence_files/t0054-ECH.text similarity index 100% rename from fixtures/escape_sequence_files/t0054-ECH.text rename to test/fixtures/escape_sequence_files/t0054-ECH.text diff --git a/fixtures/escape_sequence_files/t0055-EL.in b/test/fixtures/escape_sequence_files/t0055-EL.in similarity index 100% rename from fixtures/escape_sequence_files/t0055-EL.in rename to test/fixtures/escape_sequence_files/t0055-EL.in diff --git a/fixtures/escape_sequence_files/t0055-EL.text b/test/fixtures/escape_sequence_files/t0055-EL.text similarity index 100% rename from fixtures/escape_sequence_files/t0055-EL.text rename to test/fixtures/escape_sequence_files/t0055-EL.text diff --git a/fixtures/escape_sequence_files/t0056-ED.in b/test/fixtures/escape_sequence_files/t0056-ED.in similarity index 100% rename from fixtures/escape_sequence_files/t0056-ED.in rename to test/fixtures/escape_sequence_files/t0056-ED.in diff --git a/fixtures/escape_sequence_files/t0056-ED.text b/test/fixtures/escape_sequence_files/t0056-ED.text similarity index 100% rename from fixtures/escape_sequence_files/t0056-ED.text rename to test/fixtures/escape_sequence_files/t0056-ED.text diff --git a/fixtures/escape_sequence_files/t0057-ED3.in b/test/fixtures/escape_sequence_files/t0057-ED3.in similarity index 100% rename from fixtures/escape_sequence_files/t0057-ED3.in rename to test/fixtures/escape_sequence_files/t0057-ED3.in diff --git a/fixtures/escape_sequence_files/t0057-ED3.note b/test/fixtures/escape_sequence_files/t0057-ED3.note similarity index 100% rename from fixtures/escape_sequence_files/t0057-ED3.note rename to test/fixtures/escape_sequence_files/t0057-ED3.note diff --git a/fixtures/escape_sequence_files/t0057-ED3.text b/test/fixtures/escape_sequence_files/t0057-ED3.text similarity index 100% rename from fixtures/escape_sequence_files/t0057-ED3.text rename to test/fixtures/escape_sequence_files/t0057-ED3.text diff --git a/fixtures/escape_sequence_files/t0060-DECSC.in b/test/fixtures/escape_sequence_files/t0060-DECSC.in similarity index 100% rename from fixtures/escape_sequence_files/t0060-DECSC.in rename to test/fixtures/escape_sequence_files/t0060-DECSC.in diff --git a/fixtures/escape_sequence_files/t0060-DECSC.text b/test/fixtures/escape_sequence_files/t0060-DECSC.text similarity index 100% rename from fixtures/escape_sequence_files/t0060-DECSC.text rename to test/fixtures/escape_sequence_files/t0060-DECSC.text diff --git a/fixtures/escape_sequence_files/t0061-CSI_s.in b/test/fixtures/escape_sequence_files/t0061-CSI_s.in similarity index 100% rename from fixtures/escape_sequence_files/t0061-CSI_s.in rename to test/fixtures/escape_sequence_files/t0061-CSI_s.in diff --git a/fixtures/escape_sequence_files/t0061-CSI_s.text b/test/fixtures/escape_sequence_files/t0061-CSI_s.text similarity index 100% rename from fixtures/escape_sequence_files/t0061-CSI_s.text rename to test/fixtures/escape_sequence_files/t0061-CSI_s.text diff --git a/fixtures/escape_sequence_files/t0070-DECSTBM_LF.in b/test/fixtures/escape_sequence_files/t0070-DECSTBM_LF.in similarity index 100% rename from fixtures/escape_sequence_files/t0070-DECSTBM_LF.in rename to test/fixtures/escape_sequence_files/t0070-DECSTBM_LF.in diff --git a/fixtures/escape_sequence_files/t0070-DECSTBM_LF.text b/test/fixtures/escape_sequence_files/t0070-DECSTBM_LF.text similarity index 100% rename from fixtures/escape_sequence_files/t0070-DECSTBM_LF.text rename to test/fixtures/escape_sequence_files/t0070-DECSTBM_LF.text diff --git a/fixtures/escape_sequence_files/t0071-DECSTBM_IND.in b/test/fixtures/escape_sequence_files/t0071-DECSTBM_IND.in similarity index 100% rename from fixtures/escape_sequence_files/t0071-DECSTBM_IND.in rename to test/fixtures/escape_sequence_files/t0071-DECSTBM_IND.in diff --git a/fixtures/escape_sequence_files/t0071-DECSTBM_IND.text b/test/fixtures/escape_sequence_files/t0071-DECSTBM_IND.text similarity index 100% rename from fixtures/escape_sequence_files/t0071-DECSTBM_IND.text rename to test/fixtures/escape_sequence_files/t0071-DECSTBM_IND.text diff --git a/fixtures/escape_sequence_files/t0072-DECSTBM_NEL.in b/test/fixtures/escape_sequence_files/t0072-DECSTBM_NEL.in similarity index 100% rename from fixtures/escape_sequence_files/t0072-DECSTBM_NEL.in rename to test/fixtures/escape_sequence_files/t0072-DECSTBM_NEL.in diff --git a/fixtures/escape_sequence_files/t0072-DECSTBM_NEL.text b/test/fixtures/escape_sequence_files/t0072-DECSTBM_NEL.text similarity index 100% rename from fixtures/escape_sequence_files/t0072-DECSTBM_NEL.text rename to test/fixtures/escape_sequence_files/t0072-DECSTBM_NEL.text diff --git a/fixtures/escape_sequence_files/t0073-DECSTBM_RI.in b/test/fixtures/escape_sequence_files/t0073-DECSTBM_RI.in similarity index 100% rename from fixtures/escape_sequence_files/t0073-DECSTBM_RI.in rename to test/fixtures/escape_sequence_files/t0073-DECSTBM_RI.in diff --git a/fixtures/escape_sequence_files/t0073-DECSTBM_RI.text b/test/fixtures/escape_sequence_files/t0073-DECSTBM_RI.text similarity index 100% rename from fixtures/escape_sequence_files/t0073-DECSTBM_RI.text rename to test/fixtures/escape_sequence_files/t0073-DECSTBM_RI.text diff --git a/fixtures/escape_sequence_files/t0074-DECSTBM_SU_SD.in b/test/fixtures/escape_sequence_files/t0074-DECSTBM_SU_SD.in similarity index 100% rename from fixtures/escape_sequence_files/t0074-DECSTBM_SU_SD.in rename to test/fixtures/escape_sequence_files/t0074-DECSTBM_SU_SD.in diff --git a/fixtures/escape_sequence_files/t0074-DECSTBM_SU_SD.text b/test/fixtures/escape_sequence_files/t0074-DECSTBM_SU_SD.text similarity index 100% rename from fixtures/escape_sequence_files/t0074-DECSTBM_SU_SD.text rename to test/fixtures/escape_sequence_files/t0074-DECSTBM_SU_SD.text diff --git a/fixtures/escape_sequence_files/t0075-DECSTBM_CUU_CUD.in b/test/fixtures/escape_sequence_files/t0075-DECSTBM_CUU_CUD.in similarity index 100% rename from fixtures/escape_sequence_files/t0075-DECSTBM_CUU_CUD.in rename to test/fixtures/escape_sequence_files/t0075-DECSTBM_CUU_CUD.in diff --git a/fixtures/escape_sequence_files/t0075-DECSTBM_CUU_CUD.text b/test/fixtures/escape_sequence_files/t0075-DECSTBM_CUU_CUD.text similarity index 100% rename from fixtures/escape_sequence_files/t0075-DECSTBM_CUU_CUD.text rename to test/fixtures/escape_sequence_files/t0075-DECSTBM_CUU_CUD.text diff --git a/fixtures/escape_sequence_files/t0076-DECSTBM_IL_DL.in b/test/fixtures/escape_sequence_files/t0076-DECSTBM_IL_DL.in similarity index 100% rename from fixtures/escape_sequence_files/t0076-DECSTBM_IL_DL.in rename to test/fixtures/escape_sequence_files/t0076-DECSTBM_IL_DL.in diff --git a/fixtures/escape_sequence_files/t0076-DECSTBM_IL_DL.text b/test/fixtures/escape_sequence_files/t0076-DECSTBM_IL_DL.text similarity index 100% rename from fixtures/escape_sequence_files/t0076-DECSTBM_IL_DL.text rename to test/fixtures/escape_sequence_files/t0076-DECSTBM_IL_DL.text diff --git a/fixtures/escape_sequence_files/t0077-DECSTBM_quirks.in b/test/fixtures/escape_sequence_files/t0077-DECSTBM_quirks.in similarity index 100% rename from fixtures/escape_sequence_files/t0077-DECSTBM_quirks.in rename to test/fixtures/escape_sequence_files/t0077-DECSTBM_quirks.in diff --git a/fixtures/escape_sequence_files/t0077-DECSTBM_quirks.text b/test/fixtures/escape_sequence_files/t0077-DECSTBM_quirks.text similarity index 100% rename from fixtures/escape_sequence_files/t0077-DECSTBM_quirks.text rename to test/fixtures/escape_sequence_files/t0077-DECSTBM_quirks.text diff --git a/fixtures/escape_sequence_files/t0078-DECSTBM_CPL_CNL.in b/test/fixtures/escape_sequence_files/t0078-DECSTBM_CPL_CNL.in similarity index 100% rename from fixtures/escape_sequence_files/t0078-DECSTBM_CPL_CNL.in rename to test/fixtures/escape_sequence_files/t0078-DECSTBM_CPL_CNL.in diff --git a/fixtures/escape_sequence_files/t0078-DECSTBM_CPL_CNL.text b/test/fixtures/escape_sequence_files/t0078-DECSTBM_CPL_CNL.text similarity index 100% rename from fixtures/escape_sequence_files/t0078-DECSTBM_CPL_CNL.text rename to test/fixtures/escape_sequence_files/t0078-DECSTBM_CPL_CNL.text diff --git a/fixtures/escape_sequence_files/t0079-DECSTBM_VPR.in b/test/fixtures/escape_sequence_files/t0079-DECSTBM_VPR.in similarity index 100% rename from fixtures/escape_sequence_files/t0079-DECSTBM_VPR.in rename to test/fixtures/escape_sequence_files/t0079-DECSTBM_VPR.in diff --git a/fixtures/escape_sequence_files/t0079-DECSTBM_VPR.text b/test/fixtures/escape_sequence_files/t0079-DECSTBM_VPR.text similarity index 100% rename from fixtures/escape_sequence_files/t0079-DECSTBM_VPR.text rename to test/fixtures/escape_sequence_files/t0079-DECSTBM_VPR.text diff --git a/fixtures/escape_sequence_files/t0080-HT.in b/test/fixtures/escape_sequence_files/t0080-HT.in similarity index 100% rename from fixtures/escape_sequence_files/t0080-HT.in rename to test/fixtures/escape_sequence_files/t0080-HT.in diff --git a/fixtures/escape_sequence_files/t0080-HT.text b/test/fixtures/escape_sequence_files/t0080-HT.text similarity index 100% rename from fixtures/escape_sequence_files/t0080-HT.text rename to test/fixtures/escape_sequence_files/t0080-HT.text diff --git a/fixtures/escape_sequence_files/t0081-TBC.in b/test/fixtures/escape_sequence_files/t0081-TBC.in similarity index 100% rename from fixtures/escape_sequence_files/t0081-TBC.in rename to test/fixtures/escape_sequence_files/t0081-TBC.in diff --git a/fixtures/escape_sequence_files/t0081-TBC.text b/test/fixtures/escape_sequence_files/t0081-TBC.text similarity index 100% rename from fixtures/escape_sequence_files/t0081-TBC.text rename to test/fixtures/escape_sequence_files/t0081-TBC.text diff --git a/fixtures/escape_sequence_files/t0082-HTS.in b/test/fixtures/escape_sequence_files/t0082-HTS.in similarity index 100% rename from fixtures/escape_sequence_files/t0082-HTS.in rename to test/fixtures/escape_sequence_files/t0082-HTS.in diff --git a/fixtures/escape_sequence_files/t0082-HTS.text b/test/fixtures/escape_sequence_files/t0082-HTS.text similarity index 100% rename from fixtures/escape_sequence_files/t0082-HTS.text rename to test/fixtures/escape_sequence_files/t0082-HTS.text diff --git a/fixtures/escape_sequence_files/t0083-CHT.in b/test/fixtures/escape_sequence_files/t0083-CHT.in similarity index 100% rename from fixtures/escape_sequence_files/t0083-CHT.in rename to test/fixtures/escape_sequence_files/t0083-CHT.in diff --git a/fixtures/escape_sequence_files/t0083-CHT.text b/test/fixtures/escape_sequence_files/t0083-CHT.text similarity index 100% rename from fixtures/escape_sequence_files/t0083-CHT.text rename to test/fixtures/escape_sequence_files/t0083-CHT.text diff --git a/fixtures/escape_sequence_files/t0084-CBT.in b/test/fixtures/escape_sequence_files/t0084-CBT.in similarity index 100% rename from fixtures/escape_sequence_files/t0084-CBT.in rename to test/fixtures/escape_sequence_files/t0084-CBT.in diff --git a/fixtures/escape_sequence_files/t0084-CBT.text b/test/fixtures/escape_sequence_files/t0084-CBT.text similarity index 100% rename from fixtures/escape_sequence_files/t0084-CBT.text rename to test/fixtures/escape_sequence_files/t0084-CBT.text diff --git a/fixtures/escape_sequence_files/t0084-CBT.text-xterm b/test/fixtures/escape_sequence_files/t0084-CBT.text-xterm similarity index 100% rename from fixtures/escape_sequence_files/t0084-CBT.text-xterm rename to test/fixtures/escape_sequence_files/t0084-CBT.text-xterm diff --git a/fixtures/escape_sequence_files/t0090-alt_screen.in b/test/fixtures/escape_sequence_files/t0090-alt_screen.in similarity index 100% rename from fixtures/escape_sequence_files/t0090-alt_screen.in rename to test/fixtures/escape_sequence_files/t0090-alt_screen.in diff --git a/fixtures/escape_sequence_files/t0090-alt_screen.text b/test/fixtures/escape_sequence_files/t0090-alt_screen.text similarity index 100% rename from fixtures/escape_sequence_files/t0090-alt_screen.text rename to test/fixtures/escape_sequence_files/t0090-alt_screen.text diff --git a/fixtures/escape_sequence_files/t0091-alt_screen_ED3.in b/test/fixtures/escape_sequence_files/t0091-alt_screen_ED3.in similarity index 100% rename from fixtures/escape_sequence_files/t0091-alt_screen_ED3.in rename to test/fixtures/escape_sequence_files/t0091-alt_screen_ED3.in diff --git a/fixtures/escape_sequence_files/t0091-alt_screen_ED3.text b/test/fixtures/escape_sequence_files/t0091-alt_screen_ED3.text similarity index 100% rename from fixtures/escape_sequence_files/t0091-alt_screen_ED3.text rename to test/fixtures/escape_sequence_files/t0091-alt_screen_ED3.text diff --git a/fixtures/escape_sequence_files/t0092-alt_screen_DECSC.in b/test/fixtures/escape_sequence_files/t0092-alt_screen_DECSC.in similarity index 100% rename from fixtures/escape_sequence_files/t0092-alt_screen_DECSC.in rename to test/fixtures/escape_sequence_files/t0092-alt_screen_DECSC.in diff --git a/fixtures/escape_sequence_files/t0092-alt_screen_DECSC.text b/test/fixtures/escape_sequence_files/t0092-alt_screen_DECSC.text similarity index 100% rename from fixtures/escape_sequence_files/t0092-alt_screen_DECSC.text rename to test/fixtures/escape_sequence_files/t0092-alt_screen_DECSC.text diff --git a/fixtures/escape_sequence_files/t0100-IRM.in b/test/fixtures/escape_sequence_files/t0100-IRM.in similarity index 100% rename from fixtures/escape_sequence_files/t0100-IRM.in rename to test/fixtures/escape_sequence_files/t0100-IRM.in diff --git a/fixtures/escape_sequence_files/t0100-IRM.text b/test/fixtures/escape_sequence_files/t0100-IRM.text similarity index 100% rename from fixtures/escape_sequence_files/t0100-IRM.text rename to test/fixtures/escape_sequence_files/t0100-IRM.text diff --git a/fixtures/escape_sequence_files/t0101-NLM.in b/test/fixtures/escape_sequence_files/t0101-NLM.in similarity index 100% rename from fixtures/escape_sequence_files/t0101-NLM.in rename to test/fixtures/escape_sequence_files/t0101-NLM.in diff --git a/fixtures/escape_sequence_files/t0101-NLM.text b/test/fixtures/escape_sequence_files/t0101-NLM.text similarity index 100% rename from fixtures/escape_sequence_files/t0101-NLM.text rename to test/fixtures/escape_sequence_files/t0101-NLM.text diff --git a/fixtures/escape_sequence_files/t0102-DECAWM.in b/test/fixtures/escape_sequence_files/t0102-DECAWM.in similarity index 100% rename from fixtures/escape_sequence_files/t0102-DECAWM.in rename to test/fixtures/escape_sequence_files/t0102-DECAWM.in diff --git a/fixtures/escape_sequence_files/t0102-DECAWM.text b/test/fixtures/escape_sequence_files/t0102-DECAWM.text similarity index 100% rename from fixtures/escape_sequence_files/t0102-DECAWM.text rename to test/fixtures/escape_sequence_files/t0102-DECAWM.text diff --git a/fixtures/escape_sequence_files/t0103-reverse_wrap.in b/test/fixtures/escape_sequence_files/t0103-reverse_wrap.in similarity index 100% rename from fixtures/escape_sequence_files/t0103-reverse_wrap.in rename to test/fixtures/escape_sequence_files/t0103-reverse_wrap.in diff --git a/fixtures/escape_sequence_files/t0103-reverse_wrap.text b/test/fixtures/escape_sequence_files/t0103-reverse_wrap.text similarity index 100% rename from fixtures/escape_sequence_files/t0103-reverse_wrap.text rename to test/fixtures/escape_sequence_files/t0103-reverse_wrap.text diff --git a/fixtures/escape_sequence_files/t0200-SGR.html b/test/fixtures/escape_sequence_files/t0200-SGR.html similarity index 100% rename from fixtures/escape_sequence_files/t0200-SGR.html rename to test/fixtures/escape_sequence_files/t0200-SGR.html diff --git a/fixtures/escape_sequence_files/t0200-SGR.in_ b/test/fixtures/escape_sequence_files/t0200-SGR.in_ similarity index 100% rename from fixtures/escape_sequence_files/t0200-SGR.in_ rename to test/fixtures/escape_sequence_files/t0200-SGR.in_ diff --git a/fixtures/escape_sequence_files/t0220-SGR_inverse.html b/test/fixtures/escape_sequence_files/t0220-SGR_inverse.html similarity index 100% rename from fixtures/escape_sequence_files/t0220-SGR_inverse.html rename to test/fixtures/escape_sequence_files/t0220-SGR_inverse.html diff --git a/fixtures/escape_sequence_files/t0220-SGR_inverse.in_ b/test/fixtures/escape_sequence_files/t0220-SGR_inverse.in_ similarity index 100% rename from fixtures/escape_sequence_files/t0220-SGR_inverse.in_ rename to test/fixtures/escape_sequence_files/t0220-SGR_inverse.in_ diff --git a/fixtures/escape_sequence_files/t0300-vttest1.in b/test/fixtures/escape_sequence_files/t0300-vttest1.in similarity index 100% rename from fixtures/escape_sequence_files/t0300-vttest1.in rename to test/fixtures/escape_sequence_files/t0300-vttest1.in diff --git a/fixtures/escape_sequence_files/t0300-vttest1.text b/test/fixtures/escape_sequence_files/t0300-vttest1.text similarity index 100% rename from fixtures/escape_sequence_files/t0300-vttest1.text rename to test/fixtures/escape_sequence_files/t0300-vttest1.text diff --git a/fixtures/escape_sequence_files/t0500-bash_long_line.in b/test/fixtures/escape_sequence_files/t0500-bash_long_line.in similarity index 100% rename from fixtures/escape_sequence_files/t0500-bash_long_line.in rename to test/fixtures/escape_sequence_files/t0500-bash_long_line.in diff --git a/fixtures/escape_sequence_files/t0500-bash_long_line.text b/test/fixtures/escape_sequence_files/t0500-bash_long_line.text similarity index 100% rename from fixtures/escape_sequence_files/t0500-bash_long_line.text rename to test/fixtures/escape_sequence_files/t0500-bash_long_line.text diff --git a/fixtures/escape_sequence_files/t0501-bash_ls.in b/test/fixtures/escape_sequence_files/t0501-bash_ls.in similarity index 100% rename from fixtures/escape_sequence_files/t0501-bash_ls.in rename to test/fixtures/escape_sequence_files/t0501-bash_ls.in diff --git a/fixtures/escape_sequence_files/t0501-bash_ls.text b/test/fixtures/escape_sequence_files/t0501-bash_ls.text similarity index 100% rename from fixtures/escape_sequence_files/t0501-bash_ls.text rename to test/fixtures/escape_sequence_files/t0501-bash_ls.text diff --git a/fixtures/escape_sequence_files/t0502-bash_ls_color.in b/test/fixtures/escape_sequence_files/t0502-bash_ls_color.in similarity index 100% rename from fixtures/escape_sequence_files/t0502-bash_ls_color.in rename to test/fixtures/escape_sequence_files/t0502-bash_ls_color.in diff --git a/fixtures/escape_sequence_files/t0502-bash_ls_color.text b/test/fixtures/escape_sequence_files/t0502-bash_ls_color.text similarity index 100% rename from fixtures/escape_sequence_files/t0502-bash_ls_color.text rename to test/fixtures/escape_sequence_files/t0502-bash_ls_color.text diff --git a/fixtures/escape_sequence_files/t0503-zsh_ls_color.in b/test/fixtures/escape_sequence_files/t0503-zsh_ls_color.in similarity index 100% rename from fixtures/escape_sequence_files/t0503-zsh_ls_color.in rename to test/fixtures/escape_sequence_files/t0503-zsh_ls_color.in diff --git a/fixtures/escape_sequence_files/t0503-zsh_ls_color.text b/test/fixtures/escape_sequence_files/t0503-zsh_ls_color.text similarity index 100% rename from fixtures/escape_sequence_files/t0503-zsh_ls_color.text rename to test/fixtures/escape_sequence_files/t0503-zsh_ls_color.text diff --git a/fixtures/escape_sequence_files/t0504-vim.in b/test/fixtures/escape_sequence_files/t0504-vim.in similarity index 100% rename from fixtures/escape_sequence_files/t0504-vim.in rename to test/fixtures/escape_sequence_files/t0504-vim.in diff --git a/fixtures/escape_sequence_files/t0504-vim.text b/test/fixtures/escape_sequence_files/t0504-vim.text similarity index 100% rename from fixtures/escape_sequence_files/t0504-vim.text rename to test/fixtures/escape_sequence_files/t0504-vim.text diff --git a/fixtures/escape_sequence_files/t600-DECSTBM_SR.in b/test/fixtures/escape_sequence_files/t600-DECSTBM_SR.in similarity index 100% rename from fixtures/escape_sequence_files/t600-DECSTBM_SR.in rename to test/fixtures/escape_sequence_files/t600-DECSTBM_SR.in diff --git a/fixtures/escape_sequence_files/t600-DECSTBM_SR.text b/test/fixtures/escape_sequence_files/t600-DECSTBM_SR.text similarity index 100% rename from fixtures/escape_sequence_files/t600-DECSTBM_SR.text rename to test/fixtures/escape_sequence_files/t600-DECSTBM_SR.text diff --git a/fixtures/escape_sequence_files/t601-DECSTBM_SL.in b/test/fixtures/escape_sequence_files/t601-DECSTBM_SL.in similarity index 100% rename from fixtures/escape_sequence_files/t601-DECSTBM_SL.in rename to test/fixtures/escape_sequence_files/t601-DECSTBM_SL.in diff --git a/fixtures/escape_sequence_files/t601-DECSTBM_SL.text b/test/fixtures/escape_sequence_files/t601-DECSTBM_SL.text similarity index 100% rename from fixtures/escape_sequence_files/t601-DECSTBM_SL.text rename to test/fixtures/escape_sequence_files/t601-DECSTBM_SL.text diff --git a/fixtures/escape_sequence_files/t602-DECSTBM_DECIC.in b/test/fixtures/escape_sequence_files/t602-DECSTBM_DECIC.in similarity index 100% rename from fixtures/escape_sequence_files/t602-DECSTBM_DECIC.in rename to test/fixtures/escape_sequence_files/t602-DECSTBM_DECIC.in diff --git a/fixtures/escape_sequence_files/t602-DECSTBM_DECIC.text b/test/fixtures/escape_sequence_files/t602-DECSTBM_DECIC.text similarity index 100% rename from fixtures/escape_sequence_files/t602-DECSTBM_DECIC.text rename to test/fixtures/escape_sequence_files/t602-DECSTBM_DECIC.text diff --git a/fixtures/escape_sequence_files/t603-DECSTBM_DECDC.in b/test/fixtures/escape_sequence_files/t603-DECSTBM_DECDC.in similarity index 100% rename from fixtures/escape_sequence_files/t603-DECSTBM_DECDC.in rename to test/fixtures/escape_sequence_files/t603-DECSTBM_DECDC.in diff --git a/fixtures/escape_sequence_files/t603-DECSTBM_DECDC.text b/test/fixtures/escape_sequence_files/t603-DECSTBM_DECDC.text similarity index 100% rename from fixtures/escape_sequence_files/t603-DECSTBM_DECDC.text rename to test/fixtures/escape_sequence_files/t603-DECSTBM_DECDC.text diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index db5c4c073..1983fd410 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -980,7 +980,7 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void }); test.describe('selectionInactiveBackground', async () => { - test('should render the the inactive selection when not focused', async () => { + test('should render the inactive selection when not focused', async () => { const theme: ITheme = { selectionBackground: '#FF000080', selectionInactiveBackground: '#0000FF80' diff --git a/test/playwright/Terminal.test.ts b/test/playwright/Terminal.test.ts index 2d1133cce..c6c93359e 100644 --- a/test/playwright/Terminal.test.ts +++ b/test/playwright/Terminal.test.ts @@ -5,7 +5,7 @@ import { test } from '@playwright/test'; import { deepStrictEqual, notStrictEqual, strictEqual } from 'assert'; import { ITestContext, createTestContext, openTerminal, pollFor, timeout } from './TestUtils'; -import { IRenderDimensions } from 'browser/renderer/shared/Types'; +import { IRenderDimensions } from '../../src/browser/renderer/shared/Types'; let ctx: ITestContext; test.beforeAll(async ({ browser }) => { diff --git a/test/playwright/TestUtils.ts b/test/playwright/TestUtils.ts index 8a76c8820..2a44c3592 100644 --- a/test/playwright/TestUtils.ts +++ b/test/playwright/TestUtils.ts @@ -5,9 +5,11 @@ import { Browser, JSHandle, Page } from '@playwright/test'; import { deepStrictEqual, strictEqual } from 'assert'; -import type { IRenderDimensions as IRenderDimensionsInternal } from 'browser/renderer/shared/Types'; -import type { IRenderService } from 'browser/services/Services'; -import type { ICoreTerminal, IDisposable, IMarker } from 'common/Types'; +import type { IRenderDimensions as IRenderDimensionsInternal } from '../../src/browser/renderer/shared/Types'; +import type { IRenderService } from '../../src/browser/services/Services'; +import type { IDisposable } from '../../src/common/Types'; +import type { IMarker } from '../../src/common/buffer/Types'; +import type { ICoreTerminal } from '../../src/common/CoreTerminal'; import * as playwright from '@playwright/test'; import { IBuffer, IBufferCell, IBufferLine, IBufferNamespace, IBufferRange, IDecoration, IDecorationOptions, IModes, IRenderDimensions, ITerminalInitOnlyOptions, ITerminalOptions, Terminal } from '@xterm/xterm'; diff --git a/test/playwright/tsconfig.json b/test/playwright/tsconfig.json index f1372e89f..0339896bc 100644 --- a/test/playwright/tsconfig.json +++ b/test/playwright/tsconfig.json @@ -16,17 +16,9 @@ "strict": true, "noImplicitAny": false, "declaration": true, - "moduleResolution": "node", - "paths": { - "browser/*": [ - "../../src/browser/*" - ], - "common/*": [ - "../../src/common/*" - ] - }, + "moduleResolution": "nodenext", "target": "ESNext", - "module": "commonjs", + "module": "nodenext", "composite": true }, "include": [ diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index d3b62346d..21e884ecb 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -136,6 +136,17 @@ declare module '@xterm/headless' { */ minimumContrastRatio?: number; + /** + * When enabled and the terminal is in mouse events mode, mouse click, drag, + * and move events are only sent to the underlying application when the alt + * key is held. The alt key is not included in the mouse reports sent to the + * application. Wheel events are not affected. This allows normal text + * selection by default while still supporting application mouse interaction + * and scrolling when holding alt. When enabled, this takes precedence over + * `macOptionClickForcesSelection`. + */ + mouseEventsRequireAlt?: boolean; + /** * Whether to reflow the line containing the cursor when the terminal is * resized. Defaults to false, because shells usually handle this @@ -825,12 +836,11 @@ declare module '@xterm/headless' { resize(columns: number, rows: number): void; /** - * Adds a marker to the normal buffer and returns it. If the alt buffer is - * active, undefined is returned. + * Adds a marker to the normal buffer and returns it. * @param cursorYOffset The y position offset of the marker from the cursor. * @returns The new marker or undefined. */ - registerMarker(cursorYOffset?: number): IMarker | undefined; + registerMarker(cursorYOffset?: number): IMarker; /* * Disposes of the terminal, detaching it from the DOM and removing any diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index d1ce877b9..c66a52e85 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -206,6 +206,17 @@ declare module '@xterm/xterm' { */ minimumContrastRatio?: number; + /** + * When enabled and the terminal is in mouse events mode, mouse click, drag, + * and move events are only sent to the underlying application when the alt + * key is held. The alt key is not included in the mouse reports sent to the + * application. Wheel events are not affected. This allows normal text + * selection by default while still supporting application mouse interaction + * and scrolling when holding alt. When enabled, this takes precedence over + * `macOptionClickForcesSelection`. + */ + mouseEventsRequireAlt?: boolean; + /** * Control various quirks features that are either non-standard or standard * in but generally rejected in modern terminals. diff --git a/webpack.config.headless.js b/webpack.config.headless.js index ed2856bd0..6f9f26d22 100644 --- a/webpack.config.headless.js +++ b/webpack.config.headless.js @@ -8,8 +8,7 @@ const path = require('path'); /** * This webpack config does a production build for xterm.js headless. It works by taking the output * from tsc (via `npm run watch` or `npm run prebuild`) which are put into `out/` and webpacks them - * into a production mode umd library module in `lib-headless/`. The aliases are used fix up the - * absolute paths output by tsc (because of `baseUrl` and `paths` in `tsconfig.json`. + * into a production mode umd library module in `lib-headless/`. * * @type {import('webpack').Configuration} */ @@ -29,11 +28,6 @@ const config = { resolve: { modules: ['./node_modules'], extensions: [ '.js' ], - alias: { - common: path.resolve('./out/common'), - headless: path.resolve('./out/headless'), - vs: path.resolve('./out/vs') - } }, output: { filename: 'xterm-headless.js', diff --git a/webpack.config.js b/webpack.config.js index 74acb30f8..22a41e3ca 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -10,8 +10,7 @@ const path = require('path'); /** * This webpack config does a production build for xterm.js. It works by taking the output from tsc * (via `npm run watch` or `npm run prebuild`) which are put into `out/` and webpacks them into a - * production mode umd library module in `lib/`. The aliases are used fix up the absolute paths - * output by tsc (because of `baseUrl` and `paths` in `tsconfig.json`. + * production mode umd library module in `lib/`. * * @type {import('webpack').Configuration} */ @@ -31,11 +30,6 @@ const config = { resolve: { modules: ['./node_modules'], extensions: [ '.js' ], - alias: { - common: path.resolve('./out/common'), - browser: path.resolve('./out/browser'), - vs: path.resolve('./out/vs'), - } }, output: { filename: 'xterm.js',