Skip to content

Commit c66e5ac

Browse files
feat(oxlint-config-smarthr): Oxlint のための共通設定パッケージを追加 (#1239)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9f51b41 commit c66e5ac

9 files changed

Lines changed: 611 additions & 1 deletion

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Preview Release
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened, synchronize]
6+
paths:
7+
- 'packages/oxlint-config-smarthr/**'
8+
9+
jobs:
10+
previewRelease:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v6
15+
- uses: pnpm/action-setup@v6
16+
with:
17+
package_json_file: 'package.json'
18+
run_install: false
19+
- uses: actions/setup-node@v6
20+
with:
21+
node-version-file: '.node-version'
22+
- run: pnpx pkg-pr-new publish packages/oxlint-config-smarthr

packages/eslint-config-smarthr/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import typescript from './configs/typescript.js'
55
import smarthr from 'eslint-plugin-smarthr'
66

77
/**
8+
* NOTE: ESLint / oxlint 併用期間中は、ルールの追加・変更時に
9+
* oxlint-config-smarthr (packages/oxlint-config-smarthr/index.js) にも同じ修正を適用すること。
10+
*
811
* @type {import('eslint').Linter.Config[]}
912
*/
1013
export default [
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
The MIT License (MIT)
2+
3+
Copyright 2026 SmartHR
4+
5+
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:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
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.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# oxlint-config-smarthr
2+
3+
[![npm version](https://badge.fury.io/js/oxlint-config-smarthr.svg)](https://badge.fury.io/js/oxlint-config-smarthr)
4+
5+
SmartHR 全社共通の oxlint 設定です。
6+
React + TypeScript プロジェクトでの利用を想定しています。
7+
8+
## インストール
9+
10+
```sh
11+
pnpm add --dev oxlint eslint-plugin-smarthr # peerDependencies
12+
pnpm add --dev oxlint-config-smarthr
13+
```
14+
15+
## 使い方
16+
17+
`oxlint.config.ts` で設定をインポートし、`extends` に追加してください。
18+
19+
```ts
20+
import { defineConfig } from 'oxlint'
21+
import smarthrConfig from 'oxlint-config-smarthr'
22+
23+
export default defineConfig({
24+
extends: [smarthrConfig],
25+
// NOTE: plugins / jsPlugins は extends によって上書きされるため、
26+
// 共有設定分も含めて必要なプラグインをすべて再宣言する必要があります。
27+
plugins: ['typescript', 'import', 'react', 'jsx-a11y'],
28+
jsPlugins: ['eslint-plugin-smarthr'],
29+
rules: {
30+
// プロダクト固有のルール
31+
},
32+
})
33+
```
34+
35+
`oxlint` コマンドで実行可能です。 eslint で使用できる大半のコマンドを利用できます。
36+
37+
```sh
38+
pnpm oxlint
39+
```
40+
41+
## Type-aware linting
42+
43+
この共有設定には `options.typeAware` は含まれていません。
44+
TypeScript の型情報を利用するルール(`typescript/dot-notation` など)を有効にするには、追加パッケージをインストールし、設定ファイルを調整してください。
45+
46+
```bash
47+
pnpm add -D oxlint-tsgolint
48+
```
49+
50+
```ts
51+
export default defineConfig({
52+
extends: [smarthrConfig],
53+
options: {
54+
typeAware: true,
55+
},
56+
// ...
57+
})
58+
```
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/**
2+
* SmartHR 全社共通の oxlint 設定
3+
*
4+
* eslint-config-smarthr の oxlint 版。
5+
* プロダクト横断で共有するルールセットを定義する。
6+
*
7+
* NOTE: ESLint / oxlint 併用期間中は、ルールの追加・変更時に
8+
* eslint-config-smarthr (packages/eslint-config-smarthr/index.js) にも同じ修正を適用すること。
9+
*
10+
* @type {import('oxlint').OxlintConfig}
11+
*/
12+
const config = {
13+
plugins: ['typescript', 'import', 'react', 'jsx-a11y'],
14+
jsPlugins: ['eslint-plugin-smarthr'],
15+
env: {
16+
builtin: true,
17+
browser: true,
18+
commonjs: true,
19+
es2016: true,
20+
},
21+
rules: {
22+
23+
// === ESLint recommended ===
24+
'constructor-super': 'error',
25+
'for-direction': 'error',
26+
'no-async-promise-executor': 'error',
27+
'no-case-declarations': 'error',
28+
'no-class-assign': 'error',
29+
'no-compare-neg-zero': 'error',
30+
'no-cond-assign': 'error',
31+
'no-const-assign': 'error',
32+
'no-constant-binary-expression': 'error',
33+
'no-constant-condition': 'error',
34+
'no-control-regex': 'error',
35+
'no-debugger': 'error',
36+
'no-delete-var': 'error',
37+
'no-dupe-class-members': 'error',
38+
'no-dupe-else-if': 'error',
39+
'no-dupe-keys': 'error',
40+
'no-duplicate-case': 'error',
41+
'no-empty': 'error',
42+
'no-empty-character-class': 'error',
43+
'no-empty-pattern': 'error',
44+
'no-empty-static-block': 'error',
45+
'no-ex-assign': 'error',
46+
'no-extra-boolean-cast': 'error',
47+
'no-fallthrough': 'error',
48+
'no-func-assign': 'error',
49+
'no-global-assign': 'error',
50+
'no-import-assign': 'error',
51+
'no-invalid-regexp': 'error',
52+
'no-irregular-whitespace': 'error',
53+
'no-loss-of-precision': 'error',
54+
'no-misleading-character-class': 'error',
55+
'no-new-native-nonconstructor': 'error',
56+
'no-nonoctal-decimal-escape': 'error',
57+
'no-obj-calls': 'error',
58+
'no-prototype-builtins': 'error',
59+
'no-redeclare': 'error',
60+
'no-regex-spaces': 'error',
61+
'no-self-assign': 'error',
62+
'no-setter-return': 'error',
63+
'no-shadow-restricted-names': 'error',
64+
'no-sparse-arrays': 'error',
65+
'no-this-before-super': 'error',
66+
'no-unsafe-finally': 'error',
67+
'no-unsafe-negation': 'error',
68+
'no-unsafe-optional-chaining': 'error',
69+
'no-unused-labels': 'error',
70+
'no-unused-private-class-members': 'error',
71+
'no-useless-backreference': 'error',
72+
'no-useless-catch': 'error',
73+
'no-useless-escape': 'error',
74+
'no-with': 'error',
75+
'require-yield': 'error',
76+
'use-isnan': 'error',
77+
'valid-typeof': ['error', { requireStringLiterals: true }],
78+
79+
// === ESLint best practices ===
80+
'array-callback-return': 'warn',
81+
'block-scoped-var': 'warn',
82+
'default-param-last': 'error',
83+
eqeqeq: 'error',
84+
'import/no-duplicates': 'error',
85+
'no-caller': 'error',
86+
'no-div-regex': 'warn',
87+
'no-eval': 'error',
88+
'no-extend-native': 'error',
89+
'no-inner-declarations': 'warn',
90+
'no-iterator': 'error',
91+
'no-label-var': 'error',
92+
'no-lone-blocks': 'error',
93+
'no-loop-func': 'warn',
94+
'no-new-func': 'error',
95+
'no-new-wrappers': 'error',
96+
'no-proto': 'error',
97+
'no-return-assign': 'error',
98+
'no-script-url': 'warn',
99+
'no-self-compare': 'error',
100+
'no-sequences': 'error',
101+
'no-shadow': 'error',
102+
'no-throw-literal': 'error',
103+
'no-unmodified-loop-condition': 'warn',
104+
'no-unused-expressions': 'error',
105+
'no-useless-call': 'warn',
106+
'no-useless-computed-key': 'error',
107+
'no-useless-concat': 'error',
108+
'no-useless-rename': 'error',
109+
'no-var': 'error',
110+
'no-void': 'error',
111+
'prefer-const': ['warn', { destructuring: 'all', ignoreReadBeforeAssign: true }],
112+
'prefer-numeric-literals': 'error',
113+
'prefer-rest-params': 'error',
114+
'prefer-spread': 'warn',
115+
radix: 'error',
116+
'symbol-description': 'error',
117+
'vars-on-top': 'warn',
118+
'no-array-constructor': 'error',
119+
120+
// === React recommended ===
121+
'react/jsx-key': 'error',
122+
'react/jsx-no-comment-textnodes': 'error',
123+
'react/jsx-no-duplicate-props': 'error',
124+
'react/jsx-no-target-blank': 'error',
125+
'react/jsx-no-undef': 'error',
126+
'react/no-children-prop': 'warn',
127+
'react/no-danger-with-children': 'error',
128+
'react/no-direct-mutation-state': 'error',
129+
'react/no-find-dom-node': 'error',
130+
'react/no-is-mounted': 'error',
131+
'react/no-render-return-value': 'error',
132+
'react/no-string-refs': 'error',
133+
'react/no-unescaped-entities': 'warn',
134+
'react/no-unknown-property': 'error',
135+
136+
// === React hooks ===
137+
'react/exhaustive-deps': 'error',
138+
'react/rules-of-hooks': 'error',
139+
140+
// === jsx-a11y ===
141+
'jsx-a11y/alt-text': 'warn',
142+
'jsx-a11y/anchor-has-content': 'warn',
143+
'jsx-a11y/aria-activedescendant-has-tabindex': 'warn',
144+
'jsx-a11y/aria-props': 'warn',
145+
'jsx-a11y/aria-role': 'warn',
146+
'jsx-a11y/aria-unsupported-elements': 'warn',
147+
'jsx-a11y/heading-has-content': 'warn',
148+
'jsx-a11y/html-has-lang': 'error',
149+
'jsx-a11y/iframe-has-title': 'warn',
150+
'jsx-a11y/label-has-associated-control': 'warn',
151+
'jsx-a11y/lang': 'error',
152+
'jsx-a11y/media-has-caption': 'warn',
153+
'jsx-a11y/mouse-events-have-key-events': 'warn',
154+
'jsx-a11y/no-access-key': 'warn',
155+
'jsx-a11y/no-autofocus': 'warn',
156+
'jsx-a11y/no-distracting-elements': 'warn',
157+
'jsx-a11y/no-noninteractive-tabindex': 'warn',
158+
'jsx-a11y/no-redundant-roles': 'warn',
159+
'jsx-a11y/role-has-required-aria-props': 'warn',
160+
'jsx-a11y/role-supports-aria-props': 'warn',
161+
'jsx-a11y/scope': 'warn',
162+
'jsx-a11y/tabindex-no-positive': 'warn',
163+
164+
// === React additional rules ===
165+
'react/jsx-curly-brace-presence': 'error',
166+
'react/jsx-filename-extension': ['error', { extensions: ['.tsx', '.jsx'] }],
167+
'react/jsx-fragments': ['error', 'syntax'],
168+
'react/jsx-no-useless-fragment': 'error',
169+
'react/jsx-pascal-case': ['warn', { allowAllCaps: true }],
170+
'react/no-did-mount-set-state': 'error',
171+
'react/no-redundant-should-component-update': 'error',
172+
'react/no-this-in-sfc': 'error',
173+
'react/no-will-update-set-state': 'error',
174+
'react/prefer-es6-class': 'error',
175+
'react/style-prop-object': 'error',
176+
'react/void-dom-elements-no-children': 'error',
177+
178+
// === TypeScript ===
179+
'typescript/dot-notation': 'error',
180+
'typescript/no-duplicate-enum-values': 'error',
181+
'typescript/no-empty-object-type': 'error',
182+
'typescript/no-extra-non-null-assertion': 'error',
183+
'typescript/no-misused-new': 'error',
184+
'typescript/no-namespace': 'error',
185+
'typescript/no-non-null-asserted-optional-chain': 'error',
186+
'typescript/no-require-imports': 'error',
187+
'typescript/no-this-alias': 'error',
188+
'typescript/no-unnecessary-type-constraint': 'error',
189+
'typescript/no-unsafe-declaration-merging': 'error',
190+
'typescript/no-unsafe-function-type': 'error',
191+
'typescript/no-wrapper-object-types': 'error',
192+
'typescript/prefer-as-const': 'error',
193+
'typescript/triple-slash-reference': 'error',
194+
'typescript/array-type': ['error', { default: 'array-simple' }],
195+
'typescript/unified-signatures': 'warn',
196+
'typescript/consistent-type-imports': ['error', { fixStyle: 'inline-type-imports' }],
197+
'typescript/no-import-type-side-effects': 'error',
198+
199+
// === eslint-plugin-smarthr ===
200+
'eslint-plugin-smarthr/a11y-anchor-has-href-attribute': 'error',
201+
'eslint-plugin-smarthr/a11y-aria-labelledby': 'warn',
202+
'eslint-plugin-smarthr/a11y-clickable-element-has-text': 'error',
203+
'eslint-plugin-smarthr/a11y-form-control-in-form': 'error',
204+
'eslint-plugin-smarthr/a11y-heading-in-sectioning-content': 'error',
205+
'eslint-plugin-smarthr/a11y-help-link-with-support-href': 'error',
206+
'eslint-plugin-smarthr/a11y-image-has-alt-attribute': 'error',
207+
'eslint-plugin-smarthr/a11y-input-has-name-attribute': 'error',
208+
'eslint-plugin-smarthr/a11y-input-in-form-control': 'error',
209+
'eslint-plugin-smarthr/a11y-numbered-text-within-ol': 'error',
210+
'eslint-plugin-smarthr/a11y-prohibit-checkbox-or-radio-in-table-cell': 'error',
211+
'eslint-plugin-smarthr/a11y-prohibit-input-maxlength-attribute': 'error',
212+
'eslint-plugin-smarthr/a11y-prohibit-input-placeholder': 'error',
213+
'eslint-plugin-smarthr/a11y-prohibit-overflow-hidden': 'warn',
214+
'eslint-plugin-smarthr/a11y-prohibit-sectioning-content-in-form': 'error',
215+
'eslint-plugin-smarthr/a11y-prohibit-useless-sectioning-fragment': 'error',
216+
'eslint-plugin-smarthr/a11y-scroller-has-tabindex': 'warn',
217+
'eslint-plugin-smarthr/a11y-trigger-has-button': 'error',
218+
'eslint-plugin-smarthr/best-practice-for-async-current-target': 'error',
219+
'eslint-plugin-smarthr/best-practice-for-button-element': 'error',
220+
'eslint-plugin-smarthr/best-practice-for-date': 'error',
221+
'eslint-plugin-smarthr/best-practice-for-data-test-attribute': 'off',
222+
'eslint-plugin-smarthr/best-practice-for-interactive-element': 'error',
223+
'eslint-plugin-smarthr/best-practice-for-layouts': 'error',
224+
'eslint-plugin-smarthr/best-practice-for-nested-attributes-array-index': 'error',
225+
'eslint-plugin-smarthr/best-practice-for-optional-chaining': 'error',
226+
'eslint-plugin-smarthr/best-practice-for-prohibit-import-smarthr-ui-local': 'error',
227+
'eslint-plugin-smarthr/best-practice-for-remote-trigger-dialog': 'error',
228+
'eslint-plugin-smarthr/best-practice-for-rest-parameters': 'off',
229+
'eslint-plugin-smarthr/best-practice-for-spread-syntax': ['error', { fix: true }],
230+
'eslint-plugin-smarthr/best-practice-for-tailwind-prohibit-root-margin': 'off',
231+
'eslint-plugin-smarthr/best-practice-for-tailwind-variants': 'off',
232+
'eslint-plugin-smarthr/best-practice-for-text-component': 'warn',
233+
'eslint-plugin-smarthr/best-practice-for-unnesessary-early-return': 'off',
234+
'eslint-plugin-smarthr/component-name': 'error',
235+
'eslint-plugin-smarthr/design-system-guideline-prohibit-dialog-button-icon': 'warn',
236+
'eslint-plugin-smarthr/design-system-guideline-prohibit-double-icons': 'off',
237+
'eslint-plugin-smarthr/format-import-path': 'off',
238+
'eslint-plugin-smarthr/format-translate-component': 'off',
239+
'eslint-plugin-smarthr/no-import-other-domain': 'off',
240+
'eslint-plugin-smarthr/prohibit-export-array-type': 'error',
241+
'eslint-plugin-smarthr/prohibit-file-name': 'off',
242+
'eslint-plugin-smarthr/prohibit-import': 'off',
243+
'eslint-plugin-smarthr/prohibit-path-within-template-literal': 'off',
244+
'eslint-plugin-smarthr/require-barrel-import': 'error',
245+
'eslint-plugin-smarthr/require-declaration': 'off',
246+
'eslint-plugin-smarthr/require-export': 'off',
247+
'eslint-plugin-smarthr/require-i18n-text': 'warn',
248+
'eslint-plugin-smarthr/require-import': 'off',
249+
'eslint-plugin-smarthr/trim-props': 'error',
250+
},
251+
}
252+
253+
export default config
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "oxlint-config-smarthr",
3+
"version": "0.1.0",
4+
"description": "A sharable oxlint config for SmartHR",
5+
"type": "module",
6+
"exports": {
7+
".": {
8+
"import": "./index.js"
9+
}
10+
},
11+
"repository": {
12+
"type": "git",
13+
"url": "git+git@github.com:kufu/tamatebako.git",
14+
"directory": "packages/oxlint-config-smarthr"
15+
},
16+
"scripts": {
17+
"test": "oxlint --config index.js --print-config > /dev/null"
18+
},
19+
"keywords": [
20+
"oxlint"
21+
],
22+
"author": "SmartHR",
23+
"license": "MIT",
24+
"bugs": {
25+
"url": "https://github.com/kufu/tamatebako/issues"
26+
},
27+
"homepage": "https://github.com/kufu/tamatebako/tree/master/packages/oxlint-config-smarthr",
28+
"publishConfig": {
29+
"registry": "https://registry.npmjs.org"
30+
},
31+
"peerDependencies": {
32+
"oxlint": ">=1.0.0",
33+
"eslint-plugin-smarthr": ">=6.0.0"
34+
}
35+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"paths": {
4+
"@/*": ["./src/*"]
5+
}
6+
}
7+
}

0 commit comments

Comments
 (0)