├── .nvmrc ├── .gitattributes ├── .npmrc ├── htmlhint ├── .npmrc ├── images │ ├── hero.png │ ├── icon.png │ ├── hover.png │ └── status-bar.png ├── .vscode │ ├── settings.json │ ├── tasks.json │ └── launch.json ├── LICENSE.md ├── tsconfig.json ├── commands.ts ├── .vscodeignore ├── package.json ├── CHANGELOG.md ├── README.md ├── extension.ts └── package-lock.json ├── .github ├── FUNDING.yml ├── CODEOWNERS ├── workflows │ ├── spellcheck.yml │ ├── test.yml │ ├── publish.yml │ ├── ossf-scorecard.yml │ ├── codeql-analysis.yml │ └── super-linter.yml ├── copilot-instructions.md └── dependabot.yml ├── htmlhint-server ├── src │ ├── typings-custom │ │ ├── thenable.d.ts │ │ └── htmlhint.d.ts │ └── tsconfig.json ├── .vscode │ ├── settings.json │ ├── tasks.json │ └── launch.json ├── package.json └── package-lock.json ├── .prettierignore ├── test ├── testNoConfigFile │ ├── test.html │ ├── markdown.md │ └── nonAlphaNumericAttributeNames.html ├── testConfigFile │ ├── A │ │ ├── test.html │ │ ├── B │ │ │ └── test.html │ │ └── .htmlhintrc │ ├── test.html │ └── .htmlhintrc ├── testWithProjectHtmlhint │ ├── test.htm │ ├── test.x │ ├── test.html │ ├── .vscode │ │ └── settings.json │ ├── nonAlphaNumericAttributeNames.html │ └── package.json ├── suite │ ├── sample.test.ts │ ├── index.ts │ └── htmlhint.test.ts ├── autofix │ ├── link-canonical-test.html │ ├── meta-description-test.html │ ├── button-test.html │ ├── tag-self-close-test.html │ ├── .htmlhintrc │ ├── alt-test.html │ ├── tag-no-obsolete-test.html │ ├── attr-value-no-duplication-test.html │ ├── attr-no-duplication-test.html │ ├── attr-whitespace-test.html │ ├── test-autofixes.html │ └── empty-tag-not-self-closed-test.html ├── runTest.ts └── tsconfig.json ├── .markdownlint.json ├── .gitignore ├── .vscode ├── extensions.json ├── settings.json ├── launch.json └── tasks.json ├── .editorconfig ├── .gemini └── config.yaml ├── .cspell.json ├── verify.sh ├── LICENSE.md ├── AGENTS.md ├── package.json ├── eslint.config.js └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry='https://registry.npmjs.org/' 2 | -------------------------------------------------------------------------------- /htmlhint/.npmrc: -------------------------------------------------------------------------------- 1 | fund = false 2 | registry = 'https://registry.npmjs.org/' 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: htmlhint 2 | ko_fi: coliff 3 | github: coliff 4 | -------------------------------------------------------------------------------- /htmlhint-server/src/typings-custom/thenable.d.ts: -------------------------------------------------------------------------------- 1 | interface Thenable extends PromiseLike {} 2 | -------------------------------------------------------------------------------- /htmlhint/images/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/htmlhint/vscode-htmlhint/HEAD/htmlhint/images/hero.png -------------------------------------------------------------------------------- /htmlhint/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/htmlhint/vscode-htmlhint/HEAD/htmlhint/images/icon.png -------------------------------------------------------------------------------- /htmlhint/images/hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/htmlhint/vscode-htmlhint/HEAD/htmlhint/images/hover.png -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cspell.json 2 | .vscode-test/ 3 | htmlhint/out/ 4 | htmlhint/server/ 5 | package-lock.json 6 | *.html 7 | -------------------------------------------------------------------------------- /htmlhint/images/status-bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/htmlhint/vscode-htmlhint/HEAD/htmlhint/images/status-bar.png -------------------------------------------------------------------------------- /htmlhint-server/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.trimTrailingWhitespace": true, 3 | "editor.insertSpaces": false 4 | } 5 | -------------------------------------------------------------------------------- /test/testNoConfigFile/test.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /test/testConfigFile/A/test.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /test/testWithProjectHtmlhint/test.htm: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /test/testWithProjectHtmlhint/test.x: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /test/testWithProjectHtmlhint/test.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "MD001": false, 3 | "MD013": false, 4 | "MD033": false, 5 | "MD034": false, 6 | "MD040": false, 7 | "MD041": false 8 | } 9 | -------------------------------------------------------------------------------- /test/testConfigFile/A/B/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /test/testWithProjectHtmlhint/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.x": "html" 4 | }, 5 | "htmlhint.documentSelector": ["html", "x"] 6 | } 7 | -------------------------------------------------------------------------------- /test/testNoConfigFile/markdown.md: -------------------------------------------------------------------------------- 1 | # Markdown Test 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | server 3 | node_modules 4 | 5 | .DS_Store 6 | *.vsix 7 | *.zip 8 | 9 | # TypeScript build info files 10 | .tsbuildinfo 11 | */.tsbuildinfo 12 | /.vscode-test 13 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # About CODEOWNERS - https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 2 | 3 | * @coliff 4 | -------------------------------------------------------------------------------- /test/suite/sample.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | 3 | describe("Sample Test Suite", () => { 4 | it("should pass a sample test", () => { 5 | assert.strictEqual(1 + 1, 2); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /test/testConfigFile/A/.htmlhintrc: -------------------------------------------------------------------------------- 1 | { 2 | "tagname-lowercase": true, 3 | "attr-lowercase": true, 4 | "attr-value-double-quotes": true, 5 | "doctype-first": true, 6 | "html-lang-require": true 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "editorconfig.editorconfig", 5 | "esbenp.prettier-vscode", 6 | "streetsidesoftware.code-spell-checker" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = 2 9 | indent_style = space 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | -------------------------------------------------------------------------------- /htmlhint/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "out": true, 4 | "bin": true 5 | }, 6 | "search.exclude": { 7 | "out": true, 8 | "bin": true 9 | }, 10 | "files.trimTrailingWhitespace": true 11 | } 12 | -------------------------------------------------------------------------------- /htmlhint/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "command": "npm", 4 | "type": "shell", 5 | "presentation": { 6 | "reveal": "silent" 7 | }, 8 | "isBackground": true, 9 | "problemMatcher": "$tsc-watch" 10 | } 11 | -------------------------------------------------------------------------------- /.gemini/config.yaml: -------------------------------------------------------------------------------- 1 | have_fun: false 2 | code_review: 3 | disable: false 4 | comment_severity_threshold: MEDIUM 5 | max_review_comments: -1 6 | pull_request_opened: 7 | help: false 8 | summary: false 9 | code_review: true 10 | -------------------------------------------------------------------------------- /htmlhint-server/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "command": "npm", 4 | "type": "shell", 5 | "presentation": { 6 | "reveal": "silent" 7 | }, 8 | "args": ["run", "watch"], 9 | "isBackground": true, 10 | "problemMatcher": "$tsc-watch" 11 | } 12 | -------------------------------------------------------------------------------- /test/testNoConfigFile/nonAlphaNumericAttributeNames.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | abc 5 |
6 | -------------------------------------------------------------------------------- /test/testConfigFile/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test Config File 6 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/testWithProjectHtmlhint/nonAlphaNumericAttributeNames.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | abc 5 |
6 | -------------------------------------------------------------------------------- /htmlhint-server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach", 6 | "type": "node", 7 | "request": "attach", 8 | "address": "localhost", 9 | "port": 6010, 10 | "sourceMaps": true, 11 | "outFiles": ["${workspaceRoot}/../htmlhint/server/**/*.js"] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/testWithProjectHtmlhint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-with-project-htmlhint", 3 | "version": "0.3.0", 4 | "description": "test project", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "htmlhint": "0.9.10" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/autofix/link-canonical-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Link Canonical Test 8 | 9 | 10 |

Link Canonical Test

11 | 12 | 13 | -------------------------------------------------------------------------------- /htmlhint/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch Extension", 6 | "type": "extensionHost", 7 | "request": "launch", 8 | "runtimeExecutable": "${execPath}", 9 | "args": ["--extensionDevelopmentPath=${workspaceRoot}"], 10 | "sourceMaps": true, 11 | "outFiles": ["${workspaceRoot}/out/*.js"], 12 | "preLaunchTask": "npm" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": "explicit" 4 | }, 5 | "editor.defaultFormatter": "EditorConfig.EditorConfig", 6 | "[javascript][typescript][json][jsonc][markdown][yaml]": { 7 | "editor.defaultFormatter": "esbenp.prettier-vscode", 8 | "editor.formatOnSave": true 9 | }, 10 | "editor.renderWhitespace": "all", 11 | "editor.trimAutoWhitespace": true, 12 | "files.trimTrailingWhitespace": true 13 | } 14 | -------------------------------------------------------------------------------- /test/autofix/meta-description-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Meta Description Test 8 | 9 | 10 |

Test Page 1

11 |

This page is missing a meta description tag.

12 | 13 | 14 | -------------------------------------------------------------------------------- /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "words": [ 4 | "autobuild", 5 | "codeql", 6 | "coliff", 7 | "dylib", 8 | "fnames", 9 | "htmlhint", 10 | "htmlhintrc", 11 | "mylang", 12 | "nvmrc", 13 | "ossf", 14 | "rollup", 15 | "ruleset", 16 | "sarif", 17 | "tagname", 18 | "tsparser", 19 | "vite", 20 | "VSIX", 21 | "ZIZMOR" 22 | ], 23 | "flagWords": [ 24 | "hte" 25 | ], 26 | "allowCompoundWords": true, 27 | "language": "en,en-US", 28 | "ignorePaths": [ 29 | ".cspell.json" 30 | ], 31 | "useGitignore": true 32 | } 33 | -------------------------------------------------------------------------------- /htmlhint-server/src/typings-custom/htmlhint.d.ts: -------------------------------------------------------------------------------- 1 | declare module "htmlhint" { 2 | // version >= 0.11.0 es6 3 | export default HTMLHint; 4 | 5 | // version < 0.11.0 6 | export var HTMLHint: Verifier | undefined; 7 | 8 | export interface Verifier { 9 | verify(text: string): Error[]; 10 | } 11 | 12 | export interface Error { 13 | type: string; 14 | message: string; 15 | raw: string; 16 | evidence: string; 17 | line: number; 18 | col: number; 19 | rule: Rule; 20 | } 21 | 22 | export interface Rule { 23 | id: string; 24 | description: string; 25 | link: string; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /htmlhint-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "htmlhint-server", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "HTMLHint Linter Server", 6 | "scripts": { 7 | "compile": "tsc -p ./src", 8 | "watch": "tsc --watch -p ./src" 9 | }, 10 | "dependencies": { 11 | "htmlhint": "^1.8.0", 12 | "strip-json-comments": "3.1.1", 13 | "vscode-languageserver": "^9.0.1", 14 | "vscode-languageserver-textdocument": "^1.0.12", 15 | "vscode-uri": "^3.1.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "22.15.31", 19 | "typescript": "5.5.4" 20 | }, 21 | "engines": { 22 | "node": "*" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/testConfigFile/.htmlhintrc: -------------------------------------------------------------------------------- 1 | { 2 | "alt-require": false, 3 | "attr-lowercase": true, 4 | "attr-no-duplication": true, 5 | "attr-value-double-quotes": true, 6 | "doctype-first": true, 7 | "empty-tag-not-self-closed": false, 8 | "frame-title-require": false, 9 | "h1-require": true, 10 | "html-lang-require": true, 11 | "id-unique": true, 12 | "input-requires-label": false, 13 | "main-require": true, 14 | "meta-charset-require": true, 15 | "meta-description-require": true, 16 | "meta-viewport-require": true, 17 | "script-disabled": false, 18 | "spec-char-escape": true, 19 | "src-not-empty": true, 20 | "tag-pair": true, 21 | "tagname-lowercase": true, 22 | "title-require": true 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/spellcheck.yml: -------------------------------------------------------------------------------- 1 | name: "Check spelling" 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | branches: [main] 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | spellcheck: 13 | runs-on: ubuntu-latest 14 | if: ${{ github.actor != 'dependabot[bot]' }} 15 | steps: 16 | - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 17 | with: 18 | persist-credentials: false 19 | 20 | - uses: streetsidesoftware/cspell-action@3294df585d3d639e30f3bc019cb11940b9866e95 # v8.0.0 21 | with: 22 | check_dot_files: false 23 | incremental_files_only: true 24 | inline: warning 25 | strict: false 26 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch Extension", 6 | "type": "extensionHost", 7 | "request": "launch", 8 | "args": ["--extensionDevelopmentPath=${workspaceFolder}/htmlhint"], 9 | "outFiles": ["${workspaceFolder}/htmlhint/out/**/*.js"] 10 | }, 11 | { 12 | "name": "Extension Tests", 13 | "type": "extensionHost", 14 | "request": "launch", 15 | "args": [ 16 | "--extensionDevelopmentPath=${workspaceFolder}/htmlhint", 17 | "--extensionTestsPath=${workspaceFolder}/htmlhint/out/test/suite/index" 18 | ], 19 | "outFiles": ["${workspaceFolder}/htmlhint/out/**/*.js"] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /verify.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Simple script to verify the extension builds and loads correctly 4 | 5 | echo "Installing dependencies..." 6 | cd "$(dirname "$0")" && npm install 7 | cd "$(dirname "$0")/htmlhint" && npm install 8 | cd "$(dirname "$0")/htmlhint-server" && npm install 9 | 10 | echo "Building extension..." 11 | cd "$(dirname "$0")/htmlhint-server" && npm run compile 12 | 13 | echo "Building server..." 14 | cd "$(dirname "$0")/htmlhint" && npm run compile 15 | 16 | echo "Build complete." 17 | echo "Extension is ready to be loaded in VS Code." 18 | echo "You can test it by opening VS Code and using the 'Developer: Install Extension from Location' command." 19 | echo "To package the extension, run 'npm run package' from the root directory." 20 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "${workspaceFolder}/htmlhint:npm: compile", 6 | "type": "npm", 7 | "script": "compile", 8 | "group": "build", 9 | "presentation": { 10 | "panel": "shared" 11 | }, 12 | "options": { 13 | "cwd": "${workspaceFolder}/htmlhint" 14 | }, 15 | "problemMatcher": "$tsc" 16 | }, 17 | { 18 | "label": "npm: compile (htmlhint-server)", 19 | "type": "npm", 20 | "script": "compile", 21 | "group": "build", 22 | "presentation": { 23 | "panel": "shared" 24 | }, 25 | "options": { 26 | "cwd": "${workspaceFolder}/htmlhint-server" 27 | }, 28 | "problemMatcher": "$tsc" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /.github/copilot-instructions.md: -------------------------------------------------------------------------------- 1 | # Copilot Instructions 2 | 3 | - This project is the HTMLHint Visual Studio Code extension. It is a linter for HTML files that helps developers write clean and error-free HTML code. The extension provides real-time feedback and suggestions for improving HTML code quality. 4 | - Code is linted with ESLint v8.57.1. 5 | - All code is formatted with Prettier. 6 | - All code and comments are in US English. 7 | - We use TypeScript v5.5.4. 8 | 9 | ## GitHub Actions 10 | 11 | - The GitHub Actions workflows should be placed in the .github/workflows directory. 12 | - The workflows should be named .yml. 13 | - All GitHub Actions should be pinned versions to avoid breaking changes (SHA-1). 14 | - If using actions/checkout, it should have persist-credentials: false set. 15 | -------------------------------------------------------------------------------- /test/autofix/button-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Button Type Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/autofix/tag-self-close-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tag Self-Close Test 8 | 9 | 10 | 11 | Test image 12 |
13 |
14 | 15 | 16 | 17 | 18 | 19 | Test image 2 20 |
21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/autofix/.htmlhintrc: -------------------------------------------------------------------------------- 1 | { 2 | "alt-require": true, 3 | "attr-lowercase": true, 4 | "attr-no-duplication": true, 5 | "attr-no-unnecessary-whitespace": true, 6 | "attr-value-double-quotes": true, 7 | "attr-value-no-duplication": true, 8 | "attr-whitespace": true, 9 | "button-type-require": true, 10 | "doctype-first": true, 11 | "doctype-html5": true, 12 | "empty-tag-not-self-closed": false, 13 | "html-lang-require": true, 14 | "id-unique": true, 15 | "link-rel-canonical-require": true, 16 | "meta-charset-require": true, 17 | "meta-description-require": true, 18 | "meta-viewport-require": true, 19 | "spec-char-escape": true, 20 | "src-not-empty": true, 21 | "tag-no-obsolete": true, 22 | "tag-pair": true, 23 | "tag-self-close": true, 24 | "tagname-lowercase": true, 25 | "title-require": true 26 | } 27 | -------------------------------------------------------------------------------- /test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { runTests } from "@vscode/test-electron"; 3 | 4 | async function main() { 5 | try { 6 | // The folder containing the Extension Manifest package.json 7 | // Passed to `--extensionDevelopmentPath` 8 | const extensionDevelopmentPath = path.resolve(__dirname, "../htmlhint"); 9 | 10 | // The path to the test runner 11 | // Passed to --extensionTestsPath 12 | const extensionTestsPath = path.resolve(__dirname, "./suite/index"); 13 | 14 | await runTests({ 15 | extensionDevelopmentPath, 16 | extensionTestsPath, 17 | launchArgs: [path.resolve(__dirname, "../test/testConfigFile")], 18 | version: "1.89.0", 19 | }); 20 | } catch (err) { 21 | console.error("Failed to run tests"); 22 | process.exit(1); 23 | } 24 | } 25 | 26 | main(); 27 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | labels: 8 | - github-actions 9 | groups: 10 | github-actions: 11 | patterns: 12 | - "*" 13 | open-pull-requests-limit: 2 14 | 15 | - package-ecosystem: npm 16 | directory: "/" 17 | schedule: 18 | interval: weekly 19 | versioning-strategy: increase 20 | open-pull-requests-limit: 1 21 | 22 | - package-ecosystem: npm 23 | directory: "/htmlhint" 24 | schedule: 25 | interval: weekly 26 | versioning-strategy: increase 27 | open-pull-requests-limit: 1 28 | 29 | - package-ecosystem: npm 30 | directory: "/htmlhint-server" 31 | schedule: 32 | interval: weekly 33 | versioning-strategy: increase 34 | open-pull-requests-limit: 1 35 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2022", 5 | "lib": ["ES2022", "DOM"], 6 | "moduleResolution": "node", 7 | "outDir": "out", 8 | "sourceMap": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "noImplicitReturns": true, 12 | "noImplicitThis": true, 13 | "strictNullChecks": true, 14 | "strictFunctionTypes": true, 15 | "strictBindCallApply": true, 16 | "alwaysStrict": true, 17 | "noUnusedLocals": false, 18 | "noUnusedParameters": false, 19 | "noFallthroughCasesInSwitch": true, 20 | "noUncheckedIndexedAccess": false, 21 | "esModuleInterop": true, 22 | "allowSyntheticDefaultImports": true, 23 | "resolveJsonModule": true, 24 | "forceConsistentCasingInFileNames": true, 25 | "types": ["node", "mocha"], 26 | "skipLibCheck": true 27 | }, 28 | "include": ["suite/**/*.ts", "runTest.ts"], 29 | "exclude": ["node_modules"] 30 | } 31 | -------------------------------------------------------------------------------- /test/autofix/alt-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Alt Attribute Test 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import Mocha from "mocha"; 3 | import * as glob from "glob"; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: "bdd", 9 | color: true, 10 | timeout: 10000, 11 | }); 12 | 13 | const testsRoot = path.resolve(__dirname, "..", "suite"); 14 | 15 | return new Promise((resolve, reject) => { 16 | glob 17 | .glob("**/*.test.js", { cwd: testsRoot }) 18 | .then((files: string[]) => { 19 | files.forEach((f: string) => mocha.addFile(path.resolve(testsRoot, f))); 20 | try { 21 | mocha.run((failures) => { 22 | if (failures > 0) { 23 | reject(new Error(`${failures} tests failed.`)); 24 | } else { 25 | resolve(); 26 | } 27 | }); 28 | } catch (err) { 29 | reject(err); 30 | } 31 | }) 32 | .catch((err: Error) => { 33 | reject(err); 34 | }); 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - "!dependabot/**" 8 | pull_request: 9 | workflow_dispatch: 10 | 11 | env: 12 | FORCE_COLOR: 2 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | run: 19 | name: Node ${{ matrix.node }} on ${{ matrix.os }} 20 | runs-on: ${{ matrix.os }} 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | node: [22] 26 | os: [ubuntu-latest] 27 | 28 | steps: 29 | - name: Clone repository 30 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 31 | with: 32 | persist-credentials: false 33 | 34 | - name: Set up Node.js 35 | uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 36 | with: 37 | node-version: ${{ matrix.node }} 38 | cache: npm 39 | 40 | - name: Install npm dependencies 41 | run: npm ci 42 | 43 | - name: Run tests 44 | run: npm test 45 | -------------------------------------------------------------------------------- /test/autofix/tag-no-obsolete-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tag No Obsolete Test 8 | 9 | 10 | 11 | HTML 12 | 13 | 14 |

This is an WWW example with URL.

15 | 16 | 17 | CSS 18 | 19 | 20 | JS 21 | 22 | 23 | XML 24 | 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2022 Microsoft 4 | Copyright (c) 2022-2025 HTMLHint 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /htmlhint/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2022 Microsoft 4 | Copyright (c) 2022-2025 HTMLHint 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "*" 5 | workflow_dispatch: 6 | 7 | name: Deploy Extension 8 | permissions: 9 | contents: read 10 | id-token: write 11 | 12 | jobs: 13 | deploy: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 17 | with: 18 | persist-credentials: false 19 | 20 | - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 21 | with: 22 | node-version: 22 23 | 24 | - run: npm ci 25 | 26 | - run: npm run build 27 | 28 | - run: npm run package 29 | 30 | - name: Publish to Open VSX Registry 31 | uses: HaaLeo/publish-vscode-extension@ca5561daa085dee804bf9f37fe0165785a9b14db # v2.0.0 32 | with: 33 | pat: ${{ secrets.OPEN_VSX_TOKEN }} 34 | 35 | - name: Publish to Visual Studio Marketplace 36 | uses: HaaLeo/publish-vscode-extension@ca5561daa085dee804bf9f37fe0165785a9b14db # v2.0.0 37 | with: 38 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 39 | registryUrl: https://marketplace.visualstudio.com 40 | -------------------------------------------------------------------------------- /htmlhint-server/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2022", 5 | "lib": ["ES2022"], 6 | "moduleResolution": "node", 7 | "outDir": "../../htmlhint/server", 8 | "sourceMap": true, 9 | "declaration": true, 10 | "declarationMap": true, 11 | "strict": true, 12 | "noImplicitAny": false, 13 | "noImplicitReturns": true, 14 | "noImplicitThis": true, 15 | "noImplicitOverride": true, 16 | "strictNullChecks": false, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": false, 20 | "alwaysStrict": true, 21 | "noUnusedLocals": false, 22 | "noUnusedParameters": false, 23 | "exactOptionalPropertyTypes": false, 24 | "noFallthroughCasesInSwitch": true, 25 | "noUncheckedIndexedAccess": false, 26 | "noPropertyAccessFromIndexSignature": false, 27 | "esModuleInterop": true, 28 | "allowSyntheticDefaultImports": true, 29 | "resolveJsonModule": true, 30 | "forceConsistentCasingInFileNames": true, 31 | "skipLibCheck": true, 32 | "incremental": true, 33 | "tsBuildInfoFile": ".tsbuildinfo" 34 | }, 35 | "include": ["**/*.ts"], 36 | "exclude": ["node_modules", "**/*.test.ts", "**/*.spec.ts"] 37 | } 38 | -------------------------------------------------------------------------------- /htmlhint/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2022", 5 | "lib": ["ES2022", "DOM"], 6 | "moduleResolution": "node", 7 | "outDir": "out", 8 | "sourceMap": true, 9 | "declaration": true, 10 | "declarationMap": true, 11 | "strict": true, 12 | "noImplicitAny": true, 13 | "noImplicitReturns": true, 14 | "noImplicitThis": true, 15 | "noImplicitOverride": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "strictBindCallApply": true, 19 | "strictPropertyInitialization": true, 20 | "alwaysStrict": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "exactOptionalPropertyTypes": true, 24 | "noFallthroughCasesInSwitch": true, 25 | "noUncheckedIndexedAccess": true, 26 | "noPropertyAccessFromIndexSignature": false, 27 | "esModuleInterop": true, 28 | "allowSyntheticDefaultImports": true, 29 | "resolveJsonModule": true, 30 | "forceConsistentCasingInFileNames": true, 31 | "skipLibCheck": true, 32 | "incremental": true, 33 | "tsBuildInfoFile": ".tsbuildinfo" 34 | }, 35 | "include": ["extension.ts", "**/*.ts"], 36 | "exclude": ["node_modules", "server", "out", "**/*.test.ts", "**/*.spec.ts"] 37 | } 38 | -------------------------------------------------------------------------------- /test/autofix/attr-value-no-duplication-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Attribute Value No Duplication Test 7 | 8 | 9 | 10 |
Button 1
11 | 12 | 13 |
Button 2
14 | 15 | 16 |
Button 3
17 | 18 | 19 |
Button 4
20 | 21 | 22 |
Button 5
23 | 24 | 25 |
Button 6
26 | 27 | 28 |
Button 7
29 | 30 | 31 |
Button 8
32 | 33 | 34 | -------------------------------------------------------------------------------- /AGENTS.md: -------------------------------------------------------------------------------- 1 | # Agents 2 | 3 | 4 | 5 | ## General Rules 6 | 7 | - Before declaring a task is complete, compile the extension to ensure it completes with no errors. 8 | - Never downgrade dependencies. 9 | - Newly added version/features for the Extension Changelog go at the top. 10 | - As a general rule: some rules, attributes, lists should be in alphabetical order. 11 | - Format everything (except HTML) with Prettier. 12 | 13 | ## Markdown Code Style 14 | 15 | - Format with Prettier. 16 | 17 | ## TypeScript Code Style 18 | 19 | - Format with Prettier. 20 | 21 | ## Communication (MANDATORY) 22 | 23 | - No apologies - State facts and solutions directly. 24 | - Concise style - Professional, avoid repetition and filler. 25 | - Single chunk edits - All file edits in one operation. 26 | - Real file links only - No placeholder files. 27 | - No unnecessary confirmations - Use available context. 28 | 29 | ## Quality & Validation (MANDATORY) 30 | 31 | - Never assume commands worked without verification. 32 | - 98%+ confidence threshold for definitive claims. 33 | - Immediate re-investigation when findings don't match expectations. 34 | - Cross-tool validation when tools fail. 35 | 36 | ## Code Standards (MANDATORY) 37 | 38 | - No emojis in code or documentation. 39 | - Only implement what's requested. 40 | - Preserve existing structures - Don't remove unrelated code. 41 | -------------------------------------------------------------------------------- /.github/workflows/ossf-scorecard.yml: -------------------------------------------------------------------------------- 1 | name: Scorecard supply-chain security 2 | on: 3 | branch_protection_rule: 4 | schedule: 5 | - cron: "27 12 * * 2" 6 | push: 7 | branches: ["main"] 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | analysis: 13 | name: Scorecard analysis 14 | runs-on: ubuntu-latest 15 | if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request' 16 | permissions: 17 | security-events: write 18 | id-token: write 19 | 20 | steps: 21 | - name: "Checkout code" 22 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 23 | with: 24 | persist-credentials: false 25 | 26 | - name: "Run analysis" 27 | uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 28 | with: 29 | results_file: results.sarif 30 | results_format: sarif 31 | publish_results: true 32 | 33 | - name: "Upload artifact" 34 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 35 | with: 36 | name: SARIF file 37 | path: results.sarif 38 | retention-days: 5 39 | 40 | - name: "Upload to code-scanning" 41 | uses: github/codeql-action/upload-sarif@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6 42 | with: 43 | sarif_file: results.sarif 44 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | pull_request: 7 | branches: ["main"] 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | analyze: 15 | name: Analyze 16 | runs-on: ubuntu-latest 17 | if: ${{ github.actor != 'dependabot[bot]' }} 18 | permissions: 19 | actions: read 20 | contents: read 21 | security-events: write 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | language: ["javascript-typescript"] 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 31 | with: 32 | persist-credentials: false 33 | 34 | - name: Initialize CodeQL 35 | uses: github/codeql-action/init@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6 36 | with: 37 | languages: ${{ matrix.language }} 38 | queries: +security-and-quality 39 | config: | 40 | paths-ignore: 41 | - test/* 42 | 43 | - name: Autobuild 44 | uses: github/codeql-action/autobuild@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6 45 | 46 | - name: Perform CodeQL Analysis 47 | uses: github/codeql-action/analyze@fe4161a26a8629af62121b670040955b330f9af2 # v4.31.6 48 | with: 49 | category: "/language:${{matrix.language}}" 50 | -------------------------------------------------------------------------------- /test/autofix/attr-no-duplication-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Attribute No Duplication Test 7 | 8 | 9 | 10 |
Button 1
11 | 12 | 13 |
Button 2
14 | 15 | 16 |
Button 3
17 | 18 | 19 |
Button 4
20 | 21 | 22 |
Button 5
23 | 24 | 25 |
Button 6
26 | 27 | 28 | 29 | 30 | 31 |
Button 8
32 | 33 | 34 | -------------------------------------------------------------------------------- /test/autofix/attr-whitespace-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Attribute Whitespace Test 7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 | 16 |
17 | 18 | 19 |
Button
20 | 21 | 22 |
23 | 24 | 25 |
Button
26 | 27 | 28 |
29 | 30 | 31 |
Content
32 | 33 | 34 |
Test
35 | 36 | 37 | -------------------------------------------------------------------------------- /.github/workflows/super-linter.yml: -------------------------------------------------------------------------------- 1 | name: "Super Linter" 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | permissions: 15 | contents: read 16 | statuses: write 17 | name: Lint Code Base 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout Code 22 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 23 | with: 24 | fetch-depth: 0 25 | persist-credentials: false 26 | 27 | - name: Lint Code Base 28 | uses: super-linter/super-linter/slim@502f4fe48a81a392756e173e39a861f8c8efe056 # v8.3.0 29 | env: 30 | DEFAULT_BRANCH: main 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | IGNORE_GITIGNORED_FILES: true 33 | LINTER_RULES_PATH: / 34 | LOG_LEVEL: NOTICE 35 | MARKDOWN_CONFIG_FILE: .markdownlint.json 36 | SUPPRESS_POSSUM: true 37 | VALIDATE_ALL_CODEBASE: false 38 | VALIDATE_BIOME_FORMAT: false 39 | VALIDATE_BIOME_LINT: false 40 | VALIDATE_EDITORCONFIG: false 41 | VALIDATE_GITHUB_ACTIONS_ZIZMOR: false 42 | VALIDATE_HTML: false 43 | VALIDATE_HTML_PRETTIER: false 44 | VALIDATE_JSCPD: false 45 | VALIDATE_JSON_PRETTIER: false 46 | VALIDATE_MARKDOWN_PRETTIER: false 47 | VALIDATE_NATURAL_LANGUAGE: false 48 | VALIDATE_TYPESCRIPT_ES: false 49 | VALIDATE_TYPESCRIPT_PRETTIER: false 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-htmlhint", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "VS Code extension to support HTMLHint, an HTML linter.", 6 | "homepage": "https://htmlhint.com", 7 | "bugs": { 8 | "url": "https://github.com/htmlhint/vscode-htmlhint/issues" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/htmlhint/vscode-htmlhint.git" 13 | }, 14 | "funding": "https://opencollective.com/htmlhint", 15 | "license": "MIT", 16 | "author": "HTMLHint", 17 | "scripts": { 18 | "build": "npm run compile", 19 | "lint": "eslint .", 20 | "lint:fix": "eslint . --fix", 21 | "prettier": "prettier --write \"**/*.{js,json,md,ts,yml}\"", 22 | "spellcheck": "npx cspell \"**/*.{html,js,json,md,ts,yml}\"", 23 | "postinstall": "cd htmlhint && npm i && cd ../htmlhint-server && npm i", 24 | "compile": "cd htmlhint-server && npm run compile && cd ../htmlhint && npm run compile", 25 | "compile:tests": "tsc -p ./test", 26 | "test": "npm run prettier && npm run lint && npm run compile && npm run compile:tests", 27 | "test-local": "node ./test/out/runTest.js", 28 | "package": "cd htmlhint && npm run vscode:prepublish && vsce package" 29 | }, 30 | "dependencies": { 31 | "vscode-languageclient": "^9.0.1" 32 | }, 33 | "devDependencies": { 34 | "@types/glob": "^8.1.0", 35 | "@types/mocha": "^10.0.10", 36 | "@types/node": "^22.19.1", 37 | "@types/vscode": "^1.101.0", 38 | "@typescript-eslint/eslint-plugin": "^8.17.0", 39 | "@typescript-eslint/parser": "^8.17.0", 40 | "@vscode/test-electron": "^2.5.2", 41 | "eslint": "^9.39.1", 42 | "eslint-config-prettier": "^10.1.8", 43 | "glob": "^13.0.0", 44 | "globals": "^16.5.0", 45 | "mocha": "^11.7.5", 46 | "prettier": "3.7.4", 47 | "ts-node": "^10.9.2", 48 | "typescript": "5.6.3" 49 | }, 50 | "engines": { 51 | "node": ">= 22" 52 | }, 53 | "volta": { 54 | "node": "22.19.0" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/suite/htmlhint.test.ts: -------------------------------------------------------------------------------- 1 | import { suite, test } from "mocha"; 2 | import * as assert from "assert"; 3 | import * as vscode from "vscode"; 4 | import * as path from "path"; 5 | 6 | suite("HTMLHint Test Suite", () => { 7 | // test("Should detect HTML linting errors", async () => { 8 | // const doc = await vscode.workspace.openTextDocument({ 9 | // content: '
\n

Test

\n\n
', 10 | // language: 'html' 11 | // }); 12 | 13 | // const editor = await vscode.window.showTextDocument(doc); 14 | 15 | // // Wait for diagnostics to be generated 16 | // await new Promise(resolve => setTimeout(resolve, 7000)); 17 | 18 | // const diagnostics = vscode.languages.getDiagnostics(doc.uri); 19 | // assert.strictEqual(diagnostics.length > 0, true, 'Should have diagnostics'); 20 | // }); 21 | 22 | test("Should load configuration from .htmlhintrc", async () => { 23 | // Wait a bit for workspace to initialize 24 | await new Promise((resolve) => setTimeout(resolve, 1000)); 25 | 26 | const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; 27 | 28 | if (!workspaceFolder) { 29 | // If no workspace folder, try to find the test config file directly 30 | const testConfigPath = path.resolve( 31 | __dirname, 32 | "../../../test/testConfigFile/.htmlhintrc", 33 | ); 34 | let configExists = false; 35 | try { 36 | await vscode.workspace.fs.stat(vscode.Uri.file(testConfigPath)); 37 | configExists = true; 38 | } catch { 39 | configExists = false; 40 | } 41 | assert.strictEqual( 42 | configExists, 43 | true, 44 | ".htmlhintrc should exist in test config directory", 45 | ); 46 | return; 47 | } 48 | 49 | const configPath = path.join(workspaceFolder.uri.fsPath, ".htmlhintrc"); 50 | let configExists = false; 51 | try { 52 | await vscode.workspace.fs.stat(vscode.Uri.file(configPath)); 53 | configExists = true; 54 | } catch { 55 | configExists = false; 56 | } 57 | 58 | assert.strictEqual(configExists, true, ".htmlhintrc should exist"); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /htmlhint/commands.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import * as fs from "fs"; 3 | import * as path from "path"; 4 | 5 | const defaultConfig = { 6 | "tagname-lowercase": true, 7 | "attr-lowercase": true, 8 | "attr-value-double-quotes": true, 9 | "doctype-first": true, 10 | "tag-pair": true, 11 | "spec-char-escape": true, 12 | "id-unique": true, 13 | "src-not-empty": true, 14 | "attr-no-duplication": true, 15 | "title-require": true, 16 | }; 17 | 18 | export async function createHtmlHintConfig() { 19 | try { 20 | // Get the current workspace folder 21 | const workspaceFolders = vscode.workspace.workspaceFolders; 22 | if (!workspaceFolders || workspaceFolders.length === 0) { 23 | vscode.window.showErrorMessage("No workspace folder is open"); 24 | return; 25 | } 26 | 27 | const firstWorkspaceFolder = workspaceFolders[0]; 28 | if (!firstWorkspaceFolder) { 29 | vscode.window.showErrorMessage("Invalid workspace folder"); 30 | return; 31 | } 32 | 33 | const workspaceRoot = firstWorkspaceFolder.uri.fsPath; 34 | const configPath = path.join(workspaceRoot, ".htmlhintrc"); 35 | 36 | try { 37 | // Try to create the file atomically 38 | fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), { 39 | flag: "wx", 40 | }); 41 | vscode.window.showInformationMessage( 42 | ".htmlhintrc configuration file created successfully", 43 | ); 44 | } catch (error) { 45 | // If file exists, ask for overwrite 46 | if ((error as NodeJS.ErrnoException).code === "EEXIST") { 47 | const overwrite = await vscode.window.showWarningMessage( 48 | ".htmlhintrc already exists. Do you want to overwrite it?", 49 | "Yes", 50 | "No", 51 | ); 52 | if (overwrite === "Yes") { 53 | fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2)); 54 | vscode.window.showInformationMessage( 55 | ".htmlhintrc configuration file updated successfully", 56 | ); 57 | } 58 | } else { 59 | throw error; 60 | } 61 | } 62 | } catch (error) { 63 | vscode.window.showErrorMessage(`Failed to create .htmlhintrc: ${error}`); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/autofix/test-autofixes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 | 29 |
30 | Test 31 |
32 | 33 | 34 | Test image 35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 |

43 | This is a test paragraph with a link. 44 |

45 |
46 | 47 | < Hello > 48 | 49 | 50 | 51 | 52 | 53 | HTML 54 | 55 | 56 |

This is an WWW example with URL.

57 | 58 | 59 | CSS 60 | 61 | 62 | JS 63 | 64 | 65 | XML 66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | const js = require("@eslint/js"); 2 | const tseslint = require("@typescript-eslint/eslint-plugin"); 3 | const tsparser = require("@typescript-eslint/parser"); 4 | const prettier = require("eslint-config-prettier"); 5 | const globals = require("globals"); 6 | 7 | module.exports = [ 8 | { 9 | ignores: [ 10 | "test/**", 11 | "**/*.d.ts", 12 | "out/**", 13 | "htmlhint/out/**", 14 | "htmlhint-server/out/**", 15 | ".vscode-test/**", 16 | "node_modules/**", 17 | "htmlhint/node_modules/**", 18 | "htmlhint-server/node_modules/**", 19 | "htmlhint/vscode-htmlhint-*.vsix", 20 | "**/*.vsix", 21 | ], 22 | }, 23 | js.configs.recommended, 24 | { 25 | files: ["**/*.ts"], 26 | languageOptions: { 27 | parser: tsparser, 28 | parserOptions: { 29 | ecmaVersion: "latest", 30 | sourceType: "module", 31 | }, 32 | globals: { 33 | ...globals.node, 34 | NodeJS: "readonly", 35 | }, 36 | }, 37 | plugins: { 38 | "@typescript-eslint": tseslint, 39 | }, 40 | rules: { 41 | ...tseslint.configs.recommended.rules, 42 | "no-console": "error", 43 | "no-empty": "off", 44 | "no-var": "off", 45 | "prefer-const": "off", 46 | "@typescript-eslint/explicit-module-boundary-types": "off", 47 | "@typescript-eslint/no-empty-interface": "off", 48 | "@typescript-eslint/no-explicit-any": "off", 49 | "@typescript-eslint/no-non-null-assertion": "off", 50 | // Disable base no-unused-vars rule for TypeScript files to prevent conflicts 51 | "no-unused-vars": "off", 52 | "@typescript-eslint/no-unused-vars": [ 53 | "error", 54 | { 55 | argsIgnorePattern: "^_", 56 | varsIgnorePattern: "^_", 57 | args: "after-used", 58 | }, 59 | ], 60 | "@typescript-eslint/no-var-requires": "off", 61 | }, 62 | }, 63 | { 64 | files: ["**/*.js"], 65 | languageOptions: { 66 | ecmaVersion: "latest", 67 | sourceType: "commonjs", 68 | globals: { 69 | ...globals.node, 70 | NodeJS: "readonly", 71 | }, 72 | }, 73 | rules: { 74 | "no-console": "error", 75 | "no-empty": "off", 76 | "no-var": "off", 77 | "prefer-const": "off", 78 | "no-unused-vars": [ 79 | "error", 80 | { 81 | argsIgnorePattern: "^_", 82 | varsIgnorePattern: "^_", 83 | args: "after-used", 84 | }, 85 | ], 86 | }, 87 | }, 88 | prettier, 89 | ]; 90 | -------------------------------------------------------------------------------- /test/autofix/empty-tag-not-self-closed-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Empty Tag Not Self-Closed Test 8 | 9 | 10 | 11 |
12 | 13 | 14 | Test 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 |
53 | Test 3 54 | 55 | 56 |
57 | Test 2 58 |
59 | 60 | 61 |
Content
62 |

Paragraph content

63 | 64 | 65 |
66 |

67 | 68 | 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HTMLHint - Visual Studio Code Extension 2 | 3 | VS Code extension to support HTMLHint, an HTML linter. 4 | 5 |

6 | 7 | Visual Studio Marketplace Version 8 | 9 | VS Code Marketplace Downloads 10 | 11 | VS Code Marketplace Installs 12 | 13 | VS Code Marketplace Ratings 14 |

15 | 16 | ## Installation 17 | 18 | Install through VS Code extensions. Search for `HTMLHint` and install the extension. 19 | 20 | - [Visual Studio Code Marketplace: HTMLHint](https://marketplace.visualstudio.com/items?itemName=HTMLHint.vscode-htmlhint) 21 | - [Open VSX Registry: HTMLHint](https://open-vsx.org/extension/HTMLHint/vscode-htmlhint) 22 | 23 | Alternatively, launch VS Code Quick Open (`Ctrl`+`P`), paste the following command, and press enter. 24 | 25 | ```txt 26 | ext install HTMLHint.vscode-htmlhint 27 | ``` 28 | 29 | ## Development setup 30 | 31 | - run `npm install` inside the `htmlhint` and `htmlhint-server` folders 32 | - run `npm run compile` inside the `htmlhint` and `htmlhint-server` folders 33 | - open VS Code on this folder 34 | - Press Ctrl+Shift+B to compile the client and server 35 | - Switch to the Debug viewlet 36 | - Select `Launch Client` from the drop down 37 | - Run the launch config 38 | - open VS Code on `htmlhint` and `htmlhint-server` 39 | 40 | ## Developing the server 41 | 42 | - open VS Code on `htmlhint-server` 43 | - run `npm run compile` or `npm run watch` to build the server and copy it into the `htmlhint` folder 44 | - to debug press F5 which attaches a debugger to the server 45 | 46 | ## Developing the extension/client 47 | 48 | - open VS Code on `htmlhint` 49 | - run F5 to build and debug the extension 50 | 51 | ## Building the Extension 52 | 53 | - run `vsce package` in extension root folder to create the VSIX file. 54 | 55 | ## Releasing a new version 56 | 57 | - update the version in the `package.json` file 58 | - update the `CHANGELOG.md` file 59 | - run `npm run package` in the extension root folder to create the VSIX file 60 | - upload the VSIX file to the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=HTMLHint.vscode-htmlhint) 61 | - upload the VSIX file to the [Open VSX Registry](https://open-vsx.org/user-settings/extensions) 62 | -------------------------------------------------------------------------------- /htmlhint/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | **/coverage/** 3 | **/example/** 4 | **/examples/** 5 | **/test/** 6 | **/tests/** 7 | **/.cspell.json 8 | **/.DS_Store 9 | **/.editorconfig 10 | **/.eslintignore 11 | **/.eslintrc.* 12 | **/.gitattributes 13 | **/.gitconfig 14 | **/.github 15 | **/.gitignore 16 | **/.gitkeep 17 | **/.history/** 18 | **/.idea/** 19 | **/.jscpd.json 20 | **/.lycheeignore 21 | **/.npmignore 22 | **/.npmrc 23 | **/.nvmrc 24 | **/.prettierignore 25 | **/.prettierrc 26 | **/*.bnf 27 | **/*.css 28 | **/*.map 29 | **/*.travis.yml 30 | **/*.ts 31 | **/*.txt 32 | **/*.vsix 33 | **/*.xml 34 | **/*.yml 35 | **/*.zip 36 | images/hero.png 37 | images/hover.png 38 | images/status-bar.png 39 | **/node_modules/async/** 40 | **/node_modules/htmlhint/dist/htmlhint.min.js 41 | **/node_modules/htmlhint/cli/formatter.js 42 | **/node_modules/htmlhint/cli/htmlhint.js 43 | **/node_modules/htmlhint/cli/parse-glob.js 44 | **/node_modules/htmlhint/cli/formatters/** 45 | **/node_modules/**/test/** 46 | **/node_modules/**/tests/** 47 | **/node_modules/**/*.md 48 | **/node_modules/**/*.txt 49 | **/node_modules/**/LICENSE* 50 | **/node_modules/**/LICENSE-MIT* 51 | **/node_modules/**/license* 52 | **/node_modules/**/CHANGELOG* 53 | **/node_modules/**/changelog* 54 | **/node_modules/**/*.map 55 | **/node_modules/**/.bin/** 56 | **/node_modules/**/bin/** 57 | **/node_modules/**/copy/** 58 | **/node_modules/**/move/** 59 | **/node_modules/**/empty/** 60 | **/node_modules/**/*.cmd 61 | **/node_modules/**/*.ps1 62 | **/node_modules/**/*.sh 63 | **/node_modules/**/*.bat 64 | **/node_modules/**/*.d.ts 65 | **/node_modules/**/*.ts 66 | **/node_modules/**/tsconfig.json 67 | **/node_modules/**/package-lock.json 68 | **/node_modules/**/.npmrc 69 | **/node_modules/**/yarn.lock 70 | **/node_modules/**/.gitignore 71 | **/node_modules/**/.npmignore 72 | **/node_modules/**/.eslintrc* 73 | **/node_modules/**/webpack.config.js 74 | **/node_modules/**/renovate.json 75 | **/node_modules/**/rollup.config.js 76 | **/node_modules/**/jest.config.js 77 | **/node_modules/**/babel.config.js 78 | **/node_modules/**/vite.config.js 79 | **/node_modules/**/.vscode/** 80 | **/node_modules/**/browser/** 81 | **/node_modules/**/esm/** 82 | **/node_modules/**/example/** 83 | **/node_modules/**/examples/** 84 | **/node_modules/**/docs/** 85 | **/node_modules/**/doc/** 86 | **/node_modules/**/*.exe 87 | **/node_modules/**/*.dll 88 | **/node_modules/**/*.so 89 | **/node_modules/**/*.dylib 90 | **/node_modules/**/coverage/** 91 | **/node_modules/**/.nyc_output/** 92 | **/node_modules/**/benchmark/** 93 | **/node_modules/**/benchmarks/** 94 | package-lock.json 95 | *.tsbuildinfo 96 | .tsbuildinfo 97 | **/.tsbuildinfo 98 | **/*.log 99 | **/*.tmp 100 | **/*.temp 101 | **/tmp/** 102 | **/temp/** 103 | **/*.bak 104 | **/*.backup 105 | **/*.orig 106 | **/*.rej 107 | **/*.patch 108 | **/*.diff 109 | **/*.old 110 | **/*.swp 111 | **/*.swo 112 | *~ 113 | tsconfig.json 114 | typings/** 115 | -------------------------------------------------------------------------------- /htmlhint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-htmlhint", 3 | "displayName": "HTMLHint", 4 | "description": "VS Code integration for HTMLHint - A Static Code Analysis Tool for HTML", 5 | "icon": "images/icon.png", 6 | "version": "1.15.0", 7 | "publisher": "HTMLHint", 8 | "galleryBanner": { 9 | "color": "#333333", 10 | "theme": "dark" 11 | }, 12 | "sponsor": { 13 | "url": "https://opencollective.com/htmlhint" 14 | }, 15 | "license": "SEE LICENSE IN LICENSE.md", 16 | "bugs": { 17 | "url": "https://github.com/htmlhint/vscode-htmlhint/issues" 18 | }, 19 | "homepage": "https://github.com/htmlhint/vscode-htmlhint/blob/main/README.md", 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/htmlhint/vscode-htmlhint.git" 23 | }, 24 | "categories": [ 25 | "Programming Languages", 26 | "Linters" 27 | ], 28 | "engines": { 29 | "vscode": "^1.101.0" 30 | }, 31 | "activationEvents": [ 32 | "onLanguage:html", 33 | "onLanguage:htm" 34 | ], 35 | "main": "./out/extension", 36 | "contributes": { 37 | "commands": [ 38 | { 39 | "command": "htmlhint.createConfig", 40 | "title": "HTMLHINT: Create a .htmlhintrc config" 41 | } 42 | ], 43 | "configuration": { 44 | "type": "object", 45 | "title": "HTMLHint", 46 | "properties": { 47 | "htmlhint.enable": { 48 | "type": "boolean", 49 | "default": true, 50 | "description": "Control whether HTMLHint is enabled for HTML files or not." 51 | }, 52 | "htmlhint.documentSelector": { 53 | "type": "array", 54 | "default": [ 55 | "html", 56 | "htm" 57 | ], 58 | "description": "The associated document types to be linted." 59 | }, 60 | "htmlhint.options": { 61 | "type": "object", 62 | "default": {}, 63 | "description": "The HTMLHint options object to provide args to the HTMLHint command." 64 | }, 65 | "htmlhint.optionsFile": { 66 | "type": "string", 67 | "default": null, 68 | "description": "The HTMLHint options config file path." 69 | }, 70 | "htmlhint.ignoreGitignore": { 71 | "type": "boolean", 72 | "default": false, 73 | "description": "Skip linting files that are ignored by .gitignore. This is useful to avoid linting generated files, dependencies, and other files that shouldn't be checked." 74 | } 75 | } 76 | }, 77 | "jsonValidation": [ 78 | { 79 | "fileMatch": [ 80 | "/.htmlhintrc" 81 | ], 82 | "url": "https://json.schemastore.org/htmlhint.json" 83 | } 84 | ] 85 | }, 86 | "scripts": { 87 | "vscode:prepublish": "npm run compile && npm run bundle-dependencies", 88 | "compile": "tsc -p ./", 89 | "watch": "tsc -watch -p ./", 90 | "bundle-dependencies": "npm install --no-package-lock --no-save --no-fund htmlhint@1.8.0 strip-json-comments@3.1.1 vscode-languageserver@9.0.1 vscode-languageserver-textdocument@1.0.12 vscode-uri@3.1.0 ignore@7.0.5", 91 | "package": "vsce package" 92 | }, 93 | "devDependencies": { 94 | "@types/node": "^22.19.1", 95 | "@types/vscode": "^1.101.0", 96 | "@vscode/test-electron": "^2.5.2", 97 | "typescript": "5.6.3" 98 | }, 99 | "dependencies": { 100 | "htmlhint": "1.8.0", 101 | "strip-json-comments": "3.1.1", 102 | "vscode-languageclient": "9.0.1", 103 | "vscode-languageserver": "9.0.1", 104 | "vscode-languageserver-textdocument": "1.0.12", 105 | "vscode-uri": "3.1.0" 106 | }, 107 | "bundleDependencies": [ 108 | "vscode-languageclient", 109 | "htmlhint", 110 | "strip-json-comments", 111 | "vscode-languageserver", 112 | "vscode-languageserver-textdocument", 113 | "vscode-uri", 114 | "ignore" 115 | ], 116 | "volta": { 117 | "node": "22.19.0" 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /htmlhint/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to the "vscode-htmlhint" extension will be documented in this file. 4 | 5 | ### v1.15.0 (TBD) 6 | 7 | - Add autofix for the `empty-tag-not-self-closed` rule 8 | - Add autofix for the `link-rel-canonical-require` rule 9 | - Smarter autofix for rules which accommodates for `tag-self-close` rule 10 | 11 | ### v1.14.0 (2025-11-26) 12 | 13 | - Add autofix for the `attr-no-duplication` rule 14 | - Add autofix for the `attr-value-no-duplication` rule 15 | - Add autofix for the `form-method-require` rule 16 | 17 | ### v1.13.0 (2025-11-25) 18 | 19 | - Update HTMLHint to v1.8.0 20 | - Add support for [disabling rules via HTML comments](https://htmlhint.com/configuration/#disabling-rules-inline) 21 | 22 | ### v1.12.0 (2025-09-15) 23 | 24 | - Update HTMLHint to v1.7.0 25 | 26 | ### v1.11.1 (2025-06-24) 27 | 28 | - Add autofix for `tag-no-obsolete` rule 29 | - Minor optimizations and code cleanup 30 | - Reduced package size by 30% 31 | 32 | ### v1.11.0 (2025-06-20) 33 | 34 | - Option to skip linting files ignored by `.gitignore` (`htmlhint.ignoreGitignore`). 35 | - When enabled, HTMLHint will not lint files or folders listed in your workspace's `.gitignore` (e.g., `node_modules/`, `dist/`, etc). 36 | - Enable this in VS Code settings: `HTMLHint: Ignore Gitignore`. 37 | - Add autofix for `attr-whitespace` rule 38 | 39 | ### v1.10.2 (2025-06-19) 40 | 41 | - Add autofix for `spec-char-escape` rule 42 | - Add autofix for `tag-self-close` rule 43 | - Rename extension output channel to "HTMLHint Extension" for better debugging 44 | 45 | ### v1.10.1 (2025-06-19) 46 | 47 | - Update HTMLHint to v1.6.3 48 | 49 | ### v1.10.0 (2025-06-18) 50 | 51 | - Update HTMLHint to v1.6.2 52 | 53 | ### v1.9.1 (2025-06-16) 54 | 55 | - Many under the hood improvements for performance and stability 56 | - Minor optimizations and code cleanup 57 | 58 | ### v1.9.0 (2025-06-13) 59 | 60 | - Add command to create a `.htmlhintrc` config file 61 | - Add autofix for `meta-description-require` 62 | - Improved Autofixing 63 | 64 | ### v1.8.0 (2025-06-13) 65 | 66 | - Issue IDs in problems now link to the HTMLHint rule documentation 67 | 68 | ### v1.7.0 (2025-06-13) 69 | 70 | - Add autofix for `meta-description-require` 71 | - Improve HTMLHint config loading 72 | - Enable Debug Logging (check the Output > HTMLHint channel in VS Code) 73 | 74 | ### v1.6.2 (2025-06-12) 75 | 76 | - Fix for config file not being used 77 | 78 | ### v1.6.1 (2025-06-12) 79 | 80 | - Reduced file-size and minor optimizations 81 | 82 | ### v1.6.0 (2025-06-12) 83 | 84 | - Add autofix for `alt-require` 85 | - Add autofix for `attr-lowercase` 86 | - Add autofix for `attr-no-unnecessary-whitespace` 87 | - Add autofix for `attr-value-double-quotes` 88 | - Add autofix for `button-type-require` 89 | - Add autofix for `doctype-first` 90 | - Add autofix for `doctype-html5` 91 | - Add autofix for `html-lang-require` 92 | - Add autofix for `meta-charset-require` 93 | - Add autofix for `meta-viewport-require` 94 | - Add autofix for `tag-self-close` 95 | - Add autofix for `tagname-lowercase` 96 | - Add autofix for `title-require` 97 | - Many under the hood improvements for performance and stability 98 | 99 | ### v1.5.0 (2025-06-11) 100 | 101 | - Update HTMLHint to v1.5.1 102 | 103 | ### v1.4.2 (2025-06-04) 104 | 105 | - Fixes missing config file path option. You could now specify a custom path to your `.htmlhintrc` file in the extension settings. e.g. `"htmlhint.optionsFile": "your-project-subfolder/.htmlhintrc"` 106 | 107 | ### v1.4.1 (2025-06-04) 108 | 109 | - Minor optimizations and code cleanup 110 | 111 | ### v1.4.0 (2025-06-03) 112 | 113 | - Update HTMLHint to v1.4.0 114 | 115 | ### v1.3.0 (2025-06-01) 116 | 117 | - Update HTMLHint to v1.3.0 118 | 119 | ### v1.2.0 (2025-05-30) 120 | 121 | - Extension now can automatically validate your `.htmlhintrc` configuration file using JSON Schema (https://json.schemastore.org/htmlhint.json) 122 | 123 | ### v1.1.0 (2025-05-28) 124 | 125 | - Migrate extension to use @types/vscode which means fewer dependencies and better compatibility with future VS Code versions 126 | 127 | ### v1.0.8 (2025-05-27) 128 | 129 | - Update HTMLHint to v1.2.0 130 | 131 | ### v1.0.7 (2025-03-19) 132 | 133 | - Fix build issue 134 | 135 | ### v1.0.6 (2025-03-19) 136 | 137 | - Fix for issues appearing even when files are closed 138 | 139 | ### v1.0.5 (2023-05-17) 140 | 141 | - Fix for activationEvents (now can be used in `markdown` and other files) 142 | - Reduced file-size and minor optimizations 143 | 144 | ### v1.0.4 (2022-10-07) 145 | 146 | - Reduced file-size and minor optimizations 147 | 148 | ### v1.0.3 (2022-09-21) 149 | 150 | - Fix extension startup issue 151 | 152 | ### v1.0.2 (2022-09-21) 153 | 154 | - Hi-DPI icon added 155 | - Reduced file-size by 29% ! 156 | 157 | ### v1.0.1 (2022-09-20) 158 | 159 | - Reduced file-size and minor optimizations 160 | 161 | ### v1.0.0 (2022-09-15) 162 | 163 | - Initial Release 164 | -------------------------------------------------------------------------------- /htmlhint/README.md: -------------------------------------------------------------------------------- 1 | # HTMLHint - VS Code Extension 2 | 3 | Integrates the [HTMLHint](https://github.com/htmlhint/HTMLHint) static analysis tool into Visual Studio Code. 4 | 5 | ![HTMLHint - VS Code Extension](https://github.com/htmlhint/vscode-htmlhint/raw/main/htmlhint/images/hero.png) 6 | 7 | ## Configuration 8 | 9 | The HTMLHint extension will attempt to use the locally installed HTMLHint module (the project-specific module if present, or a globally installed HTMLHint module). If a locally installed HTMLHint isn't available, the extension will use the embedded version (current version 1.6.3). 10 | 11 | To install a version to the local project folder, run `npm install --save-dev htmlhint`. To install a global version on the current machine, run `npm install --global htmlhint`. 12 | 13 | ## Usage 14 | 15 | The HTMLHint extension will run HTMLHint on your open HTML files and report the number of errors on the Status Bar with details in the Problems panel (**View** > **Problems**). 16 | 17 | ![status bar](https://github.com/htmlhint/vscode-htmlhint/raw/main/htmlhint/images/status-bar.png) 18 | 19 | Errors in HTML files are highlighted with squiggles and you can hover over the squiggles to see the error message. 20 | 21 | Many problems can now be fixed automatically by clicking on the lightbulb icon in problems panel or right-clicking on the error in the HTML file and selecting "Quick Fix". 22 | 23 | ![hover](https://github.com/htmlhint/vscode-htmlhint/raw/main/htmlhint/images/hover.png) 24 | 25 | ### Auto-fix Support 26 | 27 | The extension provides automatic fixes for many common HTML issues. Currently supported auto-fixes include: 28 | 29 | - **`alt-require`** - Adds alt attribute to images 30 | - **`attr-lowercase`** - Converts uppercase attribute names to lowercase 31 | - **`attr-no-duplication`** - Removes duplicate attributes (only when values are identical) 32 | - **`attr-no-unnecessary-whitespace`** - Removes unnecessary whitespace around attributes 33 | - **`attr-value-double-quotes`** - Converts single quotes to double quotes in attributes 34 | - **`attr-value-no-duplication`** - Removes duplicate values within attributes (e.g., `class="btn btn primary"` → `class="btn primary"`) 35 | - **`attr-whitespace`** - Removes leading and trailing whitespace from attribute values 36 | - **`button-type-require`** - Adds type attribute to buttons 37 | - **`doctype-first`** - Adds DOCTYPE declaration at the beginning 38 | - **`doctype-html5`** - Updates DOCTYPE to HTML5 39 | - **`empty-tag-not-self-closed`** - Converts void elements to self-closing format (e.g., `
` → `
`) 40 | - **`form-method-require`** - Adds empty method attribute to forms 41 | - **`html-lang-require`** - Adds `lang` attribute to `` tag 42 | - **`link-rel-canonical-require`** - Adds canonical link tag 43 | - **`meta-charset-require`** - Adds charset meta tag 44 | - **`meta-description-require`** - Adds description meta tag 45 | - **`meta-viewport-require`** - Adds viewport meta tag 46 | - **`spec-char-escape`** - Escapes special characters (`<`, `>`) 47 | - **`tag-no-obsolete`** - Converts obsolete tags to modern equivalents (e.g., `` to ``) 48 | - **`tag-self-close`** - Converts self-closable tags to self-closing tags 49 | - **`tagname-lowercase`** - Converts uppercase tag names to lowercase 50 | - **`title-require`** - Adds `` tag to document 51 | 52 | > **Note:** HTMLHint will only analyze open HTML files and does not search for HTML files in your project folder. 53 | 54 | ## Rules 55 | 56 | The HTMLHint extension uses the default [rules](https://htmlhint.com/list-rules/) provided by HTMLHint. 57 | 58 | ```json 59 | { 60 | "tagname-lowercase": true, 61 | "attr-lowercase": true, 62 | "attr-value-double-quotes": true, 63 | "doctype-first": true, 64 | "tag-pair": true, 65 | "spec-char-escape": true, 66 | "id-unique": true, 67 | "src-not-empty": true, 68 | "attr-no-duplication": true, 69 | "title-require": true 70 | } 71 | ``` 72 | 73 | ## .htmlhintrc 74 | 75 | If you'd like to modify the rules, you can provide a `.htmlhintrc` file in the root of your project folder with a reduced ruleset or modified values. 76 | 77 | You can learn more about rule configuration at the HTMLHint [Usage page](https://htmlhint.com/usage/cli/). 78 | 79 | ## Additional file types 80 | 81 | By default, HTMLHint will run on any files associated with the "html" language service (i.e., ".html" and ".htm" files). If you'd like to use the HTMLHint extension with additional file types, you have two options: 82 | 83 | ### Option 1: Treating your file like any other HTML file 84 | 85 | If you would like the file type to be treated as any other HTML file (including syntax highlighting, as well as HTMLHint linting), you'll need to associate the extension with the HTML language service. Add the following to your VS Code [settings](https://code.visualstudio.com/docs/configure/settings), replacing `"*.ext"` with your file extension. 86 | 87 | ```json 88 | { 89 | "files.associations": { 90 | "*.ext": "html" 91 | } 92 | } 93 | ``` 94 | 95 | ### Option 2: Associating HTMLHint extension with your file type 96 | 97 | If your file type already has an associated language service other than "html", and you'd like HTMLHint to process those file types, you will need to associate the HTMLHint extension with that language service. Add the following to your VS Code [settings](https://code.visualstudio.com/docs/configure/settings), replacing `"mylang"` with your language service. For example, if you want HTMLHint to process `.twig` files, you would use `"twig"`. Note that with this configuration, **you need to open an HTML file first** to activate the HTMLHint extension. Otherwise, you won't see any linter errors, (the extension is hard-coded to activate when the HTML language service activates). 98 | 99 | ```json 100 | { 101 | "htmlhint.documentSelector": ["html", "mylang"] 102 | } 103 | ``` 104 | 105 | ## Settings 106 | 107 | The HTMLHint extension provides these [settings](https://code.visualstudio.com/docs/getstarted/settings): 108 | 109 | - `htmlhint.enable` - disable the HTMLHint extension globally or per workspace. 110 | - `htmlhint.documentSelector` - specify additional language services to be linted 111 | - `htmlhint.options` - provide a rule set to override on disk `.htmlhintrc` or HTMLHint defaults. 112 | - `htmlhint.configFile` - specify a custom HTMLHint configuration file. Please specify either 'htmlhint.configFile' or 'htmlhint.options', but not both. 113 | 114 | You can change settings globally (**File** > **Preferences** > **User Settings**) or per workspace (**File** > **Preferences** > **Workspace Settings**). The **Preferences** menu is under **Code** on macOS. 115 | 116 | Here's an example using the `htmlhint.documentSelector` and `htmlhint.options` settings: 117 | 118 | ```json 119 | "htmlhint.documentSelector": [ 120 | "html", 121 | "htm", 122 | "twig" 123 | ], 124 | "htmlhint.options": { 125 | "attr-lowercase": true, 126 | "attr-value-double-quotes": true, 127 | "doctype-first": true, 128 | "meta-charset-require": true, 129 | "meta-viewport-require": true, 130 | "tagname-lowercase": false, 131 | "title-require": true 132 | } 133 | ``` 134 | 135 | ## Skipping Linting for `.gitignore`-d Files 136 | 137 | You can configure the extension to **skip linting files and folders that are listed in your `.gitignore`**. This is useful for ignoring generated files, dependencies, and other files you don't want to lint (like `node_modules/`, `dist/`, `build/`, etc). 138 | 139 | ### How to Enable 140 | 141 | 1. Open VS Code settings. 142 | 2. Search for `HTMLHint: Ignore Gitignore`. 143 | 3. Enable the option: 144 | **`htmlhint.ignoreGitignore`** (default: `false`) 145 | 146 | When enabled, any HTML files ignored by your workspace's `.gitignore` will not be linted by the extension. 147 | 148 | ### Example 149 | 150 | If your `.gitignore` contains: 151 | 152 | ``` 153 | node_modules/ 154 | dist/ 155 | *.tmp 156 | ``` 157 | 158 | Then files like `dist/index.html` or `node_modules/foo/bar.html` will be skipped by HTMLHint. 159 | -------------------------------------------------------------------------------- /htmlhint/extension.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import * as vscode from "vscode"; 3 | import { 4 | LanguageClient, 5 | LanguageClientOptions, 6 | ServerOptions, 7 | TransportKind, 8 | Diagnostic as LSPDiagnostic, 9 | CodeAction as LSPCodeAction, 10 | } from "vscode-languageclient/node"; 11 | import { createHtmlHintConfig } from "./commands"; 12 | 13 | let client: LanguageClient; 14 | let outputChannel: vscode.OutputChannel; 15 | 16 | export function activate(context: vscode.ExtensionContext) { 17 | // Create output channel for logging 18 | outputChannel = vscode.window.createOutputChannel("HTMLHint Extension"); 19 | context.subscriptions.push(outputChannel); 20 | 21 | // Register the create config command 22 | let createConfigCommand = vscode.commands.registerCommand( 23 | "htmlhint.createConfig", 24 | createHtmlHintConfig, 25 | ); 26 | context.subscriptions.push(createConfigCommand); 27 | 28 | // We need to go one level up since an extension compile the js code into 29 | // the output folder. 30 | let serverModulePath = path.join(__dirname, "..", "server", "server.js"); 31 | let debugOptions = { 32 | execArgv: ["--nolazy", "--inspect=6010"], 33 | cwd: process.cwd(), 34 | }; 35 | let serverOptions: ServerOptions = { 36 | run: { module: serverModulePath, transport: TransportKind.ipc }, 37 | debug: { 38 | module: serverModulePath, 39 | transport: TransportKind.ipc, 40 | options: debugOptions, 41 | }, 42 | }; 43 | 44 | // Get file types to lint from user settings 45 | let config = vscode.workspace.getConfiguration("htmlhint"); 46 | let languages: string[] = config.get("documentSelector") || ["html", "htm"]; 47 | let documentSelector = languages.map((language) => ({ 48 | language, 49 | scheme: "file", 50 | })); 51 | 52 | // Set options 53 | let clientOptions: LanguageClientOptions = { 54 | documentSelector, 55 | diagnosticCollectionName: "htmlhint", 56 | synchronize: { 57 | configurationSection: "htmlhint", 58 | fileEvents: [ 59 | vscode.workspace.createFileSystemWatcher("**/.htmlhintrc"), 60 | vscode.workspace.createFileSystemWatcher("**/.htmlhintrc.json"), 61 | vscode.workspace.createFileSystemWatcher("**/.gitignore"), 62 | ], 63 | }, 64 | middleware: { 65 | handleDiagnostics: (uri, diagnostics, next) => { 66 | const enhancedDiagnostics = diagnostics.map((diagnostic) => { 67 | const lspDiagnostic = diagnostic as unknown as LSPDiagnostic; 68 | if (lspDiagnostic.data?.href) { 69 | const vscodeDiagnostic = new vscode.Diagnostic( 70 | diagnostic.range, 71 | diagnostic.message, 72 | diagnostic.severity, 73 | ); 74 | if (diagnostic.source) { 75 | vscodeDiagnostic.source = diagnostic.source; 76 | } 77 | vscodeDiagnostic.code = { 78 | value: diagnostic.code as string, 79 | target: vscode.Uri.parse(lspDiagnostic.data.href), 80 | }; 81 | // Preserve the original data for autofix 82 | (vscodeDiagnostic as any).data = lspDiagnostic.data; 83 | return vscodeDiagnostic; 84 | } 85 | return diagnostic; 86 | }); 87 | return next(uri, enhancedDiagnostics); 88 | }, 89 | }, 90 | }; 91 | 92 | // Create the language client and start it 93 | client = new LanguageClient( 94 | "HTMLHint", 95 | "HTMLHint", 96 | serverOptions, 97 | clientOptions, 98 | ); 99 | 100 | // Register code action provider 101 | const codeActionProvider = vscode.languages.registerCodeActionsProvider( 102 | documentSelector, 103 | { 104 | provideCodeActions: async ( 105 | document, 106 | range, 107 | context, 108 | token, 109 | ): Promise<vscode.CodeAction[]> => { 110 | try { 111 | outputChannel.appendLine( 112 | `[DEBUG] Code action requested for ${document.uri}`, 113 | ); 114 | outputChannel.appendLine(`[DEBUG] Range: ${JSON.stringify(range)}`); 115 | outputChannel.appendLine( 116 | `[DEBUG] Context diagnostics: ${JSON.stringify(context.diagnostics)}`, 117 | ); 118 | 119 | // Convert VS Code diagnostics to LSP diagnostics 120 | const lspDiagnostics = context.diagnostics.map((d) => { 121 | const code = d.code as { value: string; target: vscode.Uri }; 122 | const data = (d as any).data || { 123 | ruleId: code.value, 124 | href: code.target.toString(), 125 | line: d.range.start.line + 1, // Convert 0-based to 1-based line numbers 126 | col: d.range.start.character + 1, // Convert 0-based to 1-based column numbers 127 | raw: d.message.split(" ")[0], // Extract the raw element from the message 128 | }; 129 | return { 130 | range: d.range, 131 | message: d.message, 132 | severity: d.severity, 133 | source: d.source, 134 | code: code.value, 135 | data: data, 136 | }; 137 | }); 138 | 139 | outputChannel.appendLine( 140 | `[DEBUG] Converted diagnostics: ${JSON.stringify(lspDiagnostics)}`, 141 | ); 142 | 143 | // Request code actions from the server 144 | const lspCodeActions = await client.sendRequest<LSPCodeAction[]>( 145 | "textDocument/codeAction", 146 | { 147 | textDocument: { uri: document.uri.toString() }, 148 | range, 149 | context: { 150 | diagnostics: lspDiagnostics, 151 | only: context.only, 152 | }, 153 | }, 154 | token, 155 | ); 156 | 157 | outputChannel.appendLine( 158 | `[DEBUG] Received ${lspCodeActions.length} code actions from server`, 159 | ); 160 | outputChannel.appendLine( 161 | `[DEBUG] Code actions: ${JSON.stringify(lspCodeActions)}`, 162 | ); 163 | 164 | // Convert LSP CodeActions to VS Code CodeActions 165 | const actions = lspCodeActions.map((lspAction) => { 166 | outputChannel.appendLine( 167 | `[DEBUG] Converting code action: ${JSON.stringify(lspAction)}`, 168 | ); 169 | 170 | const action = new vscode.CodeAction( 171 | lspAction.title, 172 | vscode.CodeActionKind.QuickFix, 173 | ); 174 | 175 | if (lspAction.edit?.changes) { 176 | action.edit = new vscode.WorkspaceEdit(); 177 | for (const [uri, edits] of Object.entries( 178 | lspAction.edit.changes, 179 | )) { 180 | for (const edit of edits) { 181 | outputChannel.appendLine( 182 | `[DEBUG] Adding edit: ${JSON.stringify(edit)}`, 183 | ); 184 | action.edit.replace( 185 | vscode.Uri.parse(uri), 186 | new vscode.Range( 187 | edit.range.start.line, 188 | edit.range.start.character, 189 | edit.range.end.line, 190 | edit.range.end.character, 191 | ), 192 | edit.newText, 193 | ); 194 | } 195 | } 196 | } 197 | 198 | if (lspAction.isPreferred) { 199 | action.isPreferred = true; 200 | } 201 | 202 | return action; 203 | }); 204 | 205 | outputChannel.appendLine( 206 | `[DEBUG] Converted ${actions.length} code actions`, 207 | ); 208 | return actions; 209 | } catch (error) { 210 | outputChannel.appendLine(`Error providing code actions: ${error}`); 211 | return []; 212 | } 213 | }, 214 | }, 215 | { 216 | providedCodeActionKinds: [vscode.CodeActionKind.QuickFix], 217 | }, 218 | ); 219 | 220 | context.subscriptions.push(codeActionProvider); 221 | 222 | // Start the client 223 | client.start(); 224 | context.subscriptions.push(client); 225 | } 226 | 227 | export async function deactivate(): Promise<void> { 228 | if (!client) { 229 | return; 230 | } 231 | return client.stop(); 232 | } 233 | -------------------------------------------------------------------------------- /htmlhint-server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "htmlhint-server", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "htmlhint-server", 9 | "version": "1.0.0", 10 | "dependencies": { 11 | "htmlhint": "^1.8.0", 12 | "strip-json-comments": "3.1.1", 13 | "vscode-languageserver": "^9.0.1", 14 | "vscode-languageserver-textdocument": "^1.0.12", 15 | "vscode-uri": "^3.1.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "22.15.31", 19 | "typescript": "5.5.4" 20 | }, 21 | "engines": { 22 | "node": "*" 23 | } 24 | }, 25 | "node_modules/@types/node": { 26 | "version": "22.15.31", 27 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.31.tgz", 28 | "integrity": "sha512-jnVe5ULKl6tijxUhvQeNbQG/84fHfg+yMak02cT8QVhBx/F05rAVxCGBYYTh2EKz22D6JF5ktXuNwdx7b9iEGw==", 29 | "dev": true, 30 | "license": "MIT", 31 | "dependencies": { 32 | "undici-types": "~6.21.0" 33 | } 34 | }, 35 | "node_modules/@types/sarif": { 36 | "version": "2.1.7", 37 | "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", 38 | "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", 39 | "license": "MIT" 40 | }, 41 | "node_modules/ansi-styles": { 42 | "version": "4.3.0", 43 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 44 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 45 | "dependencies": { 46 | "color-convert": "^2.0.1" 47 | }, 48 | "engines": { 49 | "node": ">=8" 50 | }, 51 | "funding": { 52 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 53 | } 54 | }, 55 | "node_modules/async": { 56 | "version": "3.2.6", 57 | "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", 58 | "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", 59 | "license": "MIT" 60 | }, 61 | "node_modules/balanced-match": { 62 | "version": "1.0.2", 63 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 64 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 65 | "license": "MIT" 66 | }, 67 | "node_modules/brace-expansion": { 68 | "version": "2.0.2", 69 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", 70 | "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", 71 | "license": "MIT", 72 | "dependencies": { 73 | "balanced-match": "^1.0.0" 74 | } 75 | }, 76 | "node_modules/chalk": { 77 | "version": "4.1.2", 78 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 79 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 80 | "dependencies": { 81 | "ansi-styles": "^4.1.0", 82 | "supports-color": "^7.1.0" 83 | }, 84 | "engines": { 85 | "node": ">=10" 86 | }, 87 | "funding": { 88 | "url": "https://github.com/chalk/chalk?sponsor=1" 89 | } 90 | }, 91 | "node_modules/color-convert": { 92 | "version": "2.0.1", 93 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 94 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 95 | "dependencies": { 96 | "color-name": "~1.1.4" 97 | }, 98 | "engines": { 99 | "node": ">=7.0.0" 100 | } 101 | }, 102 | "node_modules/color-name": { 103 | "version": "1.1.4", 104 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 105 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 106 | }, 107 | "node_modules/commander": { 108 | "version": "11.1.0", 109 | "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", 110 | "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", 111 | "license": "MIT", 112 | "engines": { 113 | "node": ">=16" 114 | } 115 | }, 116 | "node_modules/fs-extra": { 117 | "version": "11.3.2", 118 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", 119 | "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", 120 | "license": "MIT", 121 | "dependencies": { 122 | "graceful-fs": "^4.2.0", 123 | "jsonfile": "^6.0.1", 124 | "universalify": "^2.0.0" 125 | }, 126 | "engines": { 127 | "node": ">=14.14" 128 | } 129 | }, 130 | "node_modules/fs.realpath": { 131 | "version": "1.0.0", 132 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 133 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 134 | "license": "ISC" 135 | }, 136 | "node_modules/glob": { 137 | "version": "9.3.5", 138 | "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", 139 | "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", 140 | "license": "ISC", 141 | "dependencies": { 142 | "fs.realpath": "^1.0.0", 143 | "minimatch": "^8.0.2", 144 | "minipass": "^4.2.4", 145 | "path-scurry": "^1.6.1" 146 | }, 147 | "engines": { 148 | "node": ">=16 || 14 >=14.17" 149 | }, 150 | "funding": { 151 | "url": "https://github.com/sponsors/isaacs" 152 | } 153 | }, 154 | "node_modules/graceful-fs": { 155 | "version": "4.2.11", 156 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 157 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 158 | "license": "ISC" 159 | }, 160 | "node_modules/has-flag": { 161 | "version": "4.0.0", 162 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 163 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 164 | "engines": { 165 | "node": ">=8" 166 | } 167 | }, 168 | "node_modules/htmlhint": { 169 | "version": "1.8.0", 170 | "resolved": "https://registry.npmjs.org/htmlhint/-/htmlhint-1.8.0.tgz", 171 | "integrity": "sha512-RT1UsSM3ldlVQ7DDqWnbbRY1Rf6wwudmdYwiJzIyZVapA0jcka5r2lE2RkMLzTDN5c8Vc06yis57TaTpZ6o3Dg==", 172 | "license": "MIT", 173 | "dependencies": { 174 | "async": "3.2.6", 175 | "chalk": "4.1.2", 176 | "commander": "11.1.0", 177 | "glob": "^9.0.0", 178 | "is-glob": "^4.0.3", 179 | "node-sarif-builder": "^3.3.1", 180 | "strip-json-comments": "3.1.1", 181 | "xml": "1.0.1" 182 | }, 183 | "bin": { 184 | "htmlhint": "bin/htmlhint" 185 | }, 186 | "engines": { 187 | "node": ">=18" 188 | }, 189 | "funding": { 190 | "type": "Open Collective", 191 | "url": "https://opencollective.com/htmlhint" 192 | } 193 | }, 194 | "node_modules/is-extglob": { 195 | "version": "2.1.1", 196 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 197 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 198 | "engines": { 199 | "node": ">=0.10.0" 200 | } 201 | }, 202 | "node_modules/is-glob": { 203 | "version": "4.0.3", 204 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 205 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 206 | "dependencies": { 207 | "is-extglob": "^2.1.1" 208 | }, 209 | "engines": { 210 | "node": ">=0.10.0" 211 | } 212 | }, 213 | "node_modules/jsonfile": { 214 | "version": "6.2.0", 215 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", 216 | "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", 217 | "license": "MIT", 218 | "dependencies": { 219 | "universalify": "^2.0.0" 220 | }, 221 | "optionalDependencies": { 222 | "graceful-fs": "^4.1.6" 223 | } 224 | }, 225 | "node_modules/lru-cache": { 226 | "version": "10.4.3", 227 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 228 | "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", 229 | "license": "ISC" 230 | }, 231 | "node_modules/minimatch": { 232 | "version": "8.0.4", 233 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", 234 | "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", 235 | "license": "ISC", 236 | "dependencies": { 237 | "brace-expansion": "^2.0.1" 238 | }, 239 | "engines": { 240 | "node": ">=16 || 14 >=14.17" 241 | }, 242 | "funding": { 243 | "url": "https://github.com/sponsors/isaacs" 244 | } 245 | }, 246 | "node_modules/minipass": { 247 | "version": "4.2.8", 248 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", 249 | "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", 250 | "license": "ISC", 251 | "engines": { 252 | "node": ">=8" 253 | } 254 | }, 255 | "node_modules/node-sarif-builder": { 256 | "version": "3.3.1", 257 | "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.3.1.tgz", 258 | "integrity": "sha512-8z5dAbhpxmk/WRQHXlv4V0h+9Y4Ugk+w08lyhV/7E/CQX9yDdBc3025/EG+RSMJU2aPFh/IQ7XDV7Ti5TLt/TA==", 259 | "license": "MIT", 260 | "dependencies": { 261 | "@types/sarif": "^2.1.7", 262 | "fs-extra": "^11.1.1" 263 | }, 264 | "engines": { 265 | "node": ">=20" 266 | } 267 | }, 268 | "node_modules/path-scurry": { 269 | "version": "1.11.1", 270 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", 271 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", 272 | "license": "BlueOak-1.0.0", 273 | "dependencies": { 274 | "lru-cache": "^10.2.0", 275 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 276 | }, 277 | "engines": { 278 | "node": ">=16 || 14 >=14.18" 279 | }, 280 | "funding": { 281 | "url": "https://github.com/sponsors/isaacs" 282 | } 283 | }, 284 | "node_modules/path-scurry/node_modules/minipass": { 285 | "version": "7.1.2", 286 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", 287 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", 288 | "license": "ISC", 289 | "engines": { 290 | "node": ">=16 || 14 >=14.17" 291 | } 292 | }, 293 | "node_modules/strip-json-comments": { 294 | "version": "3.1.1", 295 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 296 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 297 | "engines": { 298 | "node": ">=8" 299 | }, 300 | "funding": { 301 | "url": "https://github.com/sponsors/sindresorhus" 302 | } 303 | }, 304 | "node_modules/supports-color": { 305 | "version": "7.2.0", 306 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 307 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 308 | "dependencies": { 309 | "has-flag": "^4.0.0" 310 | }, 311 | "engines": { 312 | "node": ">=8" 313 | } 314 | }, 315 | "node_modules/typescript": { 316 | "version": "5.5.4", 317 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", 318 | "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", 319 | "dev": true, 320 | "license": "Apache-2.0", 321 | "bin": { 322 | "tsc": "bin/tsc", 323 | "tsserver": "bin/tsserver" 324 | }, 325 | "engines": { 326 | "node": ">=14.17" 327 | } 328 | }, 329 | "node_modules/undici-types": { 330 | "version": "6.21.0", 331 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", 332 | "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", 333 | "dev": true, 334 | "license": "MIT" 335 | }, 336 | "node_modules/universalify": { 337 | "version": "2.0.1", 338 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", 339 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", 340 | "license": "MIT", 341 | "engines": { 342 | "node": ">= 10.0.0" 343 | } 344 | }, 345 | "node_modules/vscode-jsonrpc": { 346 | "version": "8.2.0", 347 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", 348 | "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", 349 | "engines": { 350 | "node": ">=14.0.0" 351 | } 352 | }, 353 | "node_modules/vscode-languageserver": { 354 | "version": "9.0.1", 355 | "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", 356 | "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", 357 | "dependencies": { 358 | "vscode-languageserver-protocol": "3.17.5" 359 | }, 360 | "bin": { 361 | "installServerIntoExtension": "bin/installServerIntoExtension" 362 | } 363 | }, 364 | "node_modules/vscode-languageserver-protocol": { 365 | "version": "3.17.5", 366 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", 367 | "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", 368 | "dependencies": { 369 | "vscode-jsonrpc": "8.2.0", 370 | "vscode-languageserver-types": "3.17.5" 371 | } 372 | }, 373 | "node_modules/vscode-languageserver-textdocument": { 374 | "version": "1.0.12", 375 | "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", 376 | "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==" 377 | }, 378 | "node_modules/vscode-languageserver-types": { 379 | "version": "3.17.5", 380 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", 381 | "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" 382 | }, 383 | "node_modules/vscode-uri": { 384 | "version": "3.1.0", 385 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", 386 | "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", 387 | "license": "MIT" 388 | }, 389 | "node_modules/xml": { 390 | "version": "1.0.1", 391 | "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", 392 | "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" 393 | } 394 | } 395 | } 396 | -------------------------------------------------------------------------------- /htmlhint/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-htmlhint", 3 | "version": "1.15.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "vscode-htmlhint", 9 | "version": "1.15.0", 10 | "bundleDependencies": [ 11 | "vscode-languageclient", 12 | "htmlhint", 13 | "strip-json-comments", 14 | "vscode-languageserver", 15 | "vscode-languageserver-textdocument", 16 | "vscode-uri", 17 | "ignore" 18 | ], 19 | "license": "SEE LICENSE IN LICENSE.md", 20 | "dependencies": { 21 | "htmlhint": "1.8.0", 22 | "strip-json-comments": "3.1.1", 23 | "vscode-languageclient": "9.0.1", 24 | "vscode-languageserver": "9.0.1", 25 | "vscode-languageserver-textdocument": "1.0.12", 26 | "vscode-uri": "3.1.0" 27 | }, 28 | "devDependencies": { 29 | "@types/node": "^22.19.1", 30 | "@types/vscode": "^1.101.0", 31 | "@vscode/test-electron": "^2.5.2", 32 | "typescript": "5.6.3" 33 | }, 34 | "engines": { 35 | "vscode": "^1.101.0" 36 | } 37 | }, 38 | "node_modules/@types/node": { 39 | "version": "22.19.1", 40 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.1.tgz", 41 | "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==", 42 | "dev": true, 43 | "license": "MIT", 44 | "dependencies": { 45 | "undici-types": "~6.21.0" 46 | } 47 | }, 48 | "node_modules/@types/sarif": { 49 | "version": "2.1.7", 50 | "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", 51 | "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", 52 | "inBundle": true, 53 | "license": "MIT" 54 | }, 55 | "node_modules/@types/vscode": { 56 | "version": "1.101.0", 57 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.101.0.tgz", 58 | "integrity": "sha512-ZWf0IWa+NGegdW3iU42AcDTFHWW7fApLdkdnBqwYEtHVIBGbTu0ZNQKP/kX3Ds/uMJXIMQNAojHR4vexCEEz5Q==", 59 | "dev": true, 60 | "license": "MIT" 61 | }, 62 | "node_modules/@vscode/test-electron": { 63 | "version": "2.5.2", 64 | "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz", 65 | "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==", 66 | "dev": true, 67 | "license": "MIT", 68 | "dependencies": { 69 | "http-proxy-agent": "^7.0.2", 70 | "https-proxy-agent": "^7.0.5", 71 | "jszip": "^3.10.1", 72 | "ora": "^8.1.0", 73 | "semver": "^7.6.2" 74 | }, 75 | "engines": { 76 | "node": ">=16" 77 | } 78 | }, 79 | "node_modules/agent-base": { 80 | "version": "7.1.4", 81 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", 82 | "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", 83 | "dev": true, 84 | "license": "MIT", 85 | "engines": { 86 | "node": ">= 14" 87 | } 88 | }, 89 | "node_modules/ansi-regex": { 90 | "version": "6.2.2", 91 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", 92 | "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", 93 | "dev": true, 94 | "license": "MIT", 95 | "engines": { 96 | "node": ">=12" 97 | }, 98 | "funding": { 99 | "url": "https://github.com/chalk/ansi-regex?sponsor=1" 100 | } 101 | }, 102 | "node_modules/ansi-styles": { 103 | "version": "4.3.0", 104 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 105 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 106 | "inBundle": true, 107 | "license": "MIT", 108 | "dependencies": { 109 | "color-convert": "^2.0.1" 110 | }, 111 | "engines": { 112 | "node": ">=8" 113 | }, 114 | "funding": { 115 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 116 | } 117 | }, 118 | "node_modules/async": { 119 | "version": "3.2.6", 120 | "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", 121 | "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", 122 | "inBundle": true, 123 | "license": "MIT" 124 | }, 125 | "node_modules/balanced-match": { 126 | "version": "1.0.2", 127 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 128 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 129 | "inBundle": true, 130 | "license": "MIT" 131 | }, 132 | "node_modules/brace-expansion": { 133 | "version": "2.0.2", 134 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", 135 | "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", 136 | "inBundle": true, 137 | "license": "MIT", 138 | "dependencies": { 139 | "balanced-match": "^1.0.0" 140 | } 141 | }, 142 | "node_modules/chalk": { 143 | "version": "4.1.2", 144 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 145 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 146 | "inBundle": true, 147 | "license": "MIT", 148 | "dependencies": { 149 | "ansi-styles": "^4.1.0", 150 | "supports-color": "^7.1.0" 151 | }, 152 | "engines": { 153 | "node": ">=10" 154 | }, 155 | "funding": { 156 | "url": "https://github.com/chalk/chalk?sponsor=1" 157 | } 158 | }, 159 | "node_modules/cli-cursor": { 160 | "version": "5.0.0", 161 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", 162 | "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", 163 | "dev": true, 164 | "license": "MIT", 165 | "dependencies": { 166 | "restore-cursor": "^5.0.0" 167 | }, 168 | "engines": { 169 | "node": ">=18" 170 | }, 171 | "funding": { 172 | "url": "https://github.com/sponsors/sindresorhus" 173 | } 174 | }, 175 | "node_modules/cli-spinners": { 176 | "version": "2.9.2", 177 | "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", 178 | "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", 179 | "dev": true, 180 | "license": "MIT", 181 | "engines": { 182 | "node": ">=6" 183 | }, 184 | "funding": { 185 | "url": "https://github.com/sponsors/sindresorhus" 186 | } 187 | }, 188 | "node_modules/color-convert": { 189 | "version": "2.0.1", 190 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 191 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 192 | "inBundle": true, 193 | "license": "MIT", 194 | "dependencies": { 195 | "color-name": "~1.1.4" 196 | }, 197 | "engines": { 198 | "node": ">=7.0.0" 199 | } 200 | }, 201 | "node_modules/color-name": { 202 | "version": "1.1.4", 203 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 204 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 205 | "inBundle": true, 206 | "license": "MIT" 207 | }, 208 | "node_modules/commander": { 209 | "version": "11.1.0", 210 | "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", 211 | "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", 212 | "inBundle": true, 213 | "license": "MIT", 214 | "engines": { 215 | "node": ">=16" 216 | } 217 | }, 218 | "node_modules/core-util-is": { 219 | "version": "1.0.3", 220 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 221 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 222 | "dev": true, 223 | "license": "MIT" 224 | }, 225 | "node_modules/debug": { 226 | "version": "4.4.3", 227 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", 228 | "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", 229 | "dev": true, 230 | "license": "MIT", 231 | "dependencies": { 232 | "ms": "^2.1.3" 233 | }, 234 | "engines": { 235 | "node": ">=6.0" 236 | }, 237 | "peerDependenciesMeta": { 238 | "supports-color": { 239 | "optional": true 240 | } 241 | } 242 | }, 243 | "node_modules/emoji-regex": { 244 | "version": "10.6.0", 245 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", 246 | "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", 247 | "dev": true, 248 | "license": "MIT" 249 | }, 250 | "node_modules/fs-extra": { 251 | "version": "11.3.2", 252 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", 253 | "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", 254 | "inBundle": true, 255 | "license": "MIT", 256 | "dependencies": { 257 | "graceful-fs": "^4.2.0", 258 | "jsonfile": "^6.0.1", 259 | "universalify": "^2.0.0" 260 | }, 261 | "engines": { 262 | "node": ">=14.14" 263 | } 264 | }, 265 | "node_modules/fs.realpath": { 266 | "version": "1.0.0", 267 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 268 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 269 | "inBundle": true, 270 | "license": "ISC" 271 | }, 272 | "node_modules/get-east-asian-width": { 273 | "version": "1.4.0", 274 | "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", 275 | "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", 276 | "dev": true, 277 | "license": "MIT", 278 | "engines": { 279 | "node": ">=18" 280 | }, 281 | "funding": { 282 | "url": "https://github.com/sponsors/sindresorhus" 283 | } 284 | }, 285 | "node_modules/glob": { 286 | "version": "9.3.5", 287 | "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", 288 | "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", 289 | "inBundle": true, 290 | "license": "ISC", 291 | "dependencies": { 292 | "fs.realpath": "^1.0.0", 293 | "minimatch": "^8.0.2", 294 | "minipass": "^4.2.4", 295 | "path-scurry": "^1.6.1" 296 | }, 297 | "engines": { 298 | "node": ">=16 || 14 >=14.17" 299 | }, 300 | "funding": { 301 | "url": "https://github.com/sponsors/isaacs" 302 | } 303 | }, 304 | "node_modules/glob/node_modules/minimatch": { 305 | "version": "8.0.4", 306 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", 307 | "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", 308 | "inBundle": true, 309 | "license": "ISC", 310 | "dependencies": { 311 | "brace-expansion": "^2.0.1" 312 | }, 313 | "engines": { 314 | "node": ">=16 || 14 >=14.17" 315 | }, 316 | "funding": { 317 | "url": "https://github.com/sponsors/isaacs" 318 | } 319 | }, 320 | "node_modules/graceful-fs": { 321 | "version": "4.2.11", 322 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 323 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 324 | "inBundle": true, 325 | "license": "ISC" 326 | }, 327 | "node_modules/has-flag": { 328 | "version": "4.0.0", 329 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 330 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 331 | "inBundle": true, 332 | "license": "MIT", 333 | "engines": { 334 | "node": ">=8" 335 | } 336 | }, 337 | "node_modules/htmlhint": { 338 | "version": "1.8.0", 339 | "resolved": "https://registry.npmjs.org/htmlhint/-/htmlhint-1.8.0.tgz", 340 | "integrity": "sha512-RT1UsSM3ldlVQ7DDqWnbbRY1Rf6wwudmdYwiJzIyZVapA0jcka5r2lE2RkMLzTDN5c8Vc06yis57TaTpZ6o3Dg==", 341 | "inBundle": true, 342 | "license": "MIT", 343 | "dependencies": { 344 | "async": "3.2.6", 345 | "chalk": "4.1.2", 346 | "commander": "11.1.0", 347 | "glob": "^9.0.0", 348 | "is-glob": "^4.0.3", 349 | "node-sarif-builder": "^3.3.1", 350 | "strip-json-comments": "3.1.1", 351 | "xml": "1.0.1" 352 | }, 353 | "bin": { 354 | "htmlhint": "bin/htmlhint" 355 | }, 356 | "engines": { 357 | "node": ">=18" 358 | }, 359 | "funding": { 360 | "type": "Open Collective", 361 | "url": "https://opencollective.com/htmlhint" 362 | } 363 | }, 364 | "node_modules/http-proxy-agent": { 365 | "version": "7.0.2", 366 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", 367 | "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", 368 | "dev": true, 369 | "license": "MIT", 370 | "dependencies": { 371 | "agent-base": "^7.1.0", 372 | "debug": "^4.3.4" 373 | }, 374 | "engines": { 375 | "node": ">= 14" 376 | } 377 | }, 378 | "node_modules/https-proxy-agent": { 379 | "version": "7.0.6", 380 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", 381 | "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", 382 | "dev": true, 383 | "license": "MIT", 384 | "dependencies": { 385 | "agent-base": "^7.1.2", 386 | "debug": "4" 387 | }, 388 | "engines": { 389 | "node": ">= 14" 390 | } 391 | }, 392 | "node_modules/immediate": { 393 | "version": "3.0.6", 394 | "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", 395 | "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", 396 | "dev": true, 397 | "license": "MIT" 398 | }, 399 | "node_modules/inherits": { 400 | "version": "2.0.4", 401 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 402 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 403 | "dev": true, 404 | "license": "ISC" 405 | }, 406 | "node_modules/is-extglob": { 407 | "version": "2.1.1", 408 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 409 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 410 | "inBundle": true, 411 | "license": "MIT", 412 | "engines": { 413 | "node": ">=0.10.0" 414 | } 415 | }, 416 | "node_modules/is-glob": { 417 | "version": "4.0.3", 418 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 419 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 420 | "inBundle": true, 421 | "license": "MIT", 422 | "dependencies": { 423 | "is-extglob": "^2.1.1" 424 | }, 425 | "engines": { 426 | "node": ">=0.10.0" 427 | } 428 | }, 429 | "node_modules/is-interactive": { 430 | "version": "2.0.0", 431 | "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", 432 | "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", 433 | "dev": true, 434 | "license": "MIT", 435 | "engines": { 436 | "node": ">=12" 437 | }, 438 | "funding": { 439 | "url": "https://github.com/sponsors/sindresorhus" 440 | } 441 | }, 442 | "node_modules/is-unicode-supported": { 443 | "version": "2.1.0", 444 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", 445 | "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", 446 | "dev": true, 447 | "license": "MIT", 448 | "engines": { 449 | "node": ">=18" 450 | }, 451 | "funding": { 452 | "url": "https://github.com/sponsors/sindresorhus" 453 | } 454 | }, 455 | "node_modules/isarray": { 456 | "version": "1.0.0", 457 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 458 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", 459 | "dev": true, 460 | "license": "MIT" 461 | }, 462 | "node_modules/jsonfile": { 463 | "version": "6.2.0", 464 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", 465 | "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", 466 | "inBundle": true, 467 | "license": "MIT", 468 | "dependencies": { 469 | "universalify": "^2.0.0" 470 | }, 471 | "optionalDependencies": { 472 | "graceful-fs": "^4.1.6" 473 | } 474 | }, 475 | "node_modules/jszip": { 476 | "version": "3.10.1", 477 | "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", 478 | "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", 479 | "dev": true, 480 | "license": "(MIT OR GPL-3.0-or-later)", 481 | "dependencies": { 482 | "lie": "~3.3.0", 483 | "pako": "~1.0.2", 484 | "readable-stream": "~2.3.6", 485 | "setimmediate": "^1.0.5" 486 | } 487 | }, 488 | "node_modules/lie": { 489 | "version": "3.3.0", 490 | "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", 491 | "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", 492 | "dev": true, 493 | "license": "MIT", 494 | "dependencies": { 495 | "immediate": "~3.0.5" 496 | } 497 | }, 498 | "node_modules/log-symbols": { 499 | "version": "6.0.0", 500 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", 501 | "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", 502 | "dev": true, 503 | "license": "MIT", 504 | "dependencies": { 505 | "chalk": "^5.3.0", 506 | "is-unicode-supported": "^1.3.0" 507 | }, 508 | "engines": { 509 | "node": ">=18" 510 | }, 511 | "funding": { 512 | "url": "https://github.com/sponsors/sindresorhus" 513 | } 514 | }, 515 | "node_modules/log-symbols/node_modules/chalk": { 516 | "version": "5.6.2", 517 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", 518 | "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", 519 | "dev": true, 520 | "license": "MIT", 521 | "engines": { 522 | "node": "^12.17.0 || ^14.13 || >=16.0.0" 523 | }, 524 | "funding": { 525 | "url": "https://github.com/chalk/chalk?sponsor=1" 526 | } 527 | }, 528 | "node_modules/log-symbols/node_modules/is-unicode-supported": { 529 | "version": "1.3.0", 530 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", 531 | "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", 532 | "dev": true, 533 | "license": "MIT", 534 | "engines": { 535 | "node": ">=12" 536 | }, 537 | "funding": { 538 | "url": "https://github.com/sponsors/sindresorhus" 539 | } 540 | }, 541 | "node_modules/lru-cache": { 542 | "version": "10.4.3", 543 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", 544 | "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", 545 | "inBundle": true, 546 | "license": "ISC" 547 | }, 548 | "node_modules/mimic-function": { 549 | "version": "5.0.1", 550 | "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", 551 | "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", 552 | "dev": true, 553 | "license": "MIT", 554 | "engines": { 555 | "node": ">=18" 556 | }, 557 | "funding": { 558 | "url": "https://github.com/sponsors/sindresorhus" 559 | } 560 | }, 561 | "node_modules/minimatch": { 562 | "version": "5.1.6", 563 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", 564 | "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", 565 | "inBundle": true, 566 | "license": "ISC", 567 | "dependencies": { 568 | "brace-expansion": "^2.0.1" 569 | }, 570 | "engines": { 571 | "node": ">=10" 572 | } 573 | }, 574 | "node_modules/minipass": { 575 | "version": "4.2.8", 576 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", 577 | "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", 578 | "inBundle": true, 579 | "license": "ISC", 580 | "engines": { 581 | "node": ">=8" 582 | } 583 | }, 584 | "node_modules/ms": { 585 | "version": "2.1.3", 586 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 587 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 588 | "dev": true, 589 | "license": "MIT" 590 | }, 591 | "node_modules/node-sarif-builder": { 592 | "version": "3.3.1", 593 | "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.3.1.tgz", 594 | "integrity": "sha512-8z5dAbhpxmk/WRQHXlv4V0h+9Y4Ugk+w08lyhV/7E/CQX9yDdBc3025/EG+RSMJU2aPFh/IQ7XDV7Ti5TLt/TA==", 595 | "inBundle": true, 596 | "license": "MIT", 597 | "dependencies": { 598 | "@types/sarif": "^2.1.7", 599 | "fs-extra": "^11.1.1" 600 | }, 601 | "engines": { 602 | "node": ">=20" 603 | } 604 | }, 605 | "node_modules/onetime": { 606 | "version": "7.0.0", 607 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", 608 | "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", 609 | "dev": true, 610 | "license": "MIT", 611 | "dependencies": { 612 | "mimic-function": "^5.0.0" 613 | }, 614 | "engines": { 615 | "node": ">=18" 616 | }, 617 | "funding": { 618 | "url": "https://github.com/sponsors/sindresorhus" 619 | } 620 | }, 621 | "node_modules/ora": { 622 | "version": "8.2.0", 623 | "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", 624 | "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", 625 | "dev": true, 626 | "license": "MIT", 627 | "dependencies": { 628 | "chalk": "^5.3.0", 629 | "cli-cursor": "^5.0.0", 630 | "cli-spinners": "^2.9.2", 631 | "is-interactive": "^2.0.0", 632 | "is-unicode-supported": "^2.0.0", 633 | "log-symbols": "^6.0.0", 634 | "stdin-discarder": "^0.2.2", 635 | "string-width": "^7.2.0", 636 | "strip-ansi": "^7.1.0" 637 | }, 638 | "engines": { 639 | "node": ">=18" 640 | }, 641 | "funding": { 642 | "url": "https://github.com/sponsors/sindresorhus" 643 | } 644 | }, 645 | "node_modules/ora/node_modules/chalk": { 646 | "version": "5.6.2", 647 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", 648 | "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", 649 | "dev": true, 650 | "license": "MIT", 651 | "engines": { 652 | "node": "^12.17.0 || ^14.13 || >=16.0.0" 653 | }, 654 | "funding": { 655 | "url": "https://github.com/chalk/chalk?sponsor=1" 656 | } 657 | }, 658 | "node_modules/pako": { 659 | "version": "1.0.11", 660 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", 661 | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", 662 | "dev": true, 663 | "license": "(MIT AND Zlib)" 664 | }, 665 | "node_modules/path-scurry": { 666 | "version": "1.11.1", 667 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", 668 | "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", 669 | "inBundle": true, 670 | "license": "BlueOak-1.0.0", 671 | "dependencies": { 672 | "lru-cache": "^10.2.0", 673 | "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" 674 | }, 675 | "engines": { 676 | "node": ">=16 || 14 >=14.18" 677 | }, 678 | "funding": { 679 | "url": "https://github.com/sponsors/isaacs" 680 | } 681 | }, 682 | "node_modules/path-scurry/node_modules/minipass": { 683 | "version": "7.1.2", 684 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", 685 | "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", 686 | "inBundle": true, 687 | "license": "ISC", 688 | "engines": { 689 | "node": ">=16 || 14 >=14.17" 690 | } 691 | }, 692 | "node_modules/process-nextick-args": { 693 | "version": "2.0.1", 694 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 695 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 696 | "dev": true, 697 | "license": "MIT" 698 | }, 699 | "node_modules/readable-stream": { 700 | "version": "2.3.8", 701 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", 702 | "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", 703 | "dev": true, 704 | "license": "MIT", 705 | "dependencies": { 706 | "core-util-is": "~1.0.0", 707 | "inherits": "~2.0.3", 708 | "isarray": "~1.0.0", 709 | "process-nextick-args": "~2.0.0", 710 | "safe-buffer": "~5.1.1", 711 | "string_decoder": "~1.1.1", 712 | "util-deprecate": "~1.0.1" 713 | } 714 | }, 715 | "node_modules/restore-cursor": { 716 | "version": "5.1.0", 717 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", 718 | "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", 719 | "dev": true, 720 | "license": "MIT", 721 | "dependencies": { 722 | "onetime": "^7.0.0", 723 | "signal-exit": "^4.1.0" 724 | }, 725 | "engines": { 726 | "node": ">=18" 727 | }, 728 | "funding": { 729 | "url": "https://github.com/sponsors/sindresorhus" 730 | } 731 | }, 732 | "node_modules/safe-buffer": { 733 | "version": "5.1.2", 734 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 735 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 736 | "dev": true, 737 | "license": "MIT" 738 | }, 739 | "node_modules/semver": { 740 | "version": "7.7.2", 741 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", 742 | "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", 743 | "inBundle": true, 744 | "bin": { 745 | "semver": "bin/semver.js" 746 | }, 747 | "engines": { 748 | "node": ">=10" 749 | } 750 | }, 751 | "node_modules/setimmediate": { 752 | "version": "1.0.5", 753 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 754 | "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", 755 | "dev": true, 756 | "license": "MIT" 757 | }, 758 | "node_modules/signal-exit": { 759 | "version": "4.1.0", 760 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 761 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 762 | "dev": true, 763 | "license": "ISC", 764 | "engines": { 765 | "node": ">=14" 766 | }, 767 | "funding": { 768 | "url": "https://github.com/sponsors/isaacs" 769 | } 770 | }, 771 | "node_modules/stdin-discarder": { 772 | "version": "0.2.2", 773 | "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", 774 | "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", 775 | "dev": true, 776 | "license": "MIT", 777 | "engines": { 778 | "node": ">=18" 779 | }, 780 | "funding": { 781 | "url": "https://github.com/sponsors/sindresorhus" 782 | } 783 | }, 784 | "node_modules/string_decoder": { 785 | "version": "1.1.1", 786 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 787 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 788 | "dev": true, 789 | "license": "MIT", 790 | "dependencies": { 791 | "safe-buffer": "~5.1.0" 792 | } 793 | }, 794 | "node_modules/string-width": { 795 | "version": "7.2.0", 796 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", 797 | "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", 798 | "dev": true, 799 | "license": "MIT", 800 | "dependencies": { 801 | "emoji-regex": "^10.3.0", 802 | "get-east-asian-width": "^1.0.0", 803 | "strip-ansi": "^7.1.0" 804 | }, 805 | "engines": { 806 | "node": ">=18" 807 | }, 808 | "funding": { 809 | "url": "https://github.com/sponsors/sindresorhus" 810 | } 811 | }, 812 | "node_modules/strip-ansi": { 813 | "version": "7.1.2", 814 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", 815 | "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", 816 | "dev": true, 817 | "license": "MIT", 818 | "dependencies": { 819 | "ansi-regex": "^6.0.1" 820 | }, 821 | "engines": { 822 | "node": ">=12" 823 | }, 824 | "funding": { 825 | "url": "https://github.com/chalk/strip-ansi?sponsor=1" 826 | } 827 | }, 828 | "node_modules/strip-json-comments": { 829 | "version": "3.1.1", 830 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 831 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 832 | "inBundle": true, 833 | "license": "MIT", 834 | "engines": { 835 | "node": ">=8" 836 | }, 837 | "funding": { 838 | "url": "https://github.com/sponsors/sindresorhus" 839 | } 840 | }, 841 | "node_modules/supports-color": { 842 | "version": "7.2.0", 843 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 844 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 845 | "inBundle": true, 846 | "license": "MIT", 847 | "dependencies": { 848 | "has-flag": "^4.0.0" 849 | }, 850 | "engines": { 851 | "node": ">=8" 852 | } 853 | }, 854 | "node_modules/typescript": { 855 | "version": "5.6.3", 856 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", 857 | "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", 858 | "dev": true, 859 | "license": "Apache-2.0", 860 | "bin": { 861 | "tsc": "bin/tsc", 862 | "tsserver": "bin/tsserver" 863 | }, 864 | "engines": { 865 | "node": ">=14.17" 866 | } 867 | }, 868 | "node_modules/undici-types": { 869 | "version": "6.21.0", 870 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", 871 | "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", 872 | "dev": true, 873 | "license": "MIT" 874 | }, 875 | "node_modules/universalify": { 876 | "version": "2.0.1", 877 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", 878 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", 879 | "inBundle": true, 880 | "license": "MIT", 881 | "engines": { 882 | "node": ">= 10.0.0" 883 | } 884 | }, 885 | "node_modules/util-deprecate": { 886 | "version": "1.0.2", 887 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 888 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 889 | "dev": true, 890 | "license": "MIT" 891 | }, 892 | "node_modules/vscode-jsonrpc": { 893 | "version": "8.2.0", 894 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", 895 | "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", 896 | "inBundle": true, 897 | "engines": { 898 | "node": ">=14.0.0" 899 | } 900 | }, 901 | "node_modules/vscode-languageclient": { 902 | "version": "9.0.1", 903 | "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", 904 | "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", 905 | "inBundle": true, 906 | "dependencies": { 907 | "minimatch": "^5.1.0", 908 | "semver": "^7.3.7", 909 | "vscode-languageserver-protocol": "3.17.5" 910 | }, 911 | "engines": { 912 | "vscode": "^1.82.0" 913 | } 914 | }, 915 | "node_modules/vscode-languageserver": { 916 | "version": "9.0.1", 917 | "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", 918 | "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", 919 | "inBundle": true, 920 | "dependencies": { 921 | "vscode-languageserver-protocol": "3.17.5" 922 | }, 923 | "bin": { 924 | "installServerIntoExtension": "bin/installServerIntoExtension" 925 | } 926 | }, 927 | "node_modules/vscode-languageserver-protocol": { 928 | "version": "3.17.5", 929 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", 930 | "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", 931 | "inBundle": true, 932 | "dependencies": { 933 | "vscode-jsonrpc": "8.2.0", 934 | "vscode-languageserver-types": "3.17.5" 935 | } 936 | }, 937 | "node_modules/vscode-languageserver-textdocument": { 938 | "version": "1.0.12", 939 | "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", 940 | "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", 941 | "inBundle": true, 942 | "license": "MIT" 943 | }, 944 | "node_modules/vscode-languageserver-types": { 945 | "version": "3.17.5", 946 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", 947 | "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", 948 | "inBundle": true 949 | }, 950 | "node_modules/vscode-uri": { 951 | "version": "3.1.0", 952 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", 953 | "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", 954 | "inBundle": true, 955 | "license": "MIT" 956 | }, 957 | "node_modules/xml": { 958 | "version": "1.0.1", 959 | "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", 960 | "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", 961 | "inBundle": true, 962 | "license": "MIT" 963 | } 964 | } 965 | } 966 | --------------------------------------------------------------------------------