Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • html-validate/html-validate
  • stofolus/html-validate
  • Hawakes/html-validate
  • lahandjch/html-validate
  • mihkeleidast/html-validate
  • danielroe/html-validate
  • annemariedupont/html-validate
  • llazzaro/html-validate
  • stklcode/html-validate
  • davideinfo4/html-validate
  • hubmisto/html-validate
  • Badlapje/html-validate
  • ongaq/html-validate
  • jeremy.greenwald/html-validate
  • Mirza-Hassan/html-validate
  • n1j0/html-validate
  • deemyboy2/html-validate
  • Zaid-Parkar/html-validate
  • shngt/html-validate
  • leahzaloshinsky/html-validate
  • daoyuly/html-validate
  • istr/html-validate
  • fulldecent/html-validate
  • notinn/html-validate
  • armbiant/html-validate
  • janschoenherr/html-validate
  • aabccd021/html-validate
  • jordanoverbye/html-validate
  • sofiajimenezcabrera14/html-validate
  • maxwell.baduduedu/html-validate
  • anubhav1450/html-validate
  • devanshbaghel/html-validate
  • saquib24k/html-validate
  • everead2001/html-validate
  • Vishalrewaskar/html-validate
  • seeerge/html-validate
  • KishanSoni66/html-validate
  • MCFK/html-validate
  • armbiant/gnome-html-5-validate
  • quitziamerc/html-validate
40 results
Select Git revision
Show changes
Commits on Source (19)
Showing
with 1155 additions and 835 deletions
coverage/
dist/
node_modules/
public/assets/
temp/
require("@html-validate/eslint-config/patch/modern-module-resolution");
module.exports = {
root: true,
extends: ["@html-validate"],
rules: {
"import/extensions": "off",
"security/detect-unsafe-regex": "off",
"sonarjs/function-return-type": "off",
"sonarjs/slow-regex": "off",
"sonarjs/todo-tag": "off",
},
overrides: [
{
/* ensure cjs and mjs files are linted too */
files: ["*.cjs", "*.mjs"],
},
{
files: ["docs/*.js"],
rules: {
/* docs scripts are expected to log to console */
"no-console": "off",
},
},
{
/* build scripts and configurations may log to console */
files: ["internal/*/*.{js,mjs,cjs}"],
rules: {
"no-console": "off",
},
},
{
files: "*.ts",
extends: ["@html-validate/typescript"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unnecessary-condition": "off",
},
},
{
files: ["docs/examples/**/*.[jt]s"],
rules: {
"@typescript-eslint/no-require-imports": "off",
"eslint-comments/require-description": "off",
"import/no-duplicates": "off",
"import/no-extraneous-dependencies": "off",
"import/no-unresolved": "off",
"n/no-extraneous-import": ["error", { allowModules: ["html-validate"] }],
"tsdoc/syntax": "off",
"no-console": "off",
},
},
{
files: ["src/**/*.ts"],
excludedFiles: ["src/**/*.spec.ts"],
parserOptions: {
tsconfigRootDir: __dirname,
project: ["./tsconfig.json"],
},
extends: ["@html-validate/typescript-typeinfo"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
},
},
{
files: "*.spec.[jt]s",
excludedFiles: ["cypress/**", "tests/e2e/**"],
extends: ["@html-validate/jest"],
rules: {
"sonarjs/no-nested-functions": "off",
},
},
{
/* files which should lint even if project isn't build yet */
files: ["./*.d.ts", "bin/*.js"],
rules: {
"import/export": "off",
"import/extensions": "off",
"import/no-unresolved": "off",
},
},
],
};
# html-validate changelog
## 9.5.1 (2025-03-13)
### Bug Fixes
- handle id with comma ([435abf5](https://gitlab.com/html-validate/html-validate/commit/435abf537e17db9239b79cac408223eec8c8a420)), closes [#299](https://gitlab.com/html-validate/html-validate/issues/299)
## 9.5.0 (2025-03-08)
### Features
......
{
"overrides": [
{
"files": "**/*.spec.ts",
"rules": {
"dot-notation": "off"
}
}
]
}
{
"rules": {
"no-console": "off"
}
}
......@@ -13,6 +13,7 @@ const path = require("canonical-path");
module.exports = function resolveUrl() {
return (currentPath, newPath, base) => {
// Extract only the path and the hash from the newPath
/* eslint-disable-next-line n/no-deprecated-api -- technical debt */
const parsedUrl = url.parse(newPath);
parsedUrl.search = null;
newPath = url.format(parsedUrl);
......@@ -22,6 +23,7 @@ module.exports = function resolveUrl() {
newPath = path.resolve(base, newPath).replace(/^(\w:)?\//, "");
} else {
// Otherwise resolve against the current path
/* eslint-disable-next-line n/no-deprecated-api -- technical debt */
newPath = url.resolve(currentPath || "", newPath);
}
......
......@@ -3,11 +3,11 @@
"private": true,
"files": [],
"devDependencies": {
"@babel/core": "7.26.9",
"@babel/core": "7.26.10",
"@babel/preset-env": "7.26.9",
"@babel/types": "7.26.9",
"@babel/types": "7.26.10",
"@fortawesome/fontawesome-free": "6.7.2",
"autoprefixer": "10.4.20",
"autoprefixer": "10.4.21",
"babelify": "10.0.0",
"bootstrap-sass": "3.4.3",
"browserify": "17.0.1",
......@@ -33,6 +33,6 @@
"synckit": "0.9.2"
},
"engines": {
"node": ">= 20"
"node": ">= 22.3"
}
}
/* This file is managed by @html-validate/eslint-config */
/* Changes may be overwritten */
import path from "node:path";
import { fileURLToPath } from "node:url";
import defaultConfig from "@html-validate/eslint-config";
import typescriptConfig from "@html-validate/eslint-config-typescript";
import typescriptTypeinfoConfig from "@html-validate/eslint-config-typescript-typeinfo";
import jestConfig from "@html-validate/eslint-config-jest";
const rootDir = path.dirname(fileURLToPath(import.meta.url));
export default [
{
name: "Ignored files",
ignores: [
"**/coverage/**",
"**/dist/**",
"**/node_modules/**",
"**/public/assets/**",
"**/temp/**",
],
},
...defaultConfig,
...typescriptConfig,
{
name: "Typescript typeinfo configuration",
files: ["src/**/*.ts"],
ignores: ["src/**/*.spec.ts"],
languageOptions: {
parserOptions: {
tsconfigRootDir: rootDir,
project: ["./tsconfig.json"],
},
},
},
...typescriptTypeinfoConfig,
...jestConfig,
{
/* files which should lint even if project isn't build yet */
files: ["./*.d.ts", "bin/*.js"],
rules: {
"import/export": "off",
"import/extensions": "off",
"import/no-unresolved": "off",
},
},
{
name: "local",
rules: {
"import/extensions": "off",
"security/detect-unsafe-regex": "off",
"sonarjs/function-return-type": "off",
"sonarjs/slow-regex": "off",
"sonarjs/todo-tag": "off",
},
},
{
/* build scripts and configurations may log to console */
name: "local/build",
files: ["internal/*/*.{js,mjs,cjs}"],
rules: {
"no-console": "off",
},
},
{
name: "local/docs",
files: ["docs/*.js", "docs/dgeni/**/*.js"],
rules: {
/* docs scripts are expected to log to console */
"no-console": "off",
},
},
{
name: "local/docs/specs",
files: ["docs/**/*.spec.ts"],
rules: {
"dot-notation": "off",
},
},
{
name: "local/docs/examples",
files: ["docs/examples/**/*.[jt]s"],
rules: {
"@typescript-eslint/no-require-imports": "off",
"eslint-comments/require-description": "off",
"import/no-duplicates": "off",
"import/no-extraneous-dependencies": "off",
"import/no-unresolved": "off",
"n/no-extraneous-import": ["error", { allowModules: ["html-validate"] }],
"tsdoc/syntax": "off",
"no-console": "off",
},
},
{
name: "local/technical-debt",
files: ["**/*.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unnecessary-condition": "off",
},
},
{
name: "local/tests/integration",
files: ["./tests/integration/**/*.{js,cjs,mjs,ts,mts,cts}"],
rules: {
"import/named": "off",
"import/no-unresolved": "off",
},
},
{
name: "local/tests/vitest",
files: ["./tests/vitest/**/*.{js,cjs,mjs,ts,mts,cts}"],
rules: {
"import/no-extraneous-dependencies": "off",
"import/no-unresolved": "off",
},
},
];
......@@ -10,6 +10,6 @@
"html-validate": "*"
},
"devDependencies": {
"esbuild": "0.25.0"
"esbuild": "0.25.1"
}
}
This diff is collapsed.
{
"name": "html-validate",
"version": "9.5.0",
"version": "9.5.1",
"description": "Offline html5 validator",
"keywords": [
"html",
......@@ -107,10 +107,10 @@
"scripts": {
"prebuild": "run-s codegen && tsc",
"build": "run-s build:cjs build:esm build:script",
"postbuild": "npm run --workspaces --if-present build",
"build:cjs": "rollup --config rollup.cjs.config.mjs",
"build:esm": "rollup --config rollup.esm.config.mjs",
"build:script": "node build.mjs",
"postbuild": "npm run --workspaces --if-present build",
"clean": "rm -rf dist public",
"codegen": "node scripts/codegen.cjs",
"compatibility": "scripts/compatibility.sh",
......@@ -234,32 +234,32 @@
},
"devDependencies": {
"@babel/code-frame": "7.26.2",
"@html-validate/commitlint-config": "3.4.2",
"@html-validate/eslint-config": "5.27.0",
"@html-validate/eslint-config-jest": "5.27.0",
"@html-validate/eslint-config-typescript": "5.27.0",
"@html-validate/eslint-config-typescript-typeinfo": "5.27.0",
"@html-validate/commitlint-config": "3.4.3",
"@html-validate/eslint-config": "5.28.1",
"@html-validate/eslint-config-jest": "5.28.0",
"@html-validate/eslint-config-typescript": "5.28.1",
"@html-validate/eslint-config-typescript-typeinfo": "5.28.1",
"@html-validate/jest-config": "3.12.0",
"@html-validate/prettier-config": "2.5.14",
"@html-validate/prettier-config": "2.5.15",
"@html-validate/release-scripts": "6.8.0",
"@html-validate/rollup-plugin-legacy": "file:internal/rollup-plugin-legacy",
"@html-validate/rollup-plugin-packagejson": "file:internal/rollup-plugin-packagejson",
"@microsoft/api-extractor": "7.51.1",
"@microsoft/api-extractor": "7.52.1",
"@rollup/plugin-commonjs": "28.0.3",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-node-resolve": "16.0.0",
"@rollup/plugin-node-resolve": "16.0.1",
"@rollup/plugin-replace": "6.0.2",
"@rollup/plugin-virtual": "3.0.2",
"@types/babar": "0.2.4",
"@types/babel__code-frame": "7.0.6",
"@types/jest": "29.5.14",
"@types/minimist": "1.2.5",
"@types/node": "18.19.79",
"@types/node": "18.19.80",
"@types/prompts": "2.4.9",
"@types/semver": "7.5.8",
"@types/stream-buffers": "3.0.7",
"babar": "0.2.3",
"esbuild": "0.25.0",
"esbuild": "0.25.1",
"husky": "9.1.7",
"is-ci": "4.1.0",
"jest": "29.7.0",
......@@ -271,7 +271,7 @@
"memfs": "4.17.0",
"npm-pkg-lint": "3.10.11",
"npm-run-all2": "7.0.2",
"rollup": "4.34.9",
"rollup": "4.35.0",
"rollup-plugin-esbuild": "6.2.1",
"stream-buffers": "3.0.3",
"ts-jest": "29.2.6",
......
......@@ -6,6 +6,35 @@ exports[`regression tests test-files/issues/issue-138-srcset-line-wrapping.html
exports[`regression tests test-files/issues/issue-154-case-insensitive-attr.html 1`] = `[]`;
exports[`regression tests test-files/issues/issue-299-comma-id.html 1`] = `
[
{
"errorCount": 1,
"filePath": "test-files/issues/issue-299-comma-id.html",
"messages": [
{
"column": 10,
"context": {
"id": "start,-end",
"kind": 4,
},
"line": 1,
"message": "element id "start,-end" must only contain letters, digits, dash and underscore characters",
"offset": 9,
"ruleId": "valid-id",
"ruleUrl": "https://html-validate.org/rules/valid-id.html",
"selector": "#start\\,-end",
"severity": 2,
"size": 10,
},
],
"source": "<div id="start,-end"></div>
",
"warningCount": 0,
},
]
`;
exports[`regression tests test-files/issues/issue27-disable-block.html 1`] = `[]`;
exports[`regression tests test-files/issues/issue35-dynamic-values.html 1`] = `[]`;
......
......@@ -989,6 +989,17 @@ describe("HtmlElement", () => {
expect(el.map((it) => it.id)).toEqual(["third"]);
});
it("should handle escaped comma", async () => {
expect.assertions(2);
const markup = /* HTML */ ` <div id="foo,bar"></div> `;
const resolvedConfig = await Config.empty().resolve();
const parser = new Parser(resolvedConfig);
const document = parser.parseHtml(markup);
const el = document.querySelector("#foo\\,bar");
expect(el?.tagName).toBe("div");
expect(el?.id).toBe("foo,bar");
});
it("should return null if nothing matches", () => {
expect.assertions(1);
const el = document.querySelector("foobar");
......@@ -1025,6 +1036,18 @@ describe("HtmlElement", () => {
expect(el[2].tagName).toBe("p");
});
it("should handle escaped comma", async () => {
expect.assertions(3);
const markup = /* HTML */ ` <div id="foo,bar"></div> `;
const resolvedConfig = await Config.empty().resolve();
const parser = new Parser(resolvedConfig);
const document = parser.parseHtml(markup);
const el = document.querySelectorAll("#foo\\,bar");
expect(el).toHaveLength(1);
expect(el[0].tagName).toBe("div");
expect(el[0].id).toBe("foo,bar");
});
it("should return [] when nothing matches", () => {
expect.assertions(1);
const el = document.querySelectorAll("missing");
......
......@@ -652,7 +652,7 @@ export class HtmlElement extends DOMNode {
if (!selectorList) {
return;
}
for (const selector of selectorList.split(/,\s*/)) {
for (const selector of selectorList.split(/(?<!\\),\s*/)) {
const pattern = new Selector(selector);
yield* pattern.match(this);
}
......
......@@ -168,6 +168,12 @@ describe("generateIdSelector()", () => {
const id = "123foo";
expect(generateIdSelector(id)).toBe('[id="123foo"]');
});
it("should handle comma", () => {
expect.assertions(1);
const id = "foo,bar";
expect(generateIdSelector(id)).toBe("#foo\\,bar");
});
});
describe("Selector", () => {
......
......@@ -23,14 +23,14 @@ function isSourceHooks(value: any): value is SourceHooks {
if (!value || typeof value === "string") {
return false;
}
return Boolean(value.processAttribute || value.processElement);
return Boolean(value.processAttribute ?? value.processElement);
}
function isConfigData(value: any): value is ConfigData {
if (!value || typeof value === "string") {
return false;
}
return !(value.processAttribute || value.processElement);
return !(value.processAttribute ?? value.processElement);
}
/**
......
......@@ -28,14 +28,14 @@ function isSourceHooks(value: any): value is SourceHooks {
if (!value || typeof value === "string") {
return false;
}
return Boolean(value.processAttribute || value.processElement);
return Boolean(value.processAttribute ?? value.processElement);
}
function isConfigData(value: any): value is ConfigData {
if (!value || typeof value === "string") {
return false;
}
return !(value.processAttribute || value.processElement);
return !(value.processAttribute ?? value.processElement);
}
/**
......
......@@ -16,14 +16,14 @@ function isMessage(arg: any): arg is Partial<Message> {
return false;
}
return Boolean(
arg.ruleId ||
arg.severity ||
arg.message ||
arg.offset ||
arg.line ||
arg.column ||
arg.size ||
arg.selector ||
arg.ruleId ??
arg.severity ??
arg.message ??
arg.offset ??
arg.line ??
arg.column ??
arg.size ??
arg.selector ??
arg.context,
);
}
......@@ -33,7 +33,7 @@ function isConfig(arg: any): arg is ConfigData {
return false;
}
return Boolean(
arg.root || arg.extends || arg.elements || arg.plugin || arg.transform || arg.rules,
arg.root ?? arg.extends ?? arg.elements ?? arg.plugin ?? arg.transform ?? arg.rules,
);
}
......
<div id="start,-end"></div>
{
"rules": {
"import/named": "off",
"import/no-unresolved": "off"
}
}