063eb09750
Co-authored-by: Danny Kim <temeddix@gmail.com> Co-committed-by: Danny Kim <temeddix@gmail.com>
2.9 KiB
2.9 KiB
description
| description |
|---|
| scripts/project-lint.ts is the repo-local plugin "project" holding the repo's rule list (typed DummyRuleMap) and repo-only rules; never published, no tests |
Every repo has scripts/project-lint.ts, copied from
cunarist/eslint-plugin-explicit-types and extended. It is a repo-local
Oxlint plugin with meta.name "project", loaded through jsPlugins in
vite.config.ts. It holds:
configs.project.rules: the repo's whole rule list beyond the published plugin configs: Deno parity rules, extras, per-rule options, and opt-outs, built-in Oxlint ids included (curly,id-match,import/no-cycle, ...).- Custom rules, enabled as
project/<rule>. Every repo hasno-disable-commentsandno-asset-imports. Since 2026-10-19 every repo also hasprefer-ascii,no-nan(a "no number" value isnull, neverNaN), and the hugoalhrecommendedports from eslint-plugin-import-structure's own lint:no-duplicate-typeofs,no-empty-yield,no-unsafe-number,no-useless-continue,no-duplicate-interfaces,no-duplicate-types,no-useless-type, andno-modifier-private.no-duplicate-awaitsandno-duplicate-voidsare covered byunicorn/no-unnecessary-awaitandtypescript/no-meaningless-void-operator, andno-enumby explicit-types.
scripts/ stays flat; don't add scripts/rules/. All rules live in the one
scripts/project-lint.ts (no file splitting), next to the plugin object and
the rule list.
import type { DummyRuleMap } from "vite-plus/lint";
const rules: DummyRuleMap = {
"id-match": ["error", "^_*[^_]*_*$|^[^a-z]*$", {/* ... */}],
curly: "error",
"project/no-disable-comments": "error",
};
const plugin = {
meta: { name: "project" },
rules: { "no-disable-comments": noDisableCommentsRule /* ... */ },
configs: { project: { rules } },
};
export default plugin;
Why DummyRuleMap and an unannotated plugin (decided 2026-10-15)
DummyRuleMap(re-exported byvite-plus/lint) is Oxlint's type forOxlintConfig.rules. Despite the name it lists every built-in rule with its options, so a typo in a rule id or option is a type error, not just a CI failure. Without it, TypeScript widens"error"tostring;as constdoesn't help because Oxlint wants mutable tuples.@eslint/core'sPluginis too loose to read back:configsis optional, any key may be missing, and a config may be an array, soprojectLint.configs.project.rulesfails invite.config.ts(and!is banned). Optional chaining still leaves the array case.- Oxlint's own
Plugintype (vite-plus/lint/plugins) has noconfigs. - Two hand-written interfaces worked but were dropped as noise; a plain config object was rejected because custom rules need the plugin form anyway and every repo should look the same.
scripts/ is tooling, not production code: never packed or published, and
no tests. Its offs sit in the Node code entry of projectOverrides; see
lint-config.