@html-validate/plugin-template 0.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/files/CHANGELOG.md +23 -0
- package/files/LICENSE +20 -0
- package/files/README.md +11 -0
- package/files/_editorconfig +20 -0
- package/files/_gitignore +9 -0
- package/files/_gitlab-ci.yml +117 -0
- package/files/_htmlvalidate.mjs +9 -0
- package/files/_npmrc +3 -0
- package/files/_prettierignore +9 -0
- package/files/build.mjs +37 -0
- package/files/eslint.config.mjs +37 -0
- package/files/package.json +117 -0
- package/files/renovate.json +3 -0
- package/files/src/__snapshots__/elements.spec.ts.snap +71 -0
- package/files/src/configs/index.ts +5 -0
- package/files/src/configs/recommended.ts +13 -0
- package/files/src/elements.spec.ts +49 -0
- package/files/src/elements.ts +13 -0
- package/files/src/entry-cjs.ts +5 -0
- package/files/src/entry-esm.ts +3 -0
- package/files/src/index.ts +17 -0
- package/files/src/rules/custom-rule.spec.ts +61 -0
- package/files/src/rules/custom-rule.ts +24 -0
- package/files/src/rules/index.ts +7 -0
- package/files/test/htmlvalidate.spec.ts +40 -0
- package/files/test-files/elements/custom-component-invalid.html +8 -0
- package/files/test-files/elements/custom-component-valid.html +1 -0
- package/files/test-files/smoketest.html +1 -0
- package/files/tsconfig.cjs.json +8 -0
- package/files/tsconfig.esm.json +10 -0
- package/files/tsconfig.json +16 -0
- package/index.js +15 -0
- package/package.json +75 -6
- package/README.md +0 -45
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @html-validate/plugin-template changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.2 (2026-06-25)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- **deps:** update cloneman to v1.18.1 ([881c389](https://gitlab.com/html-validate/plugin-template/commit/881c3893e2cf5323c83e7658f1b4883a8c262be6))
|
|
8
|
+
|
|
9
|
+
## 1.0.1 (2026-06-21)
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- ignore eslint and prettier dependencies ([1f49d2a](https://gitlab.com/html-validate/plugin-template/commit/1f49d2a5964150df02342dbf22a0090bb2eb68e1))
|
|
14
|
+
|
|
15
|
+
## 1.0.0 (2026-06-21)
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
- initial version ([1ac7862](https://gitlab.com/html-validate/plugin-template/commit/1ac786208f5f0f91b7d0f0f8bee6d9ff52e23062))
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
- no need to rerun test-files ([e7a7391](https://gitlab.com/html-validate/plugin-template/commit/e7a73910ee1e2b077e0f076e6fa236e295c7c26a))
|
package/files/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018-2026 David Sveningsson <ext@sidvind.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/files/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# @html-validate/plugin-template
|
|
2
|
+
|
|
3
|
+
[Cloneman] template for [HTML-Validate][html-validate] plugins.
|
|
4
|
+
|
|
5
|
+
[cloneman]: https://github.com/Forsakringskassan/cloneman
|
|
6
|
+
[html-validate]: https://www.npmjs.com/package/html-validate
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
npx cloneman create awesome-plugin @html-validate/plugin-template
|
|
11
|
+
npx cloneman update
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# EditorConfig: http://EditorConfig.org
|
|
2
|
+
#
|
|
3
|
+
# This file is managed by "@html-validate/plugin-template".
|
|
4
|
+
# Changes will be overwritten.
|
|
5
|
+
|
|
6
|
+
root = true
|
|
7
|
+
|
|
8
|
+
[*]
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
trim_trailing_whitespace = true
|
|
11
|
+
indent_style = tab
|
|
12
|
+
charset = utf-8
|
|
13
|
+
|
|
14
|
+
[*.json]
|
|
15
|
+
indent_style = space
|
|
16
|
+
indent_size = 2
|
|
17
|
+
|
|
18
|
+
[*.yml]
|
|
19
|
+
indent_style = space
|
|
20
|
+
indent_size = 2
|
package/files/_gitignore
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
image: node:24
|
|
2
|
+
|
|
3
|
+
include:
|
|
4
|
+
- component: $CI_SERVER_FQDN/html-validate/gitlab-ci/release@master
|
|
5
|
+
inputs:
|
|
6
|
+
legacy: false
|
|
7
|
+
on-push: true
|
|
8
|
+
|
|
9
|
+
stages:
|
|
10
|
+
- prepare
|
|
11
|
+
- test
|
|
12
|
+
- build
|
|
13
|
+
- compatibility
|
|
14
|
+
- release
|
|
15
|
+
|
|
16
|
+
NPM:
|
|
17
|
+
stage: prepare
|
|
18
|
+
artifacts:
|
|
19
|
+
name: ${CI_PROJECT_PATH_SLUG}-${CI_PIPELINE_ID}-npm
|
|
20
|
+
paths:
|
|
21
|
+
- node_modules/
|
|
22
|
+
- packages/*/node_modules/
|
|
23
|
+
reports:
|
|
24
|
+
dependency_scanning: gl-dependency-scanning.json
|
|
25
|
+
script:
|
|
26
|
+
- node --version
|
|
27
|
+
- npm --version
|
|
28
|
+
- npm ci --no-fund --no-audit --no-update-notifier
|
|
29
|
+
- npm audit --json --production | npx --yes gitlab-npm-audit-parser -o gl-dependency-scanning.json || true
|
|
30
|
+
- test -z "${UPSTREAM_VERSION}" || npm install "html-validate@${UPSTREAM_VERSION}"
|
|
31
|
+
|
|
32
|
+
ESLint:
|
|
33
|
+
stage: test
|
|
34
|
+
script:
|
|
35
|
+
- npm exec eslint-config -- --check
|
|
36
|
+
- npm run eslint -- --max-warnings 0
|
|
37
|
+
|
|
38
|
+
Jest:
|
|
39
|
+
stage: test
|
|
40
|
+
coverage: /Branches\s+:\s(\d+.\d+%)/
|
|
41
|
+
artifacts:
|
|
42
|
+
name: ${CI_PROJECT_PATH_SLUG}-${CI_PIPELINE_ID}-coverage
|
|
43
|
+
paths:
|
|
44
|
+
- coverage
|
|
45
|
+
reports:
|
|
46
|
+
junit: temp/jest.xml
|
|
47
|
+
before_script:
|
|
48
|
+
- npm run --if-present build
|
|
49
|
+
script:
|
|
50
|
+
- npm test
|
|
51
|
+
|
|
52
|
+
Prettier:
|
|
53
|
+
stage: test
|
|
54
|
+
script:
|
|
55
|
+
- npm run prettier:check
|
|
56
|
+
|
|
57
|
+
attw:
|
|
58
|
+
stage: test
|
|
59
|
+
needs: []
|
|
60
|
+
script:
|
|
61
|
+
- npm ci
|
|
62
|
+
- npm run build
|
|
63
|
+
- npm run attw
|
|
64
|
+
|
|
65
|
+
Build:
|
|
66
|
+
stage: build
|
|
67
|
+
needs:
|
|
68
|
+
- NPM
|
|
69
|
+
dependencies:
|
|
70
|
+
- NPM
|
|
71
|
+
artifacts:
|
|
72
|
+
name: ${CI_PROJECT_PATH_SLUG}-${CI_PIPELINE_ID}-build
|
|
73
|
+
paths:
|
|
74
|
+
- dist
|
|
75
|
+
script:
|
|
76
|
+
- npm run --if-present build
|
|
77
|
+
- node dist/cjs/index.cjs
|
|
78
|
+
- node dist/esm/index.mjs
|
|
79
|
+
- npm pack
|
|
80
|
+
- npm exec npm-pkg-lint
|
|
81
|
+
|
|
82
|
+
.compat: &compat
|
|
83
|
+
stage: compatibility
|
|
84
|
+
dependencies:
|
|
85
|
+
- NPM
|
|
86
|
+
- Build
|
|
87
|
+
needs:
|
|
88
|
+
- NPM
|
|
89
|
+
- Build
|
|
90
|
+
script:
|
|
91
|
+
- for spec in test/*.spec.ts; do sed 's#../src#../dist/cjs/index.cjs#g' -i "${spec}"; done
|
|
92
|
+
- sed '/dist/s#jest.mock#//#' -i "test/htmlvalidate.spec.ts"
|
|
93
|
+
- npm test -- --no-coverage test
|
|
94
|
+
|
|
95
|
+
Node:
|
|
96
|
+
extends: .compat
|
|
97
|
+
parallel:
|
|
98
|
+
matrix:
|
|
99
|
+
- VERSION:
|
|
100
|
+
- 22
|
|
101
|
+
- 24
|
|
102
|
+
image: "node:${VERSION}"
|
|
103
|
+
|
|
104
|
+
HTML-validate:
|
|
105
|
+
extends: .compat
|
|
106
|
+
parallel:
|
|
107
|
+
matrix:
|
|
108
|
+
- VERSION:
|
|
109
|
+
- 8
|
|
110
|
+
- 9
|
|
111
|
+
- 10
|
|
112
|
+
- 11
|
|
113
|
+
before_script:
|
|
114
|
+
- test ${VERSION} -lt 10 && npm install jest@29 jest-environment-jsdom@29 jest-snapshot@29 jest-diff@29 jest-runtime@29 @types/jest@29
|
|
115
|
+
- npm install $(npx -y npm-min-peer html-validate --major ${VERSION} --with-name)
|
|
116
|
+
- npm ls html-validate
|
|
117
|
+
- npm ls jest
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* This file is managed by "@html-validate/plugin-template". Changes will be overwritten */
|
|
2
|
+
|
|
3
|
+
import Plugin from "./dist/esm/index.mjs";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
plugins: [Plugin],
|
|
7
|
+
extends: ["html-validate:recommended", `${Plugin.name}:recommended`],
|
|
8
|
+
elements: ["html5"],
|
|
9
|
+
};
|
package/files/_npmrc
ADDED
package/files/build.mjs
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* This file is managed by "@html-validate/plugin-template". Changes will be overwritten */
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import { analyzeMetafile, build as esbuild } from "esbuild";
|
|
5
|
+
|
|
6
|
+
const entrypoint = {
|
|
7
|
+
cjs: "src/entry-cjs.ts",
|
|
8
|
+
esm: "src/entry-esm.ts",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const extension = {
|
|
12
|
+
cjs: ".cjs",
|
|
13
|
+
esm: ".mjs",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
await fs.rm("dist", { recursive: true, force: true });
|
|
17
|
+
|
|
18
|
+
for (const format of ["cjs", "esm"]) {
|
|
19
|
+
const result = await esbuild({
|
|
20
|
+
entryPoints: [{ in: entrypoint[format], out: "index" }],
|
|
21
|
+
outdir: `dist/${format}`,
|
|
22
|
+
bundle: true,
|
|
23
|
+
platform: "node",
|
|
24
|
+
format,
|
|
25
|
+
target: "node22",
|
|
26
|
+
logLevel: "info",
|
|
27
|
+
sourcemap: true,
|
|
28
|
+
metafile: true,
|
|
29
|
+
outExtension: {
|
|
30
|
+
".js": extension[format],
|
|
31
|
+
},
|
|
32
|
+
external: ["@html-validate/plugin-utils", "html-validate"],
|
|
33
|
+
});
|
|
34
|
+
if (format === "esm") {
|
|
35
|
+
console.log(await analyzeMetafile(result.metafile));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* This file is managed by @html-validate/eslint-config */
|
|
2
|
+
/* Changes may be overwritten */
|
|
3
|
+
|
|
4
|
+
import defaultConfig from "@html-validate/eslint-config";
|
|
5
|
+
import jestConfig from "@html-validate/eslint-config-jest";
|
|
6
|
+
import typescriptConfig from "@html-validate/eslint-config-typescript";
|
|
7
|
+
import typescriptTypeinfoConfig from "@html-validate/eslint-config-typescript-typeinfo";
|
|
8
|
+
|
|
9
|
+
export default [
|
|
10
|
+
...defaultConfig({ type: "commonjs" }),
|
|
11
|
+
|
|
12
|
+
{
|
|
13
|
+
name: "@html-validate/eslint-config-typescript",
|
|
14
|
+
files: ["**/*.{ts,cts,mts}"],
|
|
15
|
+
...typescriptConfig,
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
{
|
|
19
|
+
name: "@html-validate/eslint-config-typeinfo",
|
|
20
|
+
files: ["src/**/*.{ts,cts,mts}"],
|
|
21
|
+
ignores: ["src/**/*.spec.ts"],
|
|
22
|
+
languageOptions: {
|
|
23
|
+
parserOptions: {
|
|
24
|
+
tsconfigRootDir: import.meta.dirname,
|
|
25
|
+
projectService: true,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
...typescriptTypeinfoConfig,
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
name: "@html-validate/eslint-config-jest",
|
|
33
|
+
files: ["**/*.spec.[jt]s"],
|
|
34
|
+
ignores: ["cypress/**", "tests/e2e/**"],
|
|
35
|
+
...jestConfig,
|
|
36
|
+
},
|
|
37
|
+
];
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "${name}",
|
|
3
|
+
"version": "${version}",
|
|
4
|
+
"description": "${description}",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cloneman",
|
|
7
|
+
"html-validate"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://gitlab.com/html-validate/plugin-template",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://gitlab.com/html-validate/plugin-template/-/work_items/new?type=Issue"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://gitlab.com/html-validate/plugin-template.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "David Sveningsson <ext@sidvind.com>",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/esm/index.d.mts",
|
|
23
|
+
"default": "./dist/esm/index.mjs"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/cjs/index.d.cts",
|
|
27
|
+
"default": "./dist/cjs/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"main": "dist/cjs/index.cjs",
|
|
32
|
+
"module": "dist/esm/index.mjs",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"prebuild": "tsc",
|
|
38
|
+
"build": "run-s build:*",
|
|
39
|
+
"postbuild": "cloneman build -o temp/cloneman",
|
|
40
|
+
"build:lib": "node build.mjs",
|
|
41
|
+
"build:cjs": "dts-bundle-generator --no-banner --project tsconfig.cjs.json -o dist/cjs/index.d.cts src/entry-cjs.ts",
|
|
42
|
+
"build:esm": "dts-bundle-generator --no-banner --project tsconfig.esm.json -o dist/esm/index.d.mts src/entry-esm.ts",
|
|
43
|
+
"eslint": "eslint --cache .",
|
|
44
|
+
"eslint:fix": "eslint --cache --fix .",
|
|
45
|
+
"prepack": "release-prepack package.json --bundle",
|
|
46
|
+
"postpack": "release-postpack package.json",
|
|
47
|
+
"prepare": "husky",
|
|
48
|
+
"prepublishOnly": "release-prepack package.json --bundle",
|
|
49
|
+
"prettier:check": "prettier --check .",
|
|
50
|
+
"prettier:write": "prettier --write .",
|
|
51
|
+
"postpublish": "release-postpack package.json",
|
|
52
|
+
"attw": "attw --no-emoji --pack .",
|
|
53
|
+
"test": "jest"
|
|
54
|
+
},
|
|
55
|
+
"commitlint": {
|
|
56
|
+
"extends": "@html-validate"
|
|
57
|
+
},
|
|
58
|
+
"prettier": "@html-validate/prettier-config",
|
|
59
|
+
"release": {
|
|
60
|
+
"extends": "@html-validate/semantic-release-cloneman-config"
|
|
61
|
+
},
|
|
62
|
+
"jest": {
|
|
63
|
+
"preset": "@html-validate/jest-config"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"@html-validate/plugin-utils": "^4.0.0"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@arethetypeswrong/cli": "0.18.4",
|
|
70
|
+
"@html-validate/commitlint-config": "4.0.3",
|
|
71
|
+
"@html-validate/eslint-config": "9.8.2",
|
|
72
|
+
"@html-validate/eslint-config-jest": "9.8.0",
|
|
73
|
+
"@html-validate/eslint-config-typescript": "9.8.0",
|
|
74
|
+
"@html-validate/eslint-config-typescript-typeinfo": "9.8.0",
|
|
75
|
+
"@html-validate/jest-config": "3.18.2",
|
|
76
|
+
"@html-validate/plugin-template": "1.0.2",
|
|
77
|
+
"@html-validate/prettier-config": "4.1.1",
|
|
78
|
+
"@html-validate/release-scripts": "7.3.1",
|
|
79
|
+
"@jest/globals": "30.4.1",
|
|
80
|
+
"@tsconfig/node22": "22.0.5",
|
|
81
|
+
"@tsconfig/strictest": "2.0.8",
|
|
82
|
+
"@types/estree": "1.0.9",
|
|
83
|
+
"@types/node": "22.20.0",
|
|
84
|
+
"@types/semver": "7.7.1",
|
|
85
|
+
"cloneman": "1.18.1",
|
|
86
|
+
"dts-bundle-generator": "9.5.1",
|
|
87
|
+
"esbuild": "0.28.1",
|
|
88
|
+
"html-validate": "11.5.3",
|
|
89
|
+
"husky": "9.1.7",
|
|
90
|
+
"jest": "30.4.2",
|
|
91
|
+
"jest-environment-jsdom": "30.4.1",
|
|
92
|
+
"npm-pkg-lint": "5.1.8",
|
|
93
|
+
"npm-run-all2": "9.0.2",
|
|
94
|
+
"semver": "7.8.5",
|
|
95
|
+
"ts-jest": "29.4.11",
|
|
96
|
+
"typescript": "6.0.3"
|
|
97
|
+
},
|
|
98
|
+
"peerDependencies": {
|
|
99
|
+
"html-validate": "^8.21.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
|
|
100
|
+
},
|
|
101
|
+
"engines": {
|
|
102
|
+
"node": "^22.16 || >= 24"
|
|
103
|
+
},
|
|
104
|
+
"allowScripts": {
|
|
105
|
+
"@html-validate/commitlint-config": true,
|
|
106
|
+
"esbuild": true,
|
|
107
|
+
"fsevents": false,
|
|
108
|
+
"unrs-resolver": true
|
|
109
|
+
},
|
|
110
|
+
"cloneman": {
|
|
111
|
+
"template": "@html-validate/plugin-template",
|
|
112
|
+
"version": "1.0.2"
|
|
113
|
+
},
|
|
114
|
+
"externalDependencies": [
|
|
115
|
+
"@html-validate/plugin-utils"
|
|
116
|
+
]
|
|
117
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
|
2
|
+
|
|
3
|
+
exports[`HTML elements <custom-component> invalid markup 1`] = `
|
|
4
|
+
[
|
|
5
|
+
{
|
|
6
|
+
"errorCount": 3,
|
|
7
|
+
"filePath": "test-files/elements/custom-component-invalid.html",
|
|
8
|
+
"messages": [
|
|
9
|
+
{
|
|
10
|
+
"column": 2,
|
|
11
|
+
"context": {
|
|
12
|
+
"attr": "value",
|
|
13
|
+
"tagName": "<custom-component>",
|
|
14
|
+
},
|
|
15
|
+
"line": 2,
|
|
16
|
+
"message": "<custom-component> is missing required "value" attribute",
|
|
17
|
+
"offset": 43,
|
|
18
|
+
"ruleId": "element-required-attributes",
|
|
19
|
+
"ruleUrl": "https://html-validate.org/rules/element-required-attributes.html",
|
|
20
|
+
"selector": "custom-component:nth-child(1)",
|
|
21
|
+
"severity": 2,
|
|
22
|
+
"size": 16,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"column": 26,
|
|
26
|
+
"context": {
|
|
27
|
+
"allowed": {
|
|
28
|
+
"enum": [
|
|
29
|
+
"yes",
|
|
30
|
+
"no",
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
"attribute": "value",
|
|
34
|
+
"element": "custom-component",
|
|
35
|
+
"value": "invalid",
|
|
36
|
+
},
|
|
37
|
+
"line": 5,
|
|
38
|
+
"message": "Attribute "value" has invalid value "invalid"",
|
|
39
|
+
"offset": 139,
|
|
40
|
+
"ruleId": "attribute-allowed-values",
|
|
41
|
+
"ruleUrl": "https://html-validate.org/rules/attribute-allowed-values.html",
|
|
42
|
+
"selector": "custom-component:nth-child(2)",
|
|
43
|
+
"severity": 2,
|
|
44
|
+
"size": 7,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"column": 2,
|
|
48
|
+
"line": 8,
|
|
49
|
+
"message": "lorem ipsum",
|
|
50
|
+
"offset": 212,
|
|
51
|
+
"ruleId": "awesome-plugin/custom-rule",
|
|
52
|
+
"selector": "custom-component:nth-child(3)",
|
|
53
|
+
"severity": 2,
|
|
54
|
+
"size": 16,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
"source": "<!-- missing required value attribute -->
|
|
58
|
+
<custom-component></custom-component>
|
|
59
|
+
|
|
60
|
+
<!-- invalid value attribute -->
|
|
61
|
+
<custom-component value="invalid"></custom-component>
|
|
62
|
+
|
|
63
|
+
<!-- custom rule disallows value "no" -->
|
|
64
|
+
<custom-component value="no"></custom-component>
|
|
65
|
+
",
|
|
66
|
+
"warningCount": 0,
|
|
67
|
+
},
|
|
68
|
+
]
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
exports[`HTML elements <custom-component> valid markup 1`] = `[]`;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ConfigData } from "html-validate";
|
|
2
|
+
import elements from "../elements";
|
|
3
|
+
|
|
4
|
+
export function createConfig(): ConfigData {
|
|
5
|
+
return {
|
|
6
|
+
elements: [elements],
|
|
7
|
+
rules: {
|
|
8
|
+
"awesome-plugin/custom-rule": "error",
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default createConfig();
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { describe, expect, it } from "@jest/globals";
|
|
3
|
+
import { type Report, HtmlValidate } from "html-validate";
|
|
4
|
+
import metadata from "./elements";
|
|
5
|
+
import Plugin from "./index";
|
|
6
|
+
|
|
7
|
+
const rootDir = path.resolve(__dirname, "..");
|
|
8
|
+
const fileDirectory = path.join(rootDir, "test-files/elements");
|
|
9
|
+
const tagNames = Object.keys(metadata).filter((it) => it !== "*");
|
|
10
|
+
|
|
11
|
+
const htmlvalidate = new HtmlValidate({
|
|
12
|
+
root: true,
|
|
13
|
+
plugins: [Plugin],
|
|
14
|
+
extends: ["html-validate:recommended", `${Plugin.name}:recommended`],
|
|
15
|
+
elements: ["html5"],
|
|
16
|
+
rules: {
|
|
17
|
+
"no-unknown-attributes": "error",
|
|
18
|
+
"no-unknown-elements": "error",
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function normalizePath(report: Report): void {
|
|
23
|
+
for (const result of report.results) {
|
|
24
|
+
result.filePath = path.relative(rootDir, result.filePath);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe("HTML elements", () => {
|
|
29
|
+
for (const tagName of tagNames) {
|
|
30
|
+
const slug = tagName.replace(":", "_");
|
|
31
|
+
const filename = (variant: string): string => `${fileDirectory}/${slug}-${variant}.html`;
|
|
32
|
+
|
|
33
|
+
describe(`<${tagName}>`, () => {
|
|
34
|
+
it("valid markup", async () => {
|
|
35
|
+
expect.assertions(1);
|
|
36
|
+
const report = await htmlvalidate.validateFile(filename("valid"));
|
|
37
|
+
normalizePath(report);
|
|
38
|
+
expect(report.results).toMatchSnapshot();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("invalid markup", async () => {
|
|
42
|
+
expect.assertions(1);
|
|
43
|
+
const report = await htmlvalidate.validateFile(filename("invalid"));
|
|
44
|
+
normalizePath(report);
|
|
45
|
+
expect(report.results).toMatchSnapshot();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Plugin, compatibilityCheck } from "html-validate";
|
|
2
|
+
import { name, peerDependencies } from "../package.json";
|
|
3
|
+
import configs from "./configs";
|
|
4
|
+
import rules from "./rules";
|
|
5
|
+
|
|
6
|
+
const range = peerDependencies["html-validate"];
|
|
7
|
+
|
|
8
|
+
/* eslint-disable-next-line unicorn/no-top-level-side-effects -- intentional side-effect */
|
|
9
|
+
compatibilityCheck(name, range);
|
|
10
|
+
|
|
11
|
+
const plugin: Plugin = {
|
|
12
|
+
name,
|
|
13
|
+
configs,
|
|
14
|
+
rules,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default plugin;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from "@jest/globals";
|
|
2
|
+
import { ConfigData, FileSystemConfigLoader, HtmlValidate } from "html-validate";
|
|
3
|
+
import "html-validate/jest";
|
|
4
|
+
import Plugin from "..";
|
|
5
|
+
|
|
6
|
+
const config: ConfigData = {
|
|
7
|
+
root: true,
|
|
8
|
+
plugins: [Plugin],
|
|
9
|
+
rules: { "awesome-plugin/custom-rule": "error" },
|
|
10
|
+
};
|
|
11
|
+
const loader = new FileSystemConfigLoader(config);
|
|
12
|
+
|
|
13
|
+
describe("awesome-plugin/custom-rule", () => {
|
|
14
|
+
let htmlvalidate: HtmlValidate;
|
|
15
|
+
|
|
16
|
+
beforeAll(() => {
|
|
17
|
+
htmlvalidate = new HtmlValidate(loader);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should not report error for other elements", async () => {
|
|
21
|
+
expect.assertions(1);
|
|
22
|
+
const markup = /* HTML */ ` <input value="no" /> `;
|
|
23
|
+
const report = await htmlvalidate.validateString(markup);
|
|
24
|
+
expect(report).toBeValid();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should not report error when <custom-component> omits value", async () => {
|
|
28
|
+
expect.assertions(1);
|
|
29
|
+
const markup = /* HTML */ ` <custom-component></custom-component> `;
|
|
30
|
+
const report = await htmlvalidate.validateString(markup);
|
|
31
|
+
expect(report).toBeValid();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should not report error when <custom-component> uses positive value", async () => {
|
|
35
|
+
expect.assertions(1);
|
|
36
|
+
const markup = /* HTML */ ` <custom-component value="yes"></custom-component> `;
|
|
37
|
+
const report = await htmlvalidate.validateString(markup);
|
|
38
|
+
expect(report).toBeValid();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should report error when <custom-component> uses negative value", async () => {
|
|
42
|
+
expect.assertions(2);
|
|
43
|
+
const markup = /* HTML */ ` <custom-component value="no"></custom-component> `;
|
|
44
|
+
const report = await htmlvalidate.validateString(markup);
|
|
45
|
+
expect(report).toBeInvalid();
|
|
46
|
+
expect(report).toMatchInlineCodeframe(`
|
|
47
|
+
"error: lorem ipsum (awesome-plugin/custom-rule)
|
|
48
|
+
> 1 | <custom-component value="no"></custom-component>
|
|
49
|
+
| ^^^^^^^^^^^^^^^^
|
|
50
|
+
Selector: custom-component"
|
|
51
|
+
`);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should contain documentation", async () => {
|
|
55
|
+
expect.assertions(1);
|
|
56
|
+
const docs = await htmlvalidate.getContextualDocumentation({
|
|
57
|
+
ruleId: "awesome-plugin/custom-rule",
|
|
58
|
+
});
|
|
59
|
+
expect(docs?.description).toMatchInlineSnapshot(`"Lorem ipsum dolor sit amet."`);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type RuleDocumentation, Rule } from "html-validate";
|
|
2
|
+
|
|
3
|
+
export class CustomRule extends Rule {
|
|
4
|
+
public override documentation(): RuleDocumentation {
|
|
5
|
+
return {
|
|
6
|
+
description: "Lorem ipsum dolor sit amet.",
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public setup(): void {
|
|
11
|
+
this.on("dom:ready", (event) => {
|
|
12
|
+
const { document } = event;
|
|
13
|
+
for (const node of document.querySelectorAll("custom-component")) {
|
|
14
|
+
const attr = node.getAttribute("value");
|
|
15
|
+
if (attr?.value === "no") {
|
|
16
|
+
this.report({
|
|
17
|
+
node,
|
|
18
|
+
message: "lorem ipsum",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* eslint-disable jest/no-conditional-expect, jest/no-conditional-in-test -- needed to handle backwards compatibility, we use expect.assertions(N) to ensure the right number of expectations have run */
|
|
2
|
+
|
|
3
|
+
import { expect, it } from "@jest/globals";
|
|
4
|
+
import { ConfigData, FileSystemConfigLoader, HtmlValidate, version } from "html-validate";
|
|
5
|
+
import "html-validate/jest";
|
|
6
|
+
import { gtr } from "semver";
|
|
7
|
+
import Plugin from "../src";
|
|
8
|
+
|
|
9
|
+
const config: ConfigData = {
|
|
10
|
+
root: true,
|
|
11
|
+
plugins: [Plugin],
|
|
12
|
+
extends: ["html-validate:recommended", `${Plugin.name}:recommended`],
|
|
13
|
+
elements: ["html5"],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const loader = new FileSystemConfigLoader(config);
|
|
17
|
+
|
|
18
|
+
it('should find errors in "smoketest.html"', async () => {
|
|
19
|
+
expect.assertions(2);
|
|
20
|
+
const htmlvalidate = new HtmlValidate(loader);
|
|
21
|
+
const report = await htmlvalidate.validateFile("test-files/smoketest.html");
|
|
22
|
+
expect(report.valid).toBeFalsy();
|
|
23
|
+
if (gtr(version, "10.12.0")) {
|
|
24
|
+
expect(report).toMatchInlineCodeframe(`
|
|
25
|
+
"error: lorem ipsum (awesome-plugin/custom-rule)
|
|
26
|
+
> 1 | <custom-component value="no"></custom-component>
|
|
27
|
+
| ^^^^^^^^^^^^^^^^
|
|
28
|
+
2 |
|
|
29
|
+
Selector: custom-component"
|
|
30
|
+
`);
|
|
31
|
+
} else {
|
|
32
|
+
expect(report).toMatchInlineCodeframe(`
|
|
33
|
+
"error: lorem ipsum (awesome-plugin/custom-rule) at test-files/smoketest.html:1:2:
|
|
34
|
+
> 1 | <custom-component value="no"></custom-component>
|
|
35
|
+
| ^^^^^^^^^^^^^^^^
|
|
36
|
+
2 |
|
|
37
|
+
Selector: custom-component"
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!-- missing required value attribute -->
|
|
2
|
+
<custom-component></custom-component>
|
|
3
|
+
|
|
4
|
+
<!-- invalid value attribute -->
|
|
5
|
+
<custom-component value="invalid"></custom-component>
|
|
6
|
+
|
|
7
|
+
<!-- custom rule disallows value "no" -->
|
|
8
|
+
<custom-component value="no"></custom-component>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<custom-component value="yes"></custom-component>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<custom-component value="no"></custom-component>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* This file is managed by "@html-validate/plugin-template". Changes will be overwritten */
|
|
2
|
+
|
|
3
|
+
{
|
|
4
|
+
"extends": ["@tsconfig/node22", "@tsconfig/strictest"],
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"rootDir": ".",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"types": ["node"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*.ts", "test/**/*.ts"],
|
|
15
|
+
"exclude": ["node_modules"]
|
|
16
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
const packageJsonFile = await fs.readFile(path.join(import.meta.dirname, "package.json"), "utf8");
|
|
6
|
+
const packageJson = JSON.parse(packageJsonFile);
|
|
7
|
+
|
|
8
|
+
const options = {
|
|
9
|
+
...packageJson.cloneman,
|
|
10
|
+
filesDir: path.join(import.meta.dirname, "files"),
|
|
11
|
+
hooksDir: path.join(import.meta.dirname, "hooks"),
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default options;
|
|
15
|
+
|
package/package.json
CHANGED
|
@@ -1,10 +1,79 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@html-validate/plugin-template",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "cloneman template for html-validate plugins",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
"cloneman",
|
|
7
|
+
"html-validate"
|
|
8
|
+
],
|
|
9
|
+
"homepage": "https://gitlab.com/html-validate/plugin-template",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://gitlab.com/html-validate/plugin-template/-/work_items/new?type=Issue"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://gitlab.com/html-validate/plugin-template.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "David Sveningsson <ext@sidvind.com>",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./index.js"
|
|
22
|
+
},
|
|
23
|
+
"cloneman": {
|
|
24
|
+
"boilerplateFiles": [
|
|
25
|
+
".editorconfig",
|
|
26
|
+
".gitignore",
|
|
27
|
+
".gitlab-ci.yml",
|
|
28
|
+
".htmlvalidate.mjs",
|
|
29
|
+
".npmrc",
|
|
30
|
+
".prettierignore",
|
|
31
|
+
"CHANGELOG.md",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"README.md",
|
|
34
|
+
"build.mjs",
|
|
35
|
+
"eslint.config.mjs",
|
|
36
|
+
"renovate.json",
|
|
37
|
+
"src/__snapshots__/elements.spec.ts.snap",
|
|
38
|
+
"src/configs/index.ts",
|
|
39
|
+
"src/configs/recommended.ts",
|
|
40
|
+
"src/elements.spec.ts",
|
|
41
|
+
"src/elements.ts",
|
|
42
|
+
"src/entry-cjs.ts",
|
|
43
|
+
"src/entry-esm.ts",
|
|
44
|
+
"src/index.ts",
|
|
45
|
+
"src/rules/custom-rule.spec.ts",
|
|
46
|
+
"src/rules/custom-rule.ts",
|
|
47
|
+
"src/rules/index.ts",
|
|
48
|
+
"test-files/elements/custom-component-invalid.html",
|
|
49
|
+
"test-files/elements/custom-component-valid.html",
|
|
50
|
+
"test-files/smoketest.html",
|
|
51
|
+
"test/htmlvalidate.spec.ts",
|
|
52
|
+
"tsconfig.cjs.json",
|
|
53
|
+
"tsconfig.esm.json",
|
|
54
|
+
"tsconfig.json"
|
|
55
|
+
],
|
|
56
|
+
"managedFiles": [
|
|
57
|
+
".editorconfig",
|
|
58
|
+
".gitignore",
|
|
59
|
+
".gitlab-ci.yml",
|
|
60
|
+
".htmlvalidate.mjs",
|
|
61
|
+
".npmrc",
|
|
62
|
+
".prettierignore",
|
|
63
|
+
"LICENSE",
|
|
64
|
+
"build.mjs",
|
|
65
|
+
"eslint.config.mjs",
|
|
66
|
+
"package.json",
|
|
67
|
+
"renovate.json",
|
|
68
|
+
"tsconfig.cjs.json",
|
|
69
|
+
"tsconfig.esm.json",
|
|
70
|
+
"tsconfig.json"
|
|
71
|
+
],
|
|
72
|
+
"uninstallDependencies": [],
|
|
73
|
+
"ignoredDependencies": [
|
|
74
|
+
"html-validate",
|
|
75
|
+
"@html-validate/eslint-*",
|
|
76
|
+
"@html-validate/prettier-*"
|
|
77
|
+
]
|
|
78
|
+
}
|
|
10
79
|
}
|
package/README.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# @html-validate/plugin-template
|
|
2
|
-
|
|
3
|
-
## ⚠️ IMPORTANT NOTICE ⚠️
|
|
4
|
-
|
|
5
|
-
**This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
|
|
6
|
-
|
|
7
|
-
This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
|
|
8
|
-
|
|
9
|
-
## Purpose
|
|
10
|
-
|
|
11
|
-
This package exists to:
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@html-validate/plugin-template`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
15
|
-
|
|
16
|
-
## What is OIDC Trusted Publishing?
|
|
17
|
-
|
|
18
|
-
OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
|
|
19
|
-
|
|
20
|
-
## Setup Instructions
|
|
21
|
-
|
|
22
|
-
To properly configure OIDC trusted publishing for this package:
|
|
23
|
-
|
|
24
|
-
1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
28
|
-
|
|
29
|
-
## DO NOT USE THIS PACKAGE
|
|
30
|
-
|
|
31
|
-
This package is a placeholder for OIDC configuration only. It:
|
|
32
|
-
- Contains no executable code
|
|
33
|
-
- Provides no functionality
|
|
34
|
-
- Should not be installed as a dependency
|
|
35
|
-
- Exists only for administrative purposes
|
|
36
|
-
|
|
37
|
-
## More Information
|
|
38
|
-
|
|
39
|
-
For more details about npm's trusted publishing feature, see:
|
|
40
|
-
- [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
**Maintained for OIDC setup purposes only**
|