@rdjperron/lint 0.6.0 → 0.8.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.
@@ -10,6 +10,8 @@ const plugin = {
10
10
  };
11
11
  /** Every rule the plugin registers, prefixed. The verify bin puts all of them at error. */
12
12
  const RULE_IDS = [
13
+ "rdjperron/convex-checked-constructors",
14
+ "rdjperron/convex-require-validators",
13
15
  "rdjperron/no-array-filter-map",
14
16
  "rdjperron/no-chained-type-assertions",
15
17
  "rdjperron/no-conditional-empty-object-spread",
@@ -207,6 +209,60 @@ function expo(files, options = {}) {
207
209
  });
208
210
  return overrides;
209
211
  }
212
+ /** Convex's own plugin, loaded by the override `convex()` returns rather than at the top level. */
213
+ const convexPlugin = {
214
+ name: "@convex-dev",
215
+ specifier: "@convex-dev/eslint-plugin"
216
+ };
217
+ /**
218
+ * The Convex backend: Convex's own rules, loaded from `@convex-dev/eslint-plugin` through this
219
+ * override's `jsPlugins`, and the two `rdjperron/convex-*` rules.
220
+ *
221
+ * oxlint gives a JS plugin no type information, so `explicit-table-ids` and
222
+ * `no-collect-in-query` run on their syntax fallbacks: each reports without its autofix, and
223
+ * matches the `x.db.method(...)` and `x.db.query(...)...collect()` chains by shape.
224
+ */
225
+ function convex(files, options = {}) {
226
+ const { wrapper, wrapperImports, returns = true, tests: testFiles, hint } = options;
227
+ const located = wrapper === void 0 ? {} : wrapperImports === void 0 ? { wrapper } : {
228
+ wrapper,
229
+ wrapperImports
230
+ };
231
+ const rules = {
232
+ "@convex-dev/no-old-registered-function-syntax": "error",
233
+ "@convex-dev/explicit-table-ids": "error",
234
+ "@convex-dev/no-filter-in-query": "error",
235
+ "@convex-dev/no-top-of-hour-crons": "error",
236
+ "@convex-dev/no-schema-import-cycle": "error",
237
+ "@convex-dev/no-duplicate-indexes": "error",
238
+ "@convex-dev/no-process-env": "error",
239
+ "@convex-dev/no-collect-in-query": "error",
240
+ "@convex-dev/require-args-validator": "off",
241
+ "@convex-dev/import-wrong-runtime": "off",
242
+ "@convex-dev/require-access-control": "off",
243
+ "rdjperron/convex-require-validators": ["error", {
244
+ ...located,
245
+ returns
246
+ }]
247
+ };
248
+ if (wrapper !== void 0) rules["rdjperron/convex-checked-constructors"] = ["error", hint === void 0 ? located : {
249
+ ...located,
250
+ hint
251
+ }];
252
+ const overrides = [{
253
+ files,
254
+ jsPlugins: [convexPlugin],
255
+ rules
256
+ }];
257
+ if (testFiles !== void 0) overrides.push({
258
+ files: testFiles,
259
+ rules: {
260
+ "@convex-dev/no-collect-in-query": "off",
261
+ "@convex-dev/no-filter-in-query": "off"
262
+ }
263
+ });
264
+ return overrides;
265
+ }
210
266
  /** Test files: four rules whose premise a test does not hold. */
211
267
  function tests(files) {
212
268
  return [{
@@ -341,6 +397,6 @@ const ignore = [
341
397
  /** The pre-commit entry: `vp check --fix` is defined for JS and TS sources, nothing else. */
342
398
  const staged = { "*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}": "vp check --fix" };
343
399
  //#endregion
344
- export { i18n as a, react as c, staged as d, tests as f, fmt as i, recommended as l, decoders as n, ignore as o, expo as r, plugin as s, RULE_IDS as t, restrictedImports as u };
400
+ export { expo as a, ignore as c, recommended as d, restrictedImports as f, decoders as i, plugin as l, tests as m, convex as n, fmt as o, staged as p, convexPlugin as r, i18n as s, RULE_IDS as t, react as u };
345
401
 
346
- //# sourceMappingURL=config-CD2iCM6L.mjs.map
402
+ //# sourceMappingURL=config-BCudqv3_.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-BCudqv3_.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["/**\n * Config data for a consumer's `vite.config.ts` (or `.oxlintrc.ts`).\n *\n * The types below are declared locally rather than imported from `oxlint`:\n * `oxlint` is never a dependency of this package (`vp migrate` strips one, and a\n * direct dependency installs a second linter beside the Vite+ IDE stub), and a\n * consumer that installs only `vite-plus` has no guaranteed path to oxlint's own\n * `.d.ts`. They are structurally compatible with `OxlintConfig` and\n * `OxlintOverride`, checked by a consumer-shaped config in\n * `tests/consumer-config.ts`: arrays are mutable (oxlint's are), and `plugins` is\n * oxlint's own literal union, because a bare `string[]` is not assignable to it.\n */\n\n/** A severity as oxlint spells it in a config; the numeric forms are not used here. */\ntype Severity = \"off\" | \"warn\" | \"error\";\n\n/** A rule entry: a severity, or a severity followed by the rule's own options. */\ntype RuleEntry = Severity | [Severity, ...unknown[]];\n\ninterface Rules {\n [ruleId: string]: RuleEntry;\n}\n\n/** oxlint's built-in plugins, the values its `plugins` field accepts. */\ntype BuiltinPlugin =\n | \"eslint\"\n | \"import\"\n | \"jest\"\n | \"jsdoc\"\n | \"jsx-a11y\"\n | \"nextjs\"\n | \"node\"\n | \"oxc\"\n | \"promise\"\n | \"react\"\n | \"react-perf\"\n | \"typescript\"\n | \"unicorn\"\n | \"vitest\"\n | \"vue\";\n\n/** oxlint's rule categories, the keys its `categories` field accepts. */\ntype Category =\n | \"correctness\"\n | \"nursery\"\n | \"pedantic\"\n | \"perf\"\n | \"restriction\"\n | \"style\"\n | \"suspicious\";\n\ninterface JsPlugin {\n name: string;\n specifier: string;\n}\n\nexport interface Override {\n files: string[];\n excludeFiles?: string[];\n plugins?: BuiltinPlugin[];\n env?: { [name: string]: boolean };\n jsPlugins?: JsPlugin[];\n rules?: Rules;\n}\n\nexport interface Config {\n jsPlugins?: JsPlugin[];\n plugins?: BuiltinPlugin[];\n categories?: { [category in Category]?: Severity };\n rules?: Rules;\n overrides?: Override[];\n options?: { typeAware?: boolean; typeCheck?: boolean };\n}\n\n/**\n * The plugin entry. The alias is `rdjperron`, which is also the prefix in every\n * diagnostic and every disable comment, so a consumer that renames it renames\n * its own rule keys too.\n */\nexport const plugin: JsPlugin = { name: \"rdjperron\", specifier: \"@rdjperron/lint\" };\n\n/** Every rule the plugin registers, prefixed. The verify bin puts all of them at error. */\nexport const RULE_IDS = [\n \"rdjperron/convex-checked-constructors\",\n \"rdjperron/convex-require-validators\",\n \"rdjperron/no-array-filter-map\",\n \"rdjperron/no-chained-type-assertions\",\n \"rdjperron/no-conditional-empty-object-spread\",\n \"rdjperron/no-hardcoded-jsx-text\",\n \"rdjperron/no-known-value-widening\",\n \"rdjperron/no-module-mocking\",\n \"rdjperron/no-object-parameters\",\n \"rdjperron/no-reduce-accumulator-copy\",\n \"rdjperron/no-reflect-apply\",\n \"rdjperron/no-reflect-get\",\n \"rdjperron/no-runtime-typeof\",\n \"rdjperron/no-shape-in-symbol-names\",\n \"rdjperron/no-unknown-parameters\",\n \"rdjperron/no-unknown-returns\",\n \"rdjperron/no-unknown-type-aliases\",\n \"rdjperron/no-unsafe-dictionary-type\",\n \"rdjperron/no-use-effect\",\n \"rdjperron/no-widen-then-assert\",\n \"rdjperron/require-safety-comment-for-type-assertion\",\n \"rdjperron/static-public-env\",\n] as const;\n\nexport type RuleId = (typeof RULE_IDS)[number];\n\n/**\n * The base config, for `lint: { extends: [recommended] }`.\n *\n * Measured through `extends` on vite-plus 0.3.1 / oxlint 1.81.0 (2026-09-17):\n * `jsPlugins`, `rules`, `overrides`, `plugins`, `categories` and `options` are\n * inherited by the consumer's config, and the consumer's own entries win.\n * `env`, `settings` and `ignorePatterns` are not inherited, which is why this\n * object carries none of them and the consumer keeps writing its own.\n */\nexport const recommended: Config = {\n jsPlugins: [plugin],\n // Naming any plugin replaces oxlint's default set, so this is the whole set the\n // rules below need: `promise/*` and `typescript/*` are silently dropped without it.\n plugins: [\"typescript\", \"unicorn\", \"oxc\", \"import\", \"promise\", \"node\"],\n categories: {\n correctness: \"error\",\n suspicious: \"warn\",\n perf: \"warn\",\n },\n // `options` merges key by key through `extends`, so a consumer writing\n // `options: { typeCheck: false }` still gets `typeAware` (measured on vite-plus\n // 0.3.1 / oxlint 1.81.0, 2026-09-19). The type-aware rules below need it on.\n options: { typeAware: true },\n rules: {\n // The anti-slop rules. Measured on stack-lab 2026-08-20 and 2026-09-13, and\n // on rummy 2026-09-16 (vite-plus 0.3.1, oxlint 1.81.0): on real hand-written\n // code they fire only on the patterns they exist to reject, so a hit is the\n // finding. Land a new one at `warn` in the consumer, fix or scope what\n // fires, then let this default take over.\n \"rdjperron/no-array-filter-map\": \"error\",\n \"rdjperron/no-chained-type-assertions\": \"error\",\n \"rdjperron/no-conditional-empty-object-spread\": \"error\",\n \"rdjperron/no-known-value-widening\": \"error\",\n \"rdjperron/no-module-mocking\": \"error\",\n \"rdjperron/no-object-parameters\": \"error\",\n \"rdjperron/no-reduce-accumulator-copy\": \"error\",\n \"rdjperron/no-reflect-apply\": \"error\",\n \"rdjperron/no-reflect-get\": \"error\",\n // A `typeof` inside a type predicate is the decode the rule asks for, named\n // and reusable, and the pack already exempts a predicate's subject from\n // `no-unknown-parameters` (rummy, 2026-09-16).\n \"rdjperron/no-runtime-typeof\": [\"error\", { allowInTypeGuards: true }],\n \"rdjperron/no-shape-in-symbol-names\": \"error\",\n \"rdjperron/no-unknown-parameters\": \"error\",\n \"rdjperron/no-unknown-returns\": \"error\",\n \"rdjperron/no-unknown-type-aliases\": \"error\",\n \"rdjperron/no-unsafe-dictionary-type\": \"error\",\n \"rdjperron/no-widen-then-assert\": \"error\",\n \"rdjperron/require-safety-comment-for-type-assertion\": \"error\",\n // Derived state, event handlers and a reactive query cover every case; the\n // one sanctioned wrapper is named through `react(files, { useEffectAllowedIn })`.\n \"rdjperron/no-use-effect\": \"error\",\n\n // `no-hardcoded-jsx-text` and `static-public-env` are absent on purpose:\n // they belong to a translated app and to an Expo app. `i18n()` and `expo()`\n // switch them on for the files that want them.\n\n // Quadratic by construction, and the sibling of `no-reduce-accumulator-copy`,\n // which is already at error. `categories.perf` alone only warns. Measured\n // 2026-09-19 (vite-plus 0.3.1, oxlint 1.81.0): zero hits on this repo's 32\n // files, on rummy's 330 and on stack-lab's 57.\n \"oxc/no-accumulating-spread\": \"error\",\n\n // Type-aware rules, which `options.typeAware` above switches on.\n \"typescript/no-floating-promises\": \"error\",\n \"typescript/no-misused-promises\": \"error\",\n \"typescript/await-thenable\": \"error\",\n // Measured on rummy 2026-09-16 before the cleanup: 5, 5 and 1 hits, zero after.\n \"typescript/no-unnecessary-type-assertion\": \"error\",\n \"typescript/no-misused-spread\": \"error\",\n \"typescript/require-array-sort-compare\": \"error\",\n \"typescript/no-explicit-any\": \"warn\",\n\n \"prefer-const\": [\"error\", { destructuring: \"all\" }],\n \"no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\", varsIgnorePattern: \"^_\" }],\n // oxlint 1.77 moved this into `suspicious`, where it contradicts the `^_`\n // convention above. The prefix wins.\n \"no-underscore-dangle\": \"off\",\n eqeqeq: [\"error\", \"always\", { null: \"ignore\" }],\n\n // Deliberate off-switches, held by both consumers since the 2026-08-20 setup.\n \"typescript/no-unsafe-type-assertion\": \"off\",\n \"no-await-in-loop\": \"off\",\n \"unicorn/consistent-function-scoping\": \"off\",\n \"promise/always-return\": \"off\",\n },\n};\n\nexport interface ReactOptions {\n /**\n * The globals these files run with, as oxlint's `env`, defaulting to\n * `{ browser: true }`. A React Native app has no DOM: oxlint ships no\n * `react-native` environment, and `{ \"shared-node-browser\": true }` is the\n * closest one, the timers and the console both runtimes agree on.\n */\n env?: { [name: string]: boolean };\n /**\n * The one file allowed to call `useEffect`, as a path. Its name goes into the\n * `no-use-effect` hint for every React file, and the rule is off for it.\n */\n useEffectAllowedIn?: string;\n}\n\n/**\n * The React file set: the globals, the hooks rules, and the compiler's own\n * judgement. A consumer appends its own entries after these, because an override\n * that changes a `react/*` rule must repeat `plugins: [\"react\"]` or oxlint\n * silently drops the entry.\n */\nexport function react(files: string[], options: ReactOptions = {}): Override[] {\n const { env = { browser: true }, useEffectAllowedIn } = options;\n const rules: Rules = {\n \"react/rules-of-hooks\": \"error\",\n \"react/exhaustive-deps\": \"warn\",\n // React 19 and the automatic JSX runtime: nothing has to be in scope.\n \"react/react-in-jsx-scope\": \"off\",\n // The React Compiler's own rules: a component it silently skips is a\n // component that never memoizes.\n \"react/immutability\": \"error\",\n \"react/refs\": \"error\",\n \"react/purity\": \"error\",\n // A module that exports only components refreshes in place; any other\n // export re-runs every importer.\n \"react/only-export-components\": \"error\",\n };\n const overrides: Override[] = [{ files, plugins: [\"react\"], env, rules }];\n\n if (useEffectAllowedIn !== undefined) {\n rules[\"rdjperron/no-use-effect\"] = [\n \"error\",\n { hint: `The one sanctioned wrapper is ${useEffectAllowedIn}.` },\n ];\n overrides.push({\n // The sanctioned wrapper exists precisely so every other file can be clean.\n files: [useEffectAllowedIn],\n plugins: [\"react\"],\n rules: {\n \"rdjperron/no-use-effect\": \"off\",\n // The empty dependency array is this wrapper's contract, not an omission.\n \"react/exhaustive-deps\": \"off\",\n },\n });\n }\n\n return overrides;\n}\n\nexport interface I18nOptions {\n /**\n * The word pattern, a regex source compiled with `u`. The rule's default,\n * `\\p{L}{3,}`, reads three letters in a row as a word.\n */\n pattern?: string;\n}\n\n/** Files whose JSX text belongs in a catalogue rather than in the source. */\nexport function i18n(files: string[], options: I18nOptions = {}): Override[] {\n const { pattern } = options;\n return [\n {\n files,\n rules: {\n \"rdjperron/no-hardcoded-jsx-text\": pattern === undefined ? \"error\" : [\"error\", { pattern }],\n },\n },\n ];\n}\n\n/** Every extension Metro treats as an asset, the list eslint-config-expo 10 allowed. */\nconst ASSET_EXTENSIONS = [\n \"aac\",\n \"aiff\",\n \"avif\",\n \"bmp\",\n \"caf\",\n \"db\",\n \"gif\",\n \"heic\",\n \"html\",\n \"jpeg\",\n \"jpg\",\n \"json\",\n \"m4a\",\n \"m4v\",\n \"mov\",\n \"mp3\",\n \"mp4\",\n \"mpeg\",\n \"mpg\",\n \"otf\",\n \"pdf\",\n \"png\",\n \"psd\",\n \"svg\",\n \"ttf\",\n \"wav\",\n \"webm\",\n \"webp\",\n \"xml\",\n \"yaml\",\n \"yml\",\n \"zip\",\n];\n\nexport interface ExpoOptions {\n /** The extensions this app's `metro.config.js` adds to `resolver.assetExts`, without the dot. */\n assetExts?: string[];\n /**\n * The files React renders, if the app has any. They get the two `react/*` rules\n * an Expo app needs, on their own override because `react` is not in the\n * inherited plugin set.\n */\n reactFiles?: string[];\n}\n\n/**\n * The React Native side: what Expo's bundler inlines, what Metro bundles, and what\n * Hermes can be trusted to run.\n *\n * `typescript/no-require-imports` is relaxed here rather than switched on: the\n * repo-wide ban is the consumer's to write, and this is the one file set where\n * `require()` of an asset is how that asset enters the bundle.\n */\nexport function expo(files: string[], options: ExpoOptions = {}): Override[] {\n const { assetExts = [], reactFiles } = options;\n const extensions = [...new Set([...ASSET_EXTENSIONS, ...assetExts])].toSorted();\n const overrides: Override[] = [\n {\n files,\n rules: {\n \"rdjperron/static-public-env\": \"error\",\n // Measured on rummy's 330 files 2026-09-19 (vite-plus 0.3.1, oxlint 1.81.0):\n // zero hits, in a run that reported a non-asset `require()` from a probe file.\n \"typescript/no-require-imports\": [\"error\", { allow: [`\\\\.(${extensions.join(\"|\")})$`] }],\n // Hermes has no iterator helpers and its `toSorted` is unverified, so the copy\n // this rule asks for is not one the phone can be trusted to run.\n \"unicorn/no-array-sort\": \"off\",\n },\n },\n ];\n\n if (reactFiles !== undefined) {\n overrides.push({\n files: reactFiles,\n plugins: [\"react\"],\n rules: {\n // `Gesture.Pan()` reads as a component call to this rule; the React Compiler\n // compiles that component itself and is the judge.\n \"react/capitalized-calls\": \"off\",\n // expo-status-bar's `style` prop is a string by API design.\n \"react/style-prop-object\": [\"error\", { allow: [\"StatusBar\"] }],\n },\n });\n }\n\n return overrides;\n}\n\n/** Convex's own plugin, loaded by the override `convex()` returns rather than at the top level. */\nexport const convexPlugin: JsPlugin = {\n name: \"@convex-dev\",\n specifier: \"@convex-dev/eslint-plugin\",\n};\n\nexport interface ConvexOptions {\n /**\n * The module that builds the project's checked constructors, such as\n * `convex/lib/functions.ts`. It switches `convex-checked-constructors` on, exempts that one\n * file, and makes every name imported from it a constructor `convex-require-validators`\n * follows. A relative path is looked for from the working directory upward; an absolute one\n * pins the file.\n */\n wrapper?: string;\n /**\n * Spellings other than a relative path that import the wrapper, such as\n * `@/convex/lib/functions` from a tsconfig `paths` alias. The rules cannot read a bundler's or\n * tsconfig's aliases, so only the spellings listed here, compared exactly as written, name the\n * wrapper.\n */\n wrapperImports?: string[];\n /** Whether every function must also declare `returns`. On by default. */\n returns?: boolean;\n /**\n * Test code, where a query reads a table the test filled itself, so `.collect()` and\n * `.filter()` cost nothing.\n */\n tests?: string[];\n /** The project's own reason for its checked constructors, added to each `convex-checked-constructors` finding. */\n hint?: string;\n}\n\n/**\n * The Convex backend: Convex's own rules, loaded from `@convex-dev/eslint-plugin` through this\n * override's `jsPlugins`, and the two `rdjperron/convex-*` rules.\n *\n * oxlint gives a JS plugin no type information, so `explicit-table-ids` and\n * `no-collect-in-query` run on their syntax fallbacks: each reports without its autofix, and\n * matches the `x.db.method(...)` and `x.db.query(...)...collect()` chains by shape.\n */\nexport function convex(files: string[], options: ConvexOptions = {}): Override[] {\n const { wrapper, wrapperImports, returns = true, tests: testFiles, hint } = options;\n const located =\n wrapper === undefined\n ? {}\n : wrapperImports === undefined\n ? { wrapper }\n : { wrapper, wrapperImports };\n const validators = { ...located, returns };\n // Measured 2026-10-12 with @convex-dev/eslint-plugin 5.0.0 over `convex/**` of bidraft\n // (vite-plus 0.3.3, oxlint 1.83.0), atlas (0.3.3, 1.83.0) and rummy (0.3.1, 1.81.0), counts in\n // that order. Every rule at error found nothing or found real faults, with two exceptions noted\n // on their line that keep a disable comment. Measured again the same day after each round of\n // review fixes, bidraft at 5e216e9c, e58015ef and 8f9191a7: every count unchanged except\n // bidraft's collects in test code, 111 from e58015ef on as its own tests grew.\n const rules: Rules = {\n // 0, 0, 0.\n \"@convex-dev/no-old-registered-function-syntax\": \"error\",\n // 0, 1, 1, both a one-argument `ctx.db.delete(row._id)` in a loop over table names: the\n // table-scoped overload refuses a union, so that call keeps a disable comment.\n \"@convex-dev/explicit-table-ids\": \"error\",\n // 0, 0, 0 in deployed code; 1 in a bidraft test, which `tests` exempts.\n \"@convex-dev/no-filter-in-query\": \"error\",\n // 2, 1, 0, every one a daily cron at minute 0.\n \"@convex-dev/no-top-of-hour-crons\": \"error\",\n // 0, 0, 0.\n \"@convex-dev/no-schema-import-cycle\": \"error\",\n // 1, 2, 1. bidraft's is the `sessionId` index of `authRefreshTokens`, which @convex-dev/auth\n // queries by name, so it keeps a disable comment. The other three are real.\n \"@convex-dev/no-duplicate-indexes\": \"error\",\n // 0, 0, 1: rummy's `auth.config.ts` still reads `process.env`, the two others read `env`.\n \"@convex-dev/no-process-env\": \"error\",\n // 0, 27, 0 in deployed code, and 102, 35, 60 in tests and test helpers, which `tests`\n // exempts. atlas lands it at warn until each of its 27 is bounded or carries its reason.\n \"@convex-dev/no-collect-in-query\": \"error\",\n // `convex-require-validators` reports every omission this one does, on more functions, so\n // with both on one missing `args` would be two findings.\n \"@convex-dev/require-args-validator\": \"off\",\n // 2, 1, 1, all false: the rule looks for `use node` in the first 100 characters of the\n // imported file, and each hit was a comment saying the file has no `\"use node\"`. None of the\n // three repos has a `\"use node\"` file.\n \"@convex-dev/import-wrong-runtime\": \"off\",\n // 0, 0, 26. It sees only the raw registrars, so a function built by a checked constructor is\n // invisible to it, and it wants a top-level call named like `requireUser`: the five of rummy's\n // 26 read so far check the caller through `currentUser`, `getAuthUserId` or an internal query.\n // `convex-checked-constructors` is the stronger check where a project has a wrapper.\n \"@convex-dev/require-access-control\": \"off\",\n // 0, 3, 0 with `returns` required: bidraft and rummy declare both validators on every\n // function, and atlas's 3 are in a probe file that never deploys.\n \"rdjperron/convex-require-validators\": [\"error\", validators],\n };\n if (wrapper !== undefined) {\n // 2, 0, no wrapper: bidraft's 2 are its probe, which reads `ctx.auth` on purpose.\n rules[\"rdjperron/convex-checked-constructors\"] = [\n \"error\",\n hint === undefined ? located : { ...located, hint },\n ];\n }\n const overrides: Override[] = [{ files, jsPlugins: [convexPlugin], rules }];\n // No `jsPlugins` here: once any override names a JS plugin, its rules resolve in every override\n // (measured on vite-plus 0.3.0 to 0.3.3, 2026-10-12).\n if (testFiles !== undefined) {\n overrides.push({\n files: testFiles,\n rules: {\n \"@convex-dev/no-collect-in-query\": \"off\",\n \"@convex-dev/no-filter-in-query\": \"off\",\n },\n });\n }\n return overrides;\n}\n\n/** Test files: four rules whose premise a test does not hold. */\nexport function tests(files: string[]): Override[] {\n return [\n {\n files,\n rules: {\n // A fixture is allowed to be the wrong type on purpose.\n \"typescript/no-explicit-any\": \"off\",\n \"typescript/no-non-null-assertion\": \"off\",\n // `expect(typeof x).toBe(\"function\")` reads as an unparsed boundary, but\n // asserting the shape of your own public API is the point of the assertion.\n \"rdjperron/no-runtime-typeof\": \"off\",\n // A justification on every assertion in a test is noise (53 measured on\n // rummy, 2026-09-16).\n \"rdjperron/require-safety-comment-for-type-assertion\": \"off\",\n },\n },\n ];\n}\n\n/** One banned module or named import, as `no-restricted-imports` spells a path. */\nexport interface RestrictedPath {\n name: string;\n importNames?: string[];\n allowImportNames?: string[];\n message: string;\n}\n\n/** One banned glob group, as `no-restricted-imports` spells a pattern. */\nexport interface RestrictedPattern {\n group: string[];\n message: string;\n importNames?: string[];\n allowImportNames?: string[];\n caseSensitive?: boolean;\n}\n\n/**\n * One file set and the restrictions it carries: either the whole list by name, or\n * another scope's list plus and minus named entries.\n */\nexport type RestrictionScope<Name extends string, Parent extends string> =\n | { files: string[]; use: Name[]; from?: never; add?: never; drop?: never }\n | { files: string[]; use?: never; from: Parent; add?: Name[]; drop?: Name[] };\n\n/**\n * `no-restricted-imports` for every file set at once. Two overrides matching one\n * file do not merge, so each scope needs its whole list written out; a consumer\n * doing that by hand restates the same list per scope and lifts a ban by\n * forgetting one. Here each scope says which scope it starts `from` and what it\n * `add`s and `drop`s, and this expands them.\n *\n * One override per scope comes out in declaration order, so the consumer declares\n * broad to narrow. The broadest scope is an ordinary override on `files: [\"**\"]`,\n * which behaves exactly like the top-level rule (measured on vite-plus 0.3.1 and\n * oxlint 1.81.0, 2026-09-19).\n *\n * TypeScript rejects a name that is no key of `paths` or `patterns`, a `from`\n * naming no scope at all, and `use` beside `from`. A `from` naming a scope\n * declared later, a `drop` of a name the parent does not restrict and an `add` of\n * one it already does throw here, because resolution order is what decides them.\n */\nexport function restrictedImports<\n Paths extends { [name: string]: RestrictedPath },\n Patterns extends { [name: string]: RestrictedPattern },\n Scopes extends {\n [scope in keyof Scopes]: RestrictionScope<\n Extract<keyof Paths | keyof Patterns, string>,\n Extract<keyof Scopes, string>\n >;\n },\n>(config: { paths: Paths; patterns: Patterns; scopes: Scopes }): Override[] {\n const { paths, patterns, scopes } = config;\n const known = new Set([...Object.keys(paths), ...Object.keys(patterns)]);\n const resolved = new Map<string, Set<string>>();\n const overrides: Override[] = [];\n\n const entries: [string, RestrictionScope<string, string>][] = Object.entries(scopes);\n for (const [scope, spec] of entries) {\n const named = spec.use ?? [...(spec.add ?? []), ...(spec.drop ?? [])];\n for (const name of named) {\n if (!known.has(name)) {\n throw new Error(\n `restrictedImports: scope \"${scope}\" names \"${name}\", which is neither a path nor a pattern.`,\n );\n }\n }\n\n let chosen: Set<string>;\n if (spec.use !== undefined) {\n chosen = new Set(spec.use);\n } else {\n const parent = resolved.get(spec.from);\n if (parent === undefined) {\n throw new Error(\n `restrictedImports: scope \"${scope}\" starts from \"${spec.from}\", which is not a scope declared before it.`,\n );\n }\n chosen = new Set(parent);\n for (const name of spec.drop ?? []) {\n if (!chosen.delete(name)) {\n throw new Error(\n `restrictedImports: scope \"${scope}\" drops \"${name}\", which \"${spec.from}\" does not restrict.`,\n );\n }\n }\n for (const name of spec.add ?? []) {\n if (chosen.has(name)) {\n throw new Error(\n `restrictedImports: scope \"${scope}\" adds \"${name}\", which \"${spec.from}\" already restricts.`,\n );\n }\n chosen.add(name);\n }\n }\n\n resolved.set(scope, chosen);\n overrides.push({\n files: spec.files,\n rules: {\n \"no-restricted-imports\": [\n \"error\",\n { paths: chosenFrom(paths, chosen), patterns: chosenFrom(patterns, chosen) },\n ],\n },\n });\n }\n\n return overrides;\n}\n\n/** In the order the entry was declared in, so two scopes' lists read side by side. */\nfunction chosenFrom<Entry>(table: { [name: string]: Entry }, chosen: ReadonlySet<string>): Entry[] {\n return Object.entries(table).flatMap(([name, entry]) => (chosen.has(name) ? [entry] : []));\n}\n\nexport interface DecodersOptions {\n /**\n * The sentence appended to both findings. The default names the files in\n * `files`, which is what a reader has to know to act on either message.\n */\n hint?: string;\n}\n\n/** `a`, `a or b`, `a, b or c`. */\nfunction orList(names: string[]): string {\n const last = names.at(-1) ?? \"\";\n return names.length > 1 ? `${names.slice(0, -1).join(\", \")} or ${last}` : last;\n}\n\n/**\n * The decoder modules, the one place per kind of outside value where the parse\n * belongs. Every file gets `no-runtime-typeof` and `no-unknown-parameters` at\n * error carrying a hint that names these files, because moving the check into one\n * of them is the fix in both cases, and `no-runtime-typeof` is off inside them.\n *\n * `no-unknown-parameters` and `no-unsafe-dictionary-type` stay on in the decoders.\n * A decoder that needs either off says so in its own override with its own\n * measured count, and one switch for the whole set would cover the files that\n * never needed it.\n *\n * Place it before `tests()`, which switches `no-runtime-typeof` off for test files.\n */\nexport function decoders(files: string[], options: DecodersOptions = {}): Override[] {\n const { hint = `Decode the value in ${orList(files)}, then call that decoder from here.` } =\n options;\n return [\n {\n files: [\"**\"],\n rules: {\n // A later override replaces a rule's whole entry, options included (measured\n // on vite-plus 0.3.1 / oxlint 1.81.0, 2026-09-19), so `allowInTypeGuards` is\n // restated rather than inherited from `recommended`.\n \"rdjperron/no-runtime-typeof\": [\"error\", { allowInTypeGuards: true, hint }],\n \"rdjperron/no-unknown-parameters\": [\"error\", { hint }],\n },\n },\n {\n // Inside a decoder a `typeof` is the parse, not a narrowing in place of one.\n files,\n rules: { \"rdjperron/no-runtime-typeof\": \"off\" },\n },\n ];\n}\n\n/** The formatting both consumers settled on. Spread it and add what is yours. */\nexport const fmt = {\n printWidth: 100,\n singleQuote: false,\n semi: true,\n tabWidth: 2,\n useTabs: false,\n};\n\n/**\n * Paths no linter and no formatter should walk: build output, dependencies, the\n * directories AI coding agents scribble in, and the Vitest JSON report. Spread\n * it into `ignorePatterns` and append the repo's own.\n */\nexport const ignore: string[] = [\n \"node_modules/**\",\n \"**/node_modules/**\",\n \"dist/**\",\n \"**/dist/**\",\n ...[\n \".agents\",\n \".claude\",\n \".codex\",\n \".continue\",\n \".cursor\",\n \".gemini\",\n \".opencode\",\n \".pi\",\n \".roo\",\n \".windsurf\",\n ].flatMap((dir) => [`${dir}/**`, `**/${dir}/**`]),\n \"**/test-results.json\",\n];\n\n/** The pre-commit entry: `vp check --fix` is defined for JS and TS sources, nothing else. */\nexport const staged = {\n \"*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}\": \"vp check --fix\",\n};\n"],"mappings":"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"}
package/dist/config.d.mts CHANGED
@@ -54,7 +54,7 @@ export interface Config {
54
54
  */
55
55
  export declare const plugin: JsPlugin;
56
56
  /** Every rule the plugin registers, prefixed. The verify bin puts all of them at error. */
57
- export declare const RULE_IDS: readonly ["rdjperron/no-array-filter-map", "rdjperron/no-chained-type-assertions", "rdjperron/no-conditional-empty-object-spread", "rdjperron/no-hardcoded-jsx-text", "rdjperron/no-known-value-widening", "rdjperron/no-module-mocking", "rdjperron/no-object-parameters", "rdjperron/no-reduce-accumulator-copy", "rdjperron/no-reflect-apply", "rdjperron/no-reflect-get", "rdjperron/no-runtime-typeof", "rdjperron/no-shape-in-symbol-names", "rdjperron/no-unknown-parameters", "rdjperron/no-unknown-returns", "rdjperron/no-unknown-type-aliases", "rdjperron/no-unsafe-dictionary-type", "rdjperron/no-use-effect", "rdjperron/no-widen-then-assert", "rdjperron/require-safety-comment-for-type-assertion", "rdjperron/static-public-env"];
57
+ export declare const RULE_IDS: readonly ["rdjperron/convex-checked-constructors", "rdjperron/convex-require-validators", "rdjperron/no-array-filter-map", "rdjperron/no-chained-type-assertions", "rdjperron/no-conditional-empty-object-spread", "rdjperron/no-hardcoded-jsx-text", "rdjperron/no-known-value-widening", "rdjperron/no-module-mocking", "rdjperron/no-object-parameters", "rdjperron/no-reduce-accumulator-copy", "rdjperron/no-reflect-apply", "rdjperron/no-reflect-get", "rdjperron/no-runtime-typeof", "rdjperron/no-shape-in-symbol-names", "rdjperron/no-unknown-parameters", "rdjperron/no-unknown-returns", "rdjperron/no-unknown-type-aliases", "rdjperron/no-unsafe-dictionary-type", "rdjperron/no-use-effect", "rdjperron/no-widen-then-assert", "rdjperron/require-safety-comment-for-type-assertion", "rdjperron/static-public-env"];
58
58
  export type RuleId = (typeof RULE_IDS)[number];
59
59
  /**
60
60
  * The base config, for `lint: { extends: [recommended] }`.
@@ -117,6 +117,43 @@ export interface ExpoOptions {
117
117
  * `require()` of an asset is how that asset enters the bundle.
118
118
  */
119
119
  export declare function expo(files: string[], options?: ExpoOptions): Override[];
120
+ /** Convex's own plugin, loaded by the override `convex()` returns rather than at the top level. */
121
+ export declare const convexPlugin: JsPlugin;
122
+ export interface ConvexOptions {
123
+ /**
124
+ * The module that builds the project's checked constructors, such as
125
+ * `convex/lib/functions.ts`. It switches `convex-checked-constructors` on, exempts that one
126
+ * file, and makes every name imported from it a constructor `convex-require-validators`
127
+ * follows. A relative path is looked for from the working directory upward; an absolute one
128
+ * pins the file.
129
+ */
130
+ wrapper?: string;
131
+ /**
132
+ * Spellings other than a relative path that import the wrapper, such as
133
+ * `@/convex/lib/functions` from a tsconfig `paths` alias. The rules cannot read a bundler's or
134
+ * tsconfig's aliases, so only the spellings listed here, compared exactly as written, name the
135
+ * wrapper.
136
+ */
137
+ wrapperImports?: string[];
138
+ /** Whether every function must also declare `returns`. On by default. */
139
+ returns?: boolean;
140
+ /**
141
+ * Test code, where a query reads a table the test filled itself, so `.collect()` and
142
+ * `.filter()` cost nothing.
143
+ */
144
+ tests?: string[];
145
+ /** The project's own reason for its checked constructors, added to each `convex-checked-constructors` finding. */
146
+ hint?: string;
147
+ }
148
+ /**
149
+ * The Convex backend: Convex's own rules, loaded from `@convex-dev/eslint-plugin` through this
150
+ * override's `jsPlugins`, and the two `rdjperron/convex-*` rules.
151
+ *
152
+ * oxlint gives a JS plugin no type information, so `explicit-table-ids` and
153
+ * `no-collect-in-query` run on their syntax fallbacks: each reports without its autofix, and
154
+ * matches the `x.db.method(...)` and `x.db.query(...)...collect()` chains by shape.
155
+ */
156
+ export declare function convex(files: string[], options?: ConvexOptions): Override[];
120
157
  /** Test files: four rules whose premise a test does not hold. */
121
158
  export declare function tests(files: string[]): Override[];
122
159
  /** One banned module or named import, as `no-restricted-imports` spells a path. */
package/dist/config.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as i18n, c as react, d as staged, f as tests, i as fmt, l as recommended, n as decoders, o as ignore, r as expo, s as plugin, t as RULE_IDS, u as restrictedImports } from "./config-CD2iCM6L.mjs";
2
- export { RULE_IDS, decoders, expo, fmt, i18n, ignore, plugin, react, recommended, restrictedImports, staged, tests };
1
+ import { a as expo, c as ignore, d as recommended, f as restrictedImports, i as decoders, l as plugin, m as tests, n as convex, o as fmt, p as staged, r as convexPlugin, s as i18n, t as RULE_IDS, u as react } from "./config-BCudqv3_.mjs";
2
+ export { RULE_IDS, convex, convexPlugin, decoders, expo, fmt, i18n, ignore, plugin, react, recommended, restrictedImports, staged, tests };