-
Notifications
You must be signed in to change notification settings - Fork 5
feat(oxlint-config-smarthr): Oxlint のための共通設定パッケージを追加 #1239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1b20d16
9cddd5e
8255a21
26c1e5d
43b4a9b
d4c804f
9bc490f
64abf91
748b46c
793bafe
f7c78f1
2c5ed99
53a08eb
9054176
c4e5427
59c326c
ce10db4
8374ed9
f09351a
54a6f30
8249f1c
77f168d
a6141aa
82d326b
25c0d16
cb33d87
3da0f18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| name: Preview Release | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, reopened, synchronize] | ||
| paths: | ||
| - 'packages/oxlint-config-smarthr/**' | ||
|
|
||
| jobs: | ||
| previewRelease: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: pnpm/action-setup@v6 | ||
| with: | ||
| package_json_file: 'package.json' | ||
| run_install: false | ||
| - uses: actions/setup-node@v6 | ||
| with: | ||
| node-version-file: '.node-version' | ||
| - run: pnpx pkg-pr-new publish packages/oxlint-config-smarthr | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| The MIT License (MIT) | ||
|
|
||
| Copyright 2026 SmartHR | ||
|
|
||
| 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: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
|
|
||
| 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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # oxlint-config-smarthr | ||
|
|
||
| [](https://badge.fury.io/js/oxlint-config-smarthr) | ||
|
|
||
| SmartHR 全社共通の oxlint 設定です。 | ||
| React + TypeScript プロジェクトでの利用を想定しています。 | ||
|
|
||
| ## インストール | ||
|
|
||
| ```sh | ||
| pnpm add --dev oxlint eslint-plugin-smarthr # peerDependencies | ||
| pnpm add --dev oxlint-config-smarthr | ||
| ``` | ||
|
|
||
| ## 使い方 | ||
|
|
||
| `oxlint.config.ts` で設定をインポートし、`extends` に追加してください。 | ||
|
|
||
| ```ts | ||
| import { defineConfig } from 'oxlint' | ||
| import smarthrConfig from 'oxlint-config-smarthr' | ||
|
|
||
| export default defineConfig({ | ||
| extends: [smarthrConfig], | ||
| // NOTE: plugins / jsPlugins は extends によって上書きされるため、 | ||
| // 共有設定分も含めて必要なプラグインをすべて再宣言する必要があります。 | ||
| plugins: ['typescript', 'import', 'react', 'jsx-a11y'], | ||
| jsPlugins: ['eslint-plugin-smarthr'], | ||
| rules: { | ||
| // プロダクト固有のルール | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| `oxlint` コマンドで実行可能です。 eslint で使用できる大半のコマンドを利用できます。 | ||
|
|
||
| ```sh | ||
| pnpm oxlint | ||
| ``` | ||
|
|
||
| ## Type-aware linting | ||
|
|
||
| この共有設定には `options.typeAware` は含まれていません。 | ||
| TypeScript の型情報を利用するルール(`typescript/dot-notation` など)を有効にするには、追加パッケージをインストールし、設定ファイルを調整してください。 | ||
|
Comment on lines
+43
to
+44
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 ここの扱いはちょっと迷ったけど、tsgo に依存する必要があり、まだ必須とするには速い気がしてるのでこの形にしてます。 TypeScript 7 が出たらもうこのパッケージに入れちゃって良いかも。 |
||
|
|
||
| ```bash | ||
| pnpm add -D oxlint-tsgolint | ||
| ``` | ||
|
|
||
| ```ts | ||
| export default defineConfig({ | ||
| extends: [smarthrConfig], | ||
| options: { | ||
| typeAware: true, | ||
| }, | ||
| // ... | ||
| }) | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,253 @@ | ||
| /** | ||
| * SmartHR 全社共通の oxlint 設定 | ||
| * | ||
| * eslint-config-smarthr の oxlint 版。 | ||
| * プロダクト横断で共有するルールセットを定義する。 | ||
| * | ||
| * NOTE: ESLint / oxlint 併用期間中は、ルールの追加・変更時に | ||
| * eslint-config-smarthr (packages/eslint-config-smarthr/index.js) にも同じ修正を適用すること。 | ||
| * | ||
| * @type {import('oxlint').OxlintConfig} | ||
| */ | ||
| const config = { | ||
| plugins: ['typescript', 'import', 'react', 'jsx-a11y'], | ||
| jsPlugins: ['eslint-plugin-smarthr'], | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 名前の通り、plugins は Rust で書かれたビルトインのプラグインで、jsPlugins は ESLint プラグインです。 eslint-config-smarthr が扱っているカスタムルールのうち、eslint-plugin-smarthr だけは組み込まれていない(それはそう) ので、JSのまま読み込む形になります。 |
||
| env: { | ||
| builtin: true, | ||
| browser: true, | ||
| commonjs: true, | ||
| es2016: true, | ||
| }, | ||
| rules: { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. eslint-config-smarthr 側と限りなく同じです。ビルトイン化されたプラグインの詳細設定まで完璧に同じとは言い切れないですが‥…。 |
||
|
|
||
| // === ESLint recommended === | ||
| 'constructor-super': 'error', | ||
| 'for-direction': 'error', | ||
| 'no-async-promise-executor': 'error', | ||
| 'no-case-declarations': 'error', | ||
| 'no-class-assign': 'error', | ||
| 'no-compare-neg-zero': 'error', | ||
| 'no-cond-assign': 'error', | ||
| 'no-const-assign': 'error', | ||
| 'no-constant-binary-expression': 'error', | ||
| 'no-constant-condition': 'error', | ||
| 'no-control-regex': 'error', | ||
| 'no-debugger': 'error', | ||
| 'no-delete-var': 'error', | ||
| 'no-dupe-class-members': 'error', | ||
| 'no-dupe-else-if': 'error', | ||
| 'no-dupe-keys': 'error', | ||
| 'no-duplicate-case': 'error', | ||
| 'no-empty': 'error', | ||
| 'no-empty-character-class': 'error', | ||
| 'no-empty-pattern': 'error', | ||
| 'no-empty-static-block': 'error', | ||
| 'no-ex-assign': 'error', | ||
| 'no-extra-boolean-cast': 'error', | ||
| 'no-fallthrough': 'error', | ||
| 'no-func-assign': 'error', | ||
| 'no-global-assign': 'error', | ||
| 'no-import-assign': 'error', | ||
| 'no-invalid-regexp': 'error', | ||
| 'no-irregular-whitespace': 'error', | ||
| 'no-loss-of-precision': 'error', | ||
| 'no-misleading-character-class': 'error', | ||
| 'no-new-native-nonconstructor': 'error', | ||
| 'no-nonoctal-decimal-escape': 'error', | ||
| 'no-obj-calls': 'error', | ||
| 'no-prototype-builtins': 'error', | ||
| 'no-redeclare': 'error', | ||
| 'no-regex-spaces': 'error', | ||
| 'no-self-assign': 'error', | ||
| 'no-setter-return': 'error', | ||
| 'no-shadow-restricted-names': 'error', | ||
| 'no-sparse-arrays': 'error', | ||
| 'no-this-before-super': 'error', | ||
| 'no-unsafe-finally': 'error', | ||
| 'no-unsafe-negation': 'error', | ||
| 'no-unsafe-optional-chaining': 'error', | ||
| 'no-unused-labels': 'error', | ||
| 'no-unused-private-class-members': 'error', | ||
| 'no-useless-backreference': 'error', | ||
| 'no-useless-catch': 'error', | ||
| 'no-useless-escape': 'error', | ||
| 'no-with': 'error', | ||
| 'require-yield': 'error', | ||
| 'use-isnan': 'error', | ||
| 'valid-typeof': ['error', { requireStringLiterals: true }], | ||
|
|
||
| // === ESLint best practices === | ||
| 'array-callback-return': 'warn', | ||
| 'block-scoped-var': 'warn', | ||
| 'default-param-last': 'error', | ||
| eqeqeq: 'error', | ||
| 'import/no-duplicates': 'error', | ||
| 'no-caller': 'error', | ||
| 'no-div-regex': 'warn', | ||
| 'no-eval': 'error', | ||
| 'no-extend-native': 'error', | ||
| 'no-inner-declarations': 'warn', | ||
| 'no-iterator': 'error', | ||
| 'no-label-var': 'error', | ||
| 'no-lone-blocks': 'error', | ||
| 'no-loop-func': 'warn', | ||
| 'no-new-func': 'error', | ||
| 'no-new-wrappers': 'error', | ||
| 'no-proto': 'error', | ||
| 'no-return-assign': 'error', | ||
| 'no-script-url': 'warn', | ||
| 'no-self-compare': 'error', | ||
| 'no-sequences': 'error', | ||
| 'no-shadow': 'error', | ||
| 'no-throw-literal': 'error', | ||
| 'no-unmodified-loop-condition': 'warn', | ||
| 'no-unused-expressions': 'error', | ||
| 'no-useless-call': 'warn', | ||
| 'no-useless-computed-key': 'error', | ||
| 'no-useless-concat': 'error', | ||
| 'no-useless-rename': 'error', | ||
| 'no-var': 'error', | ||
| 'no-void': 'error', | ||
| 'prefer-const': ['warn', { destructuring: 'all', ignoreReadBeforeAssign: true }], | ||
| 'prefer-numeric-literals': 'error', | ||
| 'prefer-rest-params': 'error', | ||
| 'prefer-spread': 'warn', | ||
| radix: 'error', | ||
| 'symbol-description': 'error', | ||
| 'vars-on-top': 'warn', | ||
| 'no-array-constructor': 'error', | ||
|
|
||
| // === React recommended === | ||
| 'react/jsx-key': 'error', | ||
| 'react/jsx-no-comment-textnodes': 'error', | ||
| 'react/jsx-no-duplicate-props': 'error', | ||
| 'react/jsx-no-target-blank': 'error', | ||
| 'react/jsx-no-undef': 'error', | ||
| 'react/no-children-prop': 'warn', | ||
| 'react/no-danger-with-children': 'error', | ||
| 'react/no-direct-mutation-state': 'error', | ||
| 'react/no-find-dom-node': 'error', | ||
| 'react/no-is-mounted': 'error', | ||
| 'react/no-render-return-value': 'error', | ||
| 'react/no-string-refs': 'error', | ||
| 'react/no-unescaped-entities': 'warn', | ||
| 'react/no-unknown-property': 'error', | ||
|
|
||
| // === React hooks === | ||
| 'react/exhaustive-deps': 'error', | ||
| 'react/rules-of-hooks': 'error', | ||
|
|
||
| // === jsx-a11y === | ||
| 'jsx-a11y/alt-text': 'warn', | ||
| 'jsx-a11y/anchor-has-content': 'warn', | ||
| 'jsx-a11y/aria-activedescendant-has-tabindex': 'warn', | ||
| 'jsx-a11y/aria-props': 'warn', | ||
| 'jsx-a11y/aria-role': 'warn', | ||
| 'jsx-a11y/aria-unsupported-elements': 'warn', | ||
| 'jsx-a11y/heading-has-content': 'warn', | ||
| 'jsx-a11y/html-has-lang': 'error', | ||
| 'jsx-a11y/iframe-has-title': 'warn', | ||
| 'jsx-a11y/label-has-associated-control': 'warn', | ||
| 'jsx-a11y/lang': 'error', | ||
| 'jsx-a11y/media-has-caption': 'warn', | ||
| 'jsx-a11y/mouse-events-have-key-events': 'warn', | ||
| 'jsx-a11y/no-access-key': 'warn', | ||
| 'jsx-a11y/no-autofocus': 'warn', | ||
| 'jsx-a11y/no-distracting-elements': 'warn', | ||
| 'jsx-a11y/no-noninteractive-tabindex': 'warn', | ||
| 'jsx-a11y/no-redundant-roles': 'warn', | ||
| 'jsx-a11y/role-has-required-aria-props': 'warn', | ||
| 'jsx-a11y/role-supports-aria-props': 'warn', | ||
| 'jsx-a11y/scope': 'warn', | ||
| 'jsx-a11y/tabindex-no-positive': 'warn', | ||
|
|
||
| // === React additional rules === | ||
| 'react/jsx-curly-brace-presence': 'error', | ||
| 'react/jsx-filename-extension': ['error', { extensions: ['.tsx', '.jsx'] }], | ||
| 'react/jsx-fragments': ['error', 'syntax'], | ||
| 'react/jsx-no-useless-fragment': 'error', | ||
| 'react/jsx-pascal-case': ['warn', { allowAllCaps: true }], | ||
| 'react/no-did-mount-set-state': 'error', | ||
| 'react/no-redundant-should-component-update': 'error', | ||
| 'react/no-this-in-sfc': 'error', | ||
| 'react/no-will-update-set-state': 'error', | ||
| 'react/prefer-es6-class': 'error', | ||
| 'react/style-prop-object': 'error', | ||
| 'react/void-dom-elements-no-children': 'error', | ||
|
|
||
| // === TypeScript === | ||
| 'typescript/dot-notation': 'error', | ||
| 'typescript/no-duplicate-enum-values': 'error', | ||
| 'typescript/no-empty-object-type': 'error', | ||
| 'typescript/no-extra-non-null-assertion': 'error', | ||
| 'typescript/no-misused-new': 'error', | ||
| 'typescript/no-namespace': 'error', | ||
| 'typescript/no-non-null-asserted-optional-chain': 'error', | ||
| 'typescript/no-require-imports': 'error', | ||
| 'typescript/no-this-alias': 'error', | ||
| 'typescript/no-unnecessary-type-constraint': 'error', | ||
| 'typescript/no-unsafe-declaration-merging': 'error', | ||
| 'typescript/no-unsafe-function-type': 'error', | ||
| 'typescript/no-wrapper-object-types': 'error', | ||
| 'typescript/prefer-as-const': 'error', | ||
| 'typescript/triple-slash-reference': 'error', | ||
| 'typescript/array-type': ['error', { default: 'array-simple' }], | ||
| 'typescript/unified-signatures': 'warn', | ||
| 'typescript/consistent-type-imports': ['error', { fixStyle: 'inline-type-imports' }], | ||
| 'typescript/no-import-type-side-effects': 'error', | ||
|
|
||
| // === eslint-plugin-smarthr === | ||
| 'eslint-plugin-smarthr/a11y-anchor-has-href-attribute': 'error', | ||
| 'eslint-plugin-smarthr/a11y-aria-labelledby': 'warn', | ||
| 'eslint-plugin-smarthr/a11y-clickable-element-has-text': 'error', | ||
| 'eslint-plugin-smarthr/a11y-form-control-in-form': 'error', | ||
| 'eslint-plugin-smarthr/a11y-heading-in-sectioning-content': 'error', | ||
| 'eslint-plugin-smarthr/a11y-help-link-with-support-href': 'error', | ||
| 'eslint-plugin-smarthr/a11y-image-has-alt-attribute': 'error', | ||
| 'eslint-plugin-smarthr/a11y-input-has-name-attribute': 'error', | ||
| 'eslint-plugin-smarthr/a11y-input-in-form-control': 'error', | ||
| 'eslint-plugin-smarthr/a11y-numbered-text-within-ol': 'error', | ||
| 'eslint-plugin-smarthr/a11y-prohibit-checkbox-or-radio-in-table-cell': 'error', | ||
| 'eslint-plugin-smarthr/a11y-prohibit-input-maxlength-attribute': 'error', | ||
| 'eslint-plugin-smarthr/a11y-prohibit-input-placeholder': 'error', | ||
| 'eslint-plugin-smarthr/a11y-prohibit-overflow-hidden': 'warn', | ||
| 'eslint-plugin-smarthr/a11y-prohibit-sectioning-content-in-form': 'error', | ||
| 'eslint-plugin-smarthr/a11y-prohibit-useless-sectioning-fragment': 'error', | ||
| 'eslint-plugin-smarthr/a11y-scroller-has-tabindex': 'warn', | ||
| 'eslint-plugin-smarthr/a11y-trigger-has-button': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-async-current-target': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-button-element': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-date': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-data-test-attribute': 'off', | ||
| 'eslint-plugin-smarthr/best-practice-for-interactive-element': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-layouts': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-nested-attributes-array-index': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-optional-chaining': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-prohibit-import-smarthr-ui-local': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-remote-trigger-dialog': 'error', | ||
| 'eslint-plugin-smarthr/best-practice-for-rest-parameters': 'off', | ||
| 'eslint-plugin-smarthr/best-practice-for-spread-syntax': ['error', { fix: true }], | ||
| 'eslint-plugin-smarthr/best-practice-for-tailwind-prohibit-root-margin': 'off', | ||
| 'eslint-plugin-smarthr/best-practice-for-tailwind-variants': 'off', | ||
| 'eslint-plugin-smarthr/best-practice-for-text-component': 'warn', | ||
| 'eslint-plugin-smarthr/best-practice-for-unnesessary-early-return': 'off', | ||
| 'eslint-plugin-smarthr/component-name': 'error', | ||
| 'eslint-plugin-smarthr/design-system-guideline-prohibit-dialog-button-icon': 'warn', | ||
| 'eslint-plugin-smarthr/design-system-guideline-prohibit-double-icons': 'off', | ||
| 'eslint-plugin-smarthr/format-import-path': 'off', | ||
| 'eslint-plugin-smarthr/format-translate-component': 'off', | ||
| 'eslint-plugin-smarthr/no-import-other-domain': 'off', | ||
| 'eslint-plugin-smarthr/prohibit-export-array-type': 'error', | ||
| 'eslint-plugin-smarthr/prohibit-file-name': 'off', | ||
| 'eslint-plugin-smarthr/prohibit-import': 'off', | ||
| 'eslint-plugin-smarthr/prohibit-path-within-template-literal': 'off', | ||
| 'eslint-plugin-smarthr/require-barrel-import': 'error', | ||
| 'eslint-plugin-smarthr/require-declaration': 'off', | ||
| 'eslint-plugin-smarthr/require-export': 'off', | ||
| 'eslint-plugin-smarthr/require-i18n-text': 'warn', | ||
| 'eslint-plugin-smarthr/require-import': 'off', | ||
| 'eslint-plugin-smarthr/trim-props': 'error', | ||
| }, | ||
| } | ||
|
|
||
| export default config | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| { | ||
| "name": "oxlint-config-smarthr", | ||
| "version": "0.1.0", | ||
| "description": "A sharable oxlint config for SmartHR", | ||
| "type": "module", | ||
| "exports": { | ||
| ".": { | ||
| "import": "./index.js" | ||
| } | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+git@github.com:kufu/tamatebako.git", | ||
| "directory": "packages/oxlint-config-smarthr" | ||
| }, | ||
| "scripts": { | ||
| "test": "oxlint --config index.js --print-config > /dev/null" | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 単体テスト的なものですが、eslint-config-smarthr 側でやっているスナップショットの取得は、Oxlint がバイナリで動いてる都合再現できなかったので、設定ファイルの出力ができるかどうかだけを見ています。 少なくとも構文ミスや、存在しないプラグインの参照といったミスがある場合は失敗するようになってます。 |
||
| }, | ||
| "keywords": [ | ||
| "oxlint" | ||
| ], | ||
| "author": "SmartHR", | ||
| "license": "MIT", | ||
| "bugs": { | ||
| "url": "https://github.com/kufu/tamatebako/issues" | ||
| }, | ||
| "homepage": "https://github.com/kufu/tamatebako/tree/master/packages/oxlint-config-smarthr", | ||
| "publishConfig": { | ||
| "registry": "https://registry.npmjs.org" | ||
| }, | ||
| "peerDependencies": { | ||
| "oxlint": ">=1.0.0", | ||
| "eslint-plugin-smarthr": ">=6.0.0" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "compilerOptions": { | ||
| "paths": { | ||
| "@/*": ["./src/*"] | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 smarthr-ui パッケージで昨年から導入しているプレリリースの仕組みを、tamatebako でも使いたく導入しています。とりあえず影響範囲を最小にするために本パッケージでのみにしてますが、トリガーのオプションを調整することで任意のパッケージで使用できるはずです。