@d-zero/markuplint-config 5.0.0-dev.93 → 5.1.0

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 D-ZERO Co., Ltd.
3
+ Copyright (c) 2024 D-ZERO Co., Ltd.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,4 +1,96 @@
1
1
  # `@d-zero/markuplint-config`
2
2
 
3
- - 使用: 🆗 使用可
4
- - 解説: 🚧 準備中
3
+ D-ZERO用のMarkuplint設定です。アクセシブルで保守性の高いHTML実装を促進するためのルールセットを提供します。
4
+
5
+ ## 個別インストール
6
+
7
+ ```sh
8
+ npm install -D @d-zero/markuplint-config
9
+ ```
10
+
11
+ ## 使い方
12
+
13
+ `.markuplintrc`を作成し、[`extends`](https://markuplint.dev/ja/docs/configuration/properties#extends)機能を使って読み込みます。
14
+
15
+ ```json
16
+ {
17
+ "extends": ["@d-zero/markuplint-config"]
18
+ }
19
+ ```
20
+
21
+ ## 含まれるルール
22
+
23
+ このconfigには以下のD-ZERO独自ルールが含まれています:
24
+
25
+ ### 1. 要素の禁止・必須化
26
+
27
+ - **`br`要素の禁止**: CSSでスタイル調整を推奨
28
+ - **`img`要素のalt属性必須**: アクセシビリティ確保のため
29
+ - **`a`要素のhref属性必須**: リンクの明確化
30
+
31
+ ### 2. button要素のInvoker Commands API使用の強制
32
+
33
+ - **`type="button"`のbutton要素**: `command`属性が必須
34
+ - Invoker Commands APIを使用した宣言的なUI実装を推奨
35
+ - 例外: `role`属性を持つボタン、フォーム送信ボタン(`type="submit"`/`type="reset"`/typeなし)
36
+
37
+ - **`popovertarget`属性を持つボタン**: Invoker Commands APIへの移行を推奨
38
+ - `commandfor`/`command`属性の使用を推奨
39
+ - `popovertarget`は将来的に非推奨となる予定
40
+
41
+ 詳細は[CODING_GUIDELINES_NO_CLICK_EVENT.md](../../CODING_GUIDELINES_NO_CLICK_EVENT.md)を参照してください。
42
+
43
+ ### 3. ファイル名の命名規則
44
+
45
+ - **画像/メディアファイル**: 小文字のケバブケース(ハイフン区切り)を強制
46
+ - 対象: `img`, `video`, `audio`, `source`要素の`src`/`poster`属性
47
+ - 大文字、スペース、アンダースコアは使用不可
48
+
49
+ ### 4. 無効な属性
50
+
51
+ - **`a`要素のhref属性**: `javascript:`スキームを禁止
52
+ - 代わりに`button`要素の使用を推奨
53
+
54
+ ### 5. 特殊な属性の許可
55
+
56
+ - **`html`要素の`prefix`属性**: Open Graph Protocolのため許可
57
+
58
+ ### 拡張
59
+
60
+ プロジェクトに合わせて設定を追加します。
61
+
62
+ ```json
63
+ {
64
+ "extends": ["@d-zero/markuplint-config"],
65
+ "rules": {
66
+ // 例: クラス名の命名規則を変更する
67
+ "class-naming": {
68
+ "value": "/^c-(?<ComponentName>[a-z][a-z0-9]*(?:-[a-z0-9]+)*)$/"
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ `class-naming`の設定を変更する場合、上書きがやや冗長になるので、専用の関数を使って許可するクラスを追加します。
75
+
76
+ ```js
77
+ import { extendsConfig } from '@d-zero/markuplint-config';
78
+
79
+ export default extendsConfig({
80
+ // 通常のクラス命名規則に加えて、Splideのクラス名も許可する
81
+ classNaming: ['/^splide(?:__[a-z]+)?$/'],
82
+ });
83
+
84
+ // または、以下のように書くこともできます
85
+
86
+ export default {
87
+ ...extendsConfig({
88
+ // 通常のクラス命名規則に加えて、Splideのクラス名も許可する
89
+ classNaming: ['/^splide(?:__[a-z]+)?$/'],
90
+ }),
91
+ // 他の設定
92
+ rules: {
93
+ 'character-reference': false,
94
+ },
95
+ };
96
+ ```
package/base.js ADDED
@@ -0,0 +1,140 @@
1
+ /**
2
+ * @type {import('@markuplint/ml-config').Config}
3
+ */
4
+ export default {
5
+ extends: ['markuplint:recommended-static-html'],
6
+ rules: {
7
+ 'disallowed-element': {
8
+ value: ['br'],
9
+ reason:
10
+ 'br要素は原則使用しません。代わりにCSSでスタイルを調整してください。使用する場合は理由が必要です。(D-ZERO独自ルール)',
11
+ },
12
+ },
13
+ nodeRules: [
14
+ {
15
+ selector: "script[src^='https://'], script[src^='https://']",
16
+ rules: {
17
+ 'required-attr': false,
18
+ },
19
+ },
20
+ {
21
+ selector: 'html',
22
+ rules: {
23
+ // <html prefix="og: http://ogp.me/ns#">
24
+ 'invalid-attr': {
25
+ options: {
26
+ allowAttrs: [
27
+ {
28
+ name: 'prefix',
29
+ value: 'Any',
30
+ },
31
+ ],
32
+ },
33
+ },
34
+ },
35
+ },
36
+ {
37
+ selector: 'img',
38
+ rules: {
39
+ // https://github.com/markuplint/markuplint/blob/c35e0beb5e14093a41cee7634221dbe7f7d577f9/packages/%40markuplint/config-presets/src/preset.performance.json#L25-L35 の設定を上書き
40
+ // width, height の指定は上書きされるため、省略可能になるが、ビルド時に自動的に付与されるため問題なしとする
41
+ 'required-attr': {
42
+ value: 'alt',
43
+ reason:
44
+ '省略可能なケースがほとんど想定されないため、原則禁止としています。省略する場合は明確な理由が必要です。(D-ZERO独自ルール)',
45
+ },
46
+ },
47
+ },
48
+ {
49
+ selector:
50
+ 'img:not([src^="data:"], [src^="blob:"], [src^="https://"], [src^="http://"], [src^="//"])',
51
+ rules: {
52
+ 'invalid-attr': {
53
+ options: {
54
+ disallowAttrs: [
55
+ {
56
+ name: 'src',
57
+ value: { pattern: '/[A-Z\\s_]/' },
58
+ },
59
+ ],
60
+ },
61
+ reason:
62
+ '画像ファイル名は小文字のケバブケース(ハイフン区切り)で命名してください。大文字、スペース、アンダースコアは使用できません。(D-ZERO独自ルール)',
63
+ },
64
+ },
65
+ },
66
+ {
67
+ selector: 'video, audio, source',
68
+ rules: {
69
+ 'invalid-attr': {
70
+ options: {
71
+ disallowAttrs: [
72
+ {
73
+ name: 'src',
74
+ value: { pattern: '/[A-Z\\s_]/' },
75
+ },
76
+ {
77
+ name: 'poster',
78
+ value: { pattern: '/[A-Z\\s_]/' },
79
+ },
80
+ ],
81
+ },
82
+ reason:
83
+ 'メディアファイル名は小文字のケバブケース(ハイフン区切り)で命名してください。大文字、スペース、アンダースコアは使用できません。(D-ZERO独自ルール)',
84
+ },
85
+ },
86
+ },
87
+ {
88
+ selector: 'a',
89
+ rules: {
90
+ 'required-attr': {
91
+ value: 'href',
92
+ reason:
93
+ '省略可能なケースがほとんど想定されないため、原則禁止としています。省略する場合は明確な理由が必要です。(D-ZERO独自ルール)',
94
+ },
95
+ 'invalid-attr': {
96
+ options: {
97
+ disallowAttrs: [
98
+ {
99
+ name: 'href',
100
+ value: { pattern: '/^javascript:/i' },
101
+ },
102
+ ],
103
+ },
104
+ reason:
105
+ 'JavaScriptのリンクは使用しないでください。代わりに`button`要素を使用してください。',
106
+ },
107
+ },
108
+ },
109
+ {
110
+ selector: 'button[type=button]:not([role]):not([popovertarget])',
111
+ rules: {
112
+ 'required-attr': {
113
+ value: 'command',
114
+ reason:
115
+ 'button要素には原則としてcommand属性が必要です。Invoker Commands APIを使用してアクセシブルなUIを実装してください。role属性を持つボタン(role="tab"など)やtype="submit"/type="reset"/typeなしのボタンは例外として許可されます。(D-ZERO独自ルール)',
116
+ },
117
+ },
118
+ },
119
+ {
120
+ selector: 'button[popovertarget]',
121
+ rules: {
122
+ 'required-attr': {
123
+ value: 'commandfor',
124
+ reason:
125
+ 'popovertarget属性の代わりにcommandfor属性を使用してください。popovertarget属性は将来的に非推奨となる予定です。(D-ZERO独自ルール)',
126
+ },
127
+ },
128
+ },
129
+ {
130
+ selector: 'button[popovertargetaction]',
131
+ rules: {
132
+ 'required-attr': {
133
+ value: 'command',
134
+ reason:
135
+ 'popovertargetaction属性(show/hide/toggle)の代わりにcommand属性(show-popover/hide-popover/toggle-popover)を使用してください。(D-ZERO独自ルール)',
136
+ },
137
+ },
138
+ },
139
+ ],
140
+ };
package/index.js ADDED
@@ -0,0 +1,53 @@
1
+ import base from './base.js';
2
+ import nameConfig, { nameWith } from './name.js';
3
+ import pug from './pug.js';
4
+
5
+ const createConfig = (name = nameConfig) => {
6
+ return {
7
+ ...base,
8
+ ...pug,
9
+ ...name,
10
+ parser: {
11
+ ...base.parser,
12
+ ...pug.parser,
13
+ ...name.parser,
14
+ },
15
+ rules: {
16
+ ...base.rules,
17
+ ...pug.rules,
18
+ ...name.rules,
19
+ },
20
+ nodeRules: [
21
+ //
22
+ ...(base.nodeRules ?? []),
23
+ ...(pug.nodeRules ?? []),
24
+ ...(name.nodeRules ?? []),
25
+ ],
26
+ childNodeRules: [
27
+ //
28
+ ...(base.childNodeRules ?? []),
29
+ ...(pug.childNodeRules ?? []),
30
+ ...(name.childNodeRules ?? []),
31
+ ],
32
+ overrideMode: 'merge',
33
+ overrides: {
34
+ ...pug.overrides,
35
+ },
36
+ };
37
+ };
38
+
39
+ /**
40
+ * @type {import('@markuplint/ml-config').Config}
41
+ */
42
+ export default createConfig();
43
+
44
+ /**
45
+ *
46
+ * @param {object} options
47
+ * @param {string[]?} options.classNaming
48
+ * @returns
49
+ */
50
+ export const extendsConfig = (options) => {
51
+ const name = options?.classNaming ? nameWith(options.classNaming) : nameConfig;
52
+ return createConfig(name);
53
+ };
package/name.js ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @type {import('@markuplint/ml-config').Config}
3
+ */
4
+ const nameBase = {
5
+ rules: {
6
+ 'class-naming': {
7
+ severity: 'error',
8
+ value: '/^c-(?<ComponentName>[a-z][a-z0-9]*(?:-[a-z0-9]+)*)$/',
9
+ reason:
10
+ 'クラス名の形式はディーゼロのコーディングガイドラインに則って命名する必要があります。 http://tmpl.d-zero.com/__guideline/coding-guideline/html.html#%F0%9F%92%8E-%E3%82%B3%E3%83%B3%E3%83%9B%E3%82%9A%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88',
11
+ },
12
+ },
13
+ childNodeRules: [
14
+ {
15
+ regexSelector: {
16
+ attrName: 'class',
17
+ attrValue: '/^c-(?<ComponentName>[a-z][a-z0-9]*(?:-[a-z0-9]+)*)$/',
18
+ },
19
+ inheritance: true,
20
+ rules: {
21
+ 'class-naming': {
22
+ severity: 'error',
23
+ value: [
24
+ '/^c-{{ ComponentName }}__[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/',
25
+ '/^c-(?!{{ ComponentName }})[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/',
26
+ '/^c-{{ ComponentName }}[a-z0-9]*(?:-[a-z0-9]+)*$/',
27
+ ],
28
+ reason:
29
+ 'ディーゼロのコーディングガイドラインではコンポーネントの中はそのコンポーネントのエレメントか、他のコンポーネントである必要があります。 http://tmpl.d-zero.com/__guideline/coding-guideline/html.html#%E3%82%B3%E3%83%B3%E3%83%9B%E3%82%9A%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E6%A7%8B%E6%88%90%E3%81%A8%E3%82%AF%E3%83%A9%E3%82%B9%E5%91%BD%E5%90%8D%E8%A6%8F%E5%89%87',
30
+ },
31
+ },
32
+ },
33
+ {
34
+ selector: "[class='c-content-main']",
35
+ inheritance: true,
36
+ rules: {
37
+ 'class-naming': {
38
+ severity: 'error',
39
+ value: '/^(?!c-).+$|^$/',
40
+ reason:
41
+ 'ディーゼロのコーディングガイドラインでは「c-content-main」の中は「c-」で始めないルールとなっています。 http://tmpl.d-zero.com/__guideline/coding-guideline/html.html#%E3%82%A8%E3%83%AC%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BE%8B%E5%A4%96%E3%81%A8%E3%82%AF%E3%83%A9%E3%82%B9%E8%BF%BD%E5%8A%A0%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%AB',
42
+ },
43
+ },
44
+ },
45
+ ],
46
+ };
47
+
48
+ /**
49
+ * @type {import('@markuplint/ml-config').Config}
50
+ */
51
+ export default nameBase;
52
+
53
+ /**
54
+ * @type {(addNamingRule: string[]) => import('@markuplint/ml-config').Config}
55
+ */
56
+ export const nameWith = (addNamingRules) => {
57
+ return {
58
+ ...nameBase,
59
+ rules: {
60
+ ...nameBase.rules,
61
+ 'class-naming': {
62
+ ...nameBase.rules['class-naming'],
63
+ value: [nameBase.rules['class-naming'].value, ...addNamingRules],
64
+ },
65
+ },
66
+ childNodeRules: [
67
+ {
68
+ ...nameBase.childNodeRules[0],
69
+ rules: {
70
+ ...nameBase.childNodeRules[0].rules,
71
+ 'class-naming': {
72
+ ...nameBase.childNodeRules[0].rules['class-naming'],
73
+ value: [
74
+ ...nameBase.childNodeRules[0].rules['class-naming'].value,
75
+ ...addNamingRules,
76
+ ],
77
+ },
78
+ },
79
+ },
80
+ nameBase.childNodeRules[1],
81
+ ],
82
+ };
83
+ };
package/package.json CHANGED
@@ -1,21 +1,33 @@
1
1
  {
2
2
  "name": "@d-zero/markuplint-config",
3
- "version": "5.0.0-dev.93+c6646f2",
3
+ "version": "5.1.0",
4
4
  "description": "Configurations of Markuplint",
5
- "repository": "https://github.com/d-zero-dev/node-dev-env.git",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/d-zero-dev/linters.git",
8
+ "directory": "packages/@d-zero/markuplint-config"
9
+ },
6
10
  "author": "D-ZERO Co., Ltd.",
7
11
  "license": "MIT",
8
- "private": false,
9
12
  "publishConfig": {
10
13
  "access": "public"
11
14
  },
15
+ "engines": {
16
+ "node": ">=22.0.0"
17
+ },
18
+ "type": "module",
19
+ "exports": {
20
+ ".": "./index.js",
21
+ "./base": "./base.js",
22
+ "./name": "./name.js",
23
+ "./pug": "./pug.js"
24
+ },
12
25
  "files": [
13
- ".markuplintrc.json"
26
+ "*.js"
14
27
  ],
15
- "main": ".markuplintrc.json",
16
28
  "dependencies": {
17
- "@markuplint/pug-parser": "4.0.0-dev.20",
18
- "markuplint": "4.0.0-dev.20"
29
+ "@markuplint/pug-parser": "4.6.23",
30
+ "markuplint": "4.14.0"
19
31
  },
20
- "gitHead": "c6646f2425c257367f106e5e2cee276c42aef9d5"
32
+ "gitHead": "645a686188fe078102000e8d59860ec33f2ed750"
21
33
  }
package/pug.js ADDED
@@ -0,0 +1,18 @@
1
+ import path from 'node:path';
2
+
3
+ /**
4
+ * @type {import('@markuplint/ml-config').Config}
5
+ */
6
+ export default {
7
+ parser: {
8
+ '.pug$': '@markuplint/pug-parser',
9
+ },
10
+ overrideMode: 'merge',
11
+ overrides: {
12
+ [path.resolve(process.cwd(), '**', '*.pug')]: {
13
+ rules: {
14
+ 'character-reference': false,
15
+ },
16
+ },
17
+ },
18
+ };
@@ -1,51 +0,0 @@
1
- {
2
- "extends": ["markuplint:recommended"],
3
- "parser": {
4
- ".pug$": "@markuplint/pug-parser"
5
- },
6
- "rules": {
7
- "class-naming": {
8
- "severity": "error",
9
- "value": "/^c-(?<ComponentName>[a-z][a-z0-9]*(?:-[a-z0-9]+)*)$/",
10
- "reason": "クラス名の形式はディーゼロのコーディングガイドラインに則って命名する必要があります。 http://tmpl.d-zero.com/__guideline/coding-guideline/html.html#%F0%9F%92%8E-%E3%82%B3%E3%83%B3%E3%83%9B%E3%82%9A%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88"
11
- }
12
- },
13
- "nodeRules": [
14
- {
15
- "selector": "script[src^='https://']",
16
- "rules": {
17
- "required-attr": false
18
- }
19
- }
20
- ],
21
- "childNodeRules": [
22
- {
23
- "regexSelector": {
24
- "attrName": "class",
25
- "attrValue": "/^c-(?<ComponentName>[a-z][a-z0-9]*(?:-[a-z0-9]+)*)$/"
26
- },
27
- "inheritance": true,
28
- "rules": {
29
- "class-naming": {
30
- "severity": "error",
31
- "value": [
32
- "/^c-{{ ComponentName }}__[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/",
33
- "/^c-(?!{{ ComponentName }})[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/"
34
- ],
35
- "reason": "ディーゼロのコーディングガイドラインではコンポーネントの中はそのコンポーネントのエレメントか、他のコンポーネントである必要があります。 http://tmpl.d-zero.com/__guideline/coding-guideline/html.html#%E3%82%B3%E3%83%B3%E3%83%9B%E3%82%9A%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E6%A7%8B%E6%88%90%E3%81%A8%E3%82%AF%E3%83%A9%E3%82%B9%E5%91%BD%E5%90%8D%E8%A6%8F%E5%89%87"
36
- }
37
- }
38
- },
39
- {
40
- "selector": "[class='c-content-main']",
41
- "inheritance": true,
42
- "rules": {
43
- "class-naming": {
44
- "severity": "error",
45
- "value": "/^(?!c-).+$|^$/",
46
- "reason": "ディーゼロのコーディングガイドラインでは「c-content-main」の中は「c-」で始めないルールとなっています。 http://tmpl.d-zero.com/__guideline/coding-guideline/html.html#%E3%82%A8%E3%83%AC%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BE%8B%E5%A4%96%E3%81%A8%E3%82%AF%E3%83%A9%E3%82%B9%E8%BF%BD%E5%8A%A0%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%AB"
47
- }
48
- }
49
- }
50
- ]
51
- }