@alien_intelligence/eslint-plugin-nitpicker 0.1.0 → 0.2.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/README.md CHANGED
@@ -3,4 +3,143 @@
3
3
  <a href="https://www.alien.club" target="_blank"><img width="64px" src="https://alien-website.cdn.prismic.io/alien-website/Zrn2b0aF0TcGI3Bu_alien-logo.svg" /></a>
4
4
  <h2 align="center">@alien_intelligence/eslint-plugin-nitpicker</h2>
5
5
  <p align="center">A hyper-pedantic ESLint plugin that flags every stylistic<br />and semantic nit, specifically for AI.</p>
6
- </p>
6
+ </p>
7
+
8
+ ## What it is
9
+ Nitpicker is an ESLint plugin that enforces the small, opinionated conventions a linter usually leaves alone: comment style, JSDoc shape, spelling, decorative noise, and a few semantic anti-patterns. It is built for codebases where humans and AI agents write side by side, so every message is written to make the fix obvious without opening any docs.
10
+
11
+ Each finding is reported as a problem, a reason, and a concrete fix:
12
+ ```text
13
+ This JSDoc description is 312 characters, over the 250-character limit.
14
+ - why: A JSDoc description should summarize what something is; an oversized
15
+ one usually restates the code or explains how it is used.
16
+ - fix: Trim it to a concise summary of what it does, and drop any note about
17
+ how or where it is used.
18
+ ```
19
+
20
+ That reason and fix context is what lets an AI agent (or `eslint --fix`, where the rule supports it) resolve the nit correctly on the first pass.
21
+
22
+ ## Requirements
23
+ - **ESLint 9+**, flat config (`eslint.config.js`) only. There is no legacy `.eslintrc` support.
24
+ - A parser matching your source. For TypeScript, install [`@typescript-eslint/parser`](https://www.npmjs.com/package/@typescript-eslint/parser). Plain JavaScript uses ESLint's built-in parser.
25
+
26
+ ## Installation
27
+ ```bash
28
+ npm install --save-dev @alien_intelligence/eslint-plugin-nitpicker
29
+ ```
30
+
31
+ ## Usage
32
+ The shared configs are self-contained (they register the plugin under the `nitpicker` key for you), so the simplest setup is to drop one straight into the array:
33
+ ```js
34
+ import nitpicker from "@alien_intelligence/eslint-plugin-nitpicker"
35
+
36
+ export default [
37
+ nitpicker.configs.recommended,
38
+ ]
39
+ ```
40
+
41
+ For a TypeScript project, add a parser and scope the rules to your source files. Spreading `.rules` into a `files`-scoped block keeps the config from touching everything:
42
+ ```js
43
+ import nitpicker from "@alien_intelligence/eslint-plugin-nitpicker"
44
+ import tsParser from "@typescript-eslint/parser"
45
+
46
+ export default [
47
+ {
48
+ files: ["src/**/*.ts"],
49
+ languageOptions: {
50
+ parser: tsParser,
51
+ ecmaVersion: "latest",
52
+ sourceType: "module",
53
+ },
54
+ plugins: { nitpicker },
55
+ rules: nitpicker.configs.recommended.rules,
56
+ },
57
+ ]
58
+ ```
59
+
60
+ All rules ship as warnings. Promote any of them to errors by overriding the rule level yourself, the same way as any ESLint rule.
61
+
62
+ ## Shared configs
63
+ Nitpicker ships five shared flat configs:
64
+ | Config | What it enables |
65
+ |---------------|--------------------------------------------------------------------------------------------|
66
+ | `recommended` | The universal `base` ruleset, every rule enabled as a warning. The sensible default. |
67
+ | `base` | The same universal rules, with no framework assumptions. |
68
+ | `all` | Every rule, plus both framework rulesets opted in. The maximally pedantic setup. |
69
+ | `react` | Opts into the React ruleset for the files you scope it to. |
70
+ | `adonisjs` | Opts into the AdonisJS ruleset, and relaxes decorative separators in `start/routes` files. |
71
+
72
+ ## Rules
73
+ Every rule is part of `recommended` and enabled as a warning. The Fixable column marks rules that `eslint --fix` can resolve automatically:
74
+ | Rule | Fixable | Description |
75
+ |----------------------------------------------|---------|--------------------------------------------------------------------------------------------------|
76
+ | `nitpicker/max-jsdoc-description-length` | | Enforce a maximum character length for a JSDoc description (default 250). |
77
+ | `nitpicker/no-british-english` | yes | Disallow British spellings in identifiers and comments, reporting the American equivalent. |
78
+ | `nitpicker/no-decorative-comment-separators` | | Disallow decorative separators (banners, box-drawing, repeated dashes) inside comments. |
79
+ | `nitpicker/no-em-dash` | | Disallow the em dash character anywhere in the source. |
80
+ | `nitpicker/no-jsdoc-blank-before-tags` | yes | Disallow blank lines before JSDoc tags such as `@param` or `@returns`. |
81
+ | `nitpicker/no-line-comment-period` | yes | Disallow prose periods in `//` line comments (code-reference dots and ellipses are allowed). |
82
+ | `nitpicker/no-property-access-alias` | | Disallow a `const` whose whole value is a single property access; inline the expression instead. |
83
+ | `nitpicker/no-single-line-jsdoc` | yes | Require JSDoc comments to span multiple lines rather than a single line. |
84
+ | `nitpicker/require-framework-config` | | Warn when a file uses a framework whose Nitpicker config is not enabled. |
85
+ | `nitpicker/require-function-jsdoc` | | Require a JSDoc comment on top-level functions (React component functions are exempt). |
86
+
87
+ ### Rule options
88
+ A few rules accept options. Pass them by overriding the rule with a `["warn", { ... }]` tuple.
89
+
90
+ `max-jsdoc-description-length` takes `{ max: number }`, defaulting to `250`:
91
+ ```js
92
+ "nitpicker/max-jsdoc-description-length": ["warn", { max: 200 }],
93
+ ```
94
+
95
+ `no-british-english` takes `{ extra?: Record<string, string>; ignore?: string[] }` to extend the built-in dictionary or exempt words you want to keep:
96
+ ```js
97
+ "nitpicker/no-british-english": ["warn", {
98
+ extra: { behaviour: "behavior" },
99
+ ignore: ["colour"],
100
+ }],
101
+ ```
102
+
103
+ `no-decorative-comment-separators` takes `{ allowIn: string[] }`, a list of globs where decorative separators are tolerated:
104
+ ```js
105
+ "nitpicker/no-decorative-comment-separators": ["warn", {
106
+ allowIn: ["**/start/routes.ts"],
107
+ }],
108
+ ```
109
+
110
+ `require-framework-config` takes `{ ignore: ("adonisjs" | "react")[] }`, the frameworks to skip the nudge for:
111
+ ```js
112
+ "nitpicker/require-framework-config": ["warn", { ignore: ["react"] }],
113
+ ```
114
+
115
+ ## Framework configs
116
+ Some conventions only make sense for a given framework. Nitpicker detects when a file uses React or AdonisJS and, through `require-framework-config`, nudges you to opt into the matching config for those files. Opting in silences that nudge and applies any framework-specific tweaks.
117
+
118
+ Scope each framework config to the files it applies to:
119
+ ```js
120
+ import nitpicker from "@alien_intelligence/eslint-plugin-nitpicker"
121
+ import tsParser from "@typescript-eslint/parser"
122
+
123
+ export default [
124
+ {
125
+ files: ["src/**/*.ts", "src/**/*.tsx"],
126
+ languageOptions: { parser: tsParser, ecmaVersion: "latest", sourceType: "module" },
127
+ plugins: { nitpicker },
128
+ rules: nitpicker.configs.recommended.rules,
129
+ },
130
+ { files: ["src/**/*.tsx"], ...nitpicker.configs.react },
131
+ { files: ["app/**/*.ts", "start/**/*.ts"], ...nitpicker.configs.adonisjs },
132
+ ]
133
+ ```
134
+
135
+ ## Configuring individual rules
136
+ Turn a rule off, promote it to an error, or exempt specific files, the same way as any ESLint rule. This repo dog-foods Nitpicker on itself, and its `eslint.config.js` is a working reference for per-file exemptions:
137
+ ```js
138
+ export default [
139
+ nitpicker.configs.recommended,
140
+ {
141
+ files: ["src/lib/constants.ts"],
142
+ rules: { "nitpicker/no-em-dash": "off" },
143
+ },
144
+ ]
145
+ ```
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
- import {ESLintUtils}from'@typescript-eslint/utils';var fe={PLUGIN_NAME:"nitpicker",REPO_URL:"https://github.com/the-alien-club/eslint-plugin-nitpicker",EM_DASH:"\u2014",WORD_CHAR:/[\p{L}\p{N}_$]/u,ADONIS_SUBPATH:/^#(models|controllers|services|middleware|validators|policies|config|start|database|providers|lib)\b/,REACT_FILE:/\.[jt]sx$/,BOX_DRAWING:/[─-▟]/,PURE_SEPARATOR:/^[-=~*#_+]{3,}$/,WRAPPED_LABEL:/^[-=~*#_+]{2,}\s.*\s[-=~*#_+]{2,}$/,SUB_WORD:/[A-Z]+(?![a-z])|[A-Z][a-z]+|[a-z]+/g},a=fe;var v={colour:"color",colours:"colors",coloured:"colored",colouring:"coloring",behaviour:"behavior",behaviours:"behaviors",favourite:"favorite",favourites:"favorites",flavour:"flavor",flavours:"flavors",honour:"honor",labour:"labor",neighbour:"neighbor",normalise:"normalize",normalised:"normalized",normalising:"normalizing",normalisation:"normalization",initialise:"initialize",initialised:"initialized",initialising:"initializing",initialisation:"initialization",serialise:"serialize",serialised:"serialized",serialising:"serializing",serialisation:"serialization",organise:"organize",organised:"organized",organising:"organizing",organisation:"organization",optimise:"optimize",optimised:"optimized",optimising:"optimizing",optimisation:"optimization",customise:"customize",customised:"customized",customising:"customizing",sanitise:"sanitize",sanitised:"sanitized",sanitising:"sanitizing",synchronise:"synchronize",synchronised:"synchronized",synchronising:"synchronizing",authorise:"authorize",authorised:"authorized",authorising:"authorizing",finalise:"finalize",finalised:"finalized",finalising:"finalizing",capitalise:"capitalize",capitalised:"capitalized",capitalising:"capitalizing",categorise:"categorize",categorised:"categorized",analyse:"analyze",analysed:"analyzed",analysing:"analyzing",centre:"center",centred:"centered",centres:"centers",fibre:"fiber",metre:"meter",licence:"license",defence:"defense",offence:"offense",cancelled:"canceled",cancelling:"canceling",labelled:"labeled",labelling:"labeling",modelling:"modeling",travelled:"traveled",grey:"gray",dialogue:"dialog",catalogue:"catalog"};var F=ESLintUtils.RuleCreator(e=>`${a.REPO_URL}/blob/main/docs/rules/${e}.md`);var m=class{toRuleModule(){return F({name:this.name,meta:this.meta,defaultOptions:this.defaultOptions,create:(t,n)=>this.create(t,n)})}};function P(e,t,n){let i={};for(let[o,s]of Object.entries(e))i[o.toLowerCase()]=s;for(let[o,s]of Object.entries(t))i[o.toLowerCase()]=s;for(let o of n)delete i[o.toLowerCase()];return i}function d({problem:e,why:t,fix:n}){return `${e}
2
- - why: ${t}
3
- - fix: ${n}`}function R(e){let t=[];for(let n of e.matchAll(a.SUB_WORD))n.index!==void 0&&t.push({text:n[0],index:n.index});return t}function x(e,t){return e===e.toUpperCase()?t.toUpperCase():e.charAt(0)===e.charAt(0).toUpperCase()?t.charAt(0).toUpperCase()+t.slice(1):t}var b=class extends m{name="no-british-english";defaultOptions=[{extra:{},ignore:[]}];meta={type:"suggestion",docs:{description:"Disallow British English spellings in identifiers and comments.",recommended:true,category:"base"},fixable:"code",schema:[{type:"object",properties:{extra:{type:"object",additionalProperties:{type:"string"}},ignore:{type:"array",items:{type:"string"}}},additionalProperties:false}],messages:{british:d({problem:"British spelling `{{british}}`, this codebase uses American English.",why:"One spelling convention keeps identifiers and docs consistent and searchable",fix:"Use `{{american}}` instead"})}};create(t,n){let i=P(v,n[0]?.extra??{},n[0]?.ignore??[]),{sourceCode:o}=t;return {Identifier(s){if(!(s.parent.type==="MemberExpression"&&s.parent.property===s&&!s.parent.computed))for(let r of R(s.name)){let p=i[r.text.toLowerCase()];p!==void 0&&t.report({node:s,messageId:"british",data:{british:r.text,american:x(r.text,p)}});}},Program(){for(let s of o.getAllComments())for(let r of R(s.value)){let p=i[r.text.toLowerCase()];if(p===void 0)continue;let u=x(r.text,p),f=s.range[0]+2+r.index,y=f+r.text.length;t.report({loc:{start:o.getLocFromIndex(f),end:o.getLocFromIndex(y)},messageId:"british",data:{british:r.text,american:u},fix:ue=>ue.replaceTextRange([f,y],u)});}}}}},_=new b;function z(e){let t=e.replace(/^\s*\*?\s*/,"").trimEnd();return t.length===0?false:a.BOX_DRAWING.test(t)||a.PURE_SEPARATOR.test(t)||a.WRAPPED_LABEL.test(t)}function ye(e){let t=e.replace(/\\/g,"/"),n="^";for(let i=0;i<t.length;i++){let o=t[i];if(o===void 0)break;o==="*"?t[i+1]==="*"?(n+=".*",i++,t[i+1]==="/"&&i++):n+="[^/]*":"\\^$.|?+()[]{}".includes(o)?n+=`\\${o}`:n+=o;}return new RegExp(`${n}$`)}function U(e,t){let n=e.replace(/\\/g,"/");return t.some(i=>ye(i).test(n))}var L=class extends m{name="no-decorative-comment-separators";defaultOptions=[{allowIn:[]}];meta={type:"layout",docs:{description:"Disallow decorative separators (banners, box-drawing, repeated dashes) inside comments.",recommended:true,category:"base"},schema:[{type:"object",properties:{allowIn:{type:"array",items:{type:"string"}}},additionalProperties:false}],messages:{decorative:d({problem:"This comment uses a decorative separator.",why:"Repeated separator characters and box-drawing lines are visual noise that add nothing over a plain label",fix:"Remove the separator, a one-line label or a blank line already divides sections clearly"})}};create(t,n){let i=n[0]?.allowIn??[];if(i.length>0&&U(t.filename,i))return {};let{sourceCode:o}=t;return {Program(){for(let s of o.getAllComments()){let r=s.value.split(`
4
- `);for(let p=0;p<r.length;p++){let u=r[p];if(u===void 0||!z(u))continue;let f=s.loc.start.line+p,y=o.lines[f-1]??"";t.report({loc:{start:{line:f,column:0},end:{line:f,column:y.length}},messageId:"decorative"});}}}}}},j=new L;var N=class extends m{name="no-em-dash";defaultOptions=[];meta={type:"suggestion",docs:{description:"Disallow the em dash (\u2014) character anywhere in the source.",recommended:true},schema:[],messages:{emDash:d({problem:"Found an em dash (\u2014) character.",why:"Em dashes are typically introduced by AI-generated or auto-formatted text and are discouraged here.",fix:"Replace the em dash with a hyphen (-), a comma (,), or reword the sentence to avoid it."})}};create(t){let{sourceCode:n}=t,i=n.getText();return {Program(){for(let o=0;o<i.length;o++)i[o]===a.EM_DASH&&t.report({loc:{start:n.getLocFromIndex(o),end:n.getLocFromIndex(o+1)},messageId:"emDash"});}}}},$=new N;function h(e){return e.type==="Block"&&e.value.startsWith("*")}function J(e,t){let i=e.getCommentsBefore(t).at(-1);return i!==void 0&&h(i)}function k(e){return /^\s*\*\s*$/.test(e)}function B(e){return /^\s*\*\s*@/.test(e)}var C=class extends m{name="no-jsdoc-blank-before-tags";defaultOptions=[];meta={type:"layout",fixable:"code",docs:{description:"Disallow blank lines before JSDoc tags such as `@param` or `@returns`.",recommended:true},schema:[],messages:{blankBeforeTag:d({problem:"There is a blank line before a JSDoc tag.",why:"Tags should follow the description directly; an empty line there is noise that inflates the comment.",fix:"Remove the blank line so the tag follows on directly."})}};create(t){let{sourceCode:n}=t;return {Program(){for(let i of n.getAllComments())if(h(i)&&i.loc.start.line!==i.loc.end.line)for(let o=i.loc.start.line;o<=i.loc.end.line;o++){let s=n.lines[o-1];if(s===void 0||!k(s))continue;let r=o;for(;r<i.loc.end.line&&k(n.lines[r]??"");)r++;let p=n.lines[r];if(p!==void 0&&B(p)){let u=n.getIndexFromLoc({line:o,column:0}),f=n.getIndexFromLoc({line:r+1,column:0});t.report({loc:{start:{line:o,column:0},end:{line:r,column:s.length}},messageId:"blankBeforeTag",fix:y=>y.removeRange([u,f])});}o=r;}}}}},G=new C;function W(e){return e!==void 0&&a.WORD_CHAR.test(e)}var O=class extends m{name="no-line-comment-period";defaultOptions=[];meta={type:"layout",fixable:"code",docs:{description:"Disallow prose periods in `//` line comments (code-reference dots and ellipses are allowed).",recommended:true},schema:[],messages:{period:d({problem:"This line comment contains a period.",why:"Line comments should be short, clear fragments, not full sentences, so periods are just noise, dots inside code references like `foo.bar` are allowed.",fix:"Remove the period and keep the comment terse."})}};create(t){let{sourceCode:n}=t;return {Program(){for(let i of n.getAllComments()){if(i.type!=="Line")continue;let{value:o}=i,s=i.range[0]+2;for(let r=0;r<o.length;r++){if(o[r]!==".")continue;if(o[r+1]==="."){for(;o[r+1]===".";)r++;continue}if(W(o[r+1]))continue;let p=s+r;t.report({loc:{start:n.getLocFromIndex(p),end:n.getLocFromIndex(p+1)},messageId:"period",fix:u=>u.removeRange([p,p+1])});}}}}}},V=new O;function H(e){let t=e,n=false;for(;;){if(t.type==="ChainExpression"||t.type==="TSNonNullExpression"){t=t.expression;continue}if(t.type==="MemberExpression"){if(t.computed)return false;n=true,t=t.object;continue}break}return n&&(t.type==="Identifier"||t.type==="ThisExpression")}var I=class extends m{name="no-property-access-alias";defaultOptions=[];meta={type:"suggestion",docs:{description:"Disallow a `const` whose whole value is a single property access, inline the expression instead.",recommended:true,category:"base"},schema:[],messages:{propertyAccessAlias:d({problem:"`{{name}}` only aliases the property access `{{expression}}`.",why:"A variable that just renames a property hides where the value comes from when scanning the code",fix:"Remove it and use `{{expression}}` inline, or use `let` if it is reassigned later"})}};create(t){let{sourceCode:n}=t;return {VariableDeclarator(i){i.parent.type!=="VariableDeclaration"||i.parent.kind!=="const"||i.parent.parent.type!=="ExportNamedDeclaration"&&(i.id.type!=="Identifier"||i.init===null||H(i.init)&&t.report({node:i,messageId:"propertyAccessAlias",data:{name:i.id.name,expression:n.getText(i.init)}}));}}}},q=new I;var w=class extends m{name="no-single-line-jsdoc";defaultOptions=[];meta={type:"layout",fixable:"code",docs:{description:"Require JSDoc comments to span multiple lines rather than sit on a single line.",recommended:true},schema:[],messages:{singleLine:d({problem:"This JSDoc comment is written on a single line.",why:"Multi-line JSDoc is easier to read, diff, and extend with additional tags, and is the house style.",fix:"Put the opening `/**`, the ` * ` content, and the closing `*/` each on their own line."})}};create(t){let{sourceCode:n}=t;return {Program(){for(let i of n.getAllComments()){if(!h(i)||i.loc.start.line!==i.loc.end.line)continue;let o=i.value.replace(/^\*/,"").trim();o.length!==0&&t.report({loc:i.loc,messageId:"singleLine",fix(s){let r=" ".repeat(i.loc.start.column),p=`/**
5
- ${r} * ${o}
6
- ${r} */`;return s.replaceTextRange(i.range,p)}});}}}}},K=new w;var X={adonisjs:"AdonisJS",react:"React"};function Se(e){let t=[];for(let n of e.ast.body)n.type==="ImportDeclaration"&&t.push(String(n.source.value));return t}function Z(e,t){let n=new Set,i=Se(e);return i.some(s=>s.startsWith("@adonisjs/")||a.ADONIS_SUBPATH.test(s))&&n.add("adonisjs"),(i.some(s=>s==="react"||s.startsWith("react/")||s==="react-dom")||a.REACT_FILE.test(t))&&n.add("react"),n}var A=class extends m{name="require-framework-config";defaultOptions=[{ignore:[]}];meta={type:"suggestion",docs:{description:"Warn when a file uses a framework whose Nitpicker config is not enabled.",recommended:true,category:"base"},schema:[{type:"object",properties:{ignore:{type:"array",items:{type:"string",enum:["adonisjs","react"]}}},additionalProperties:false}],messages:{missingConfig:d({problem:"This file uses {{framework}} but the Nitpicker {{framework}} rules are not enabled.",why:"Framework rules only run when you opt into the matching config, so files like this one go unchecked",fix:"Add `nitpicker.configs.{{config}}` (scoped to these files) to your ESLint config, or turn off `nitpicker/require-framework-config`"})}};create(t,n){let i=new Set(n[0]?.ignore??[]),o=t.settings[a.PLUGIN_NAME]??{};return {Program(s){let r=Z(t.sourceCode,t.filename);for(let p of r)i.has(p)||o[p]||t.report({node:s,messageId:"missingConfig",data:{framework:X[p],config:p}});}}}},Y=new A;function Q(e){let t=e;return t.parent.type==="VariableDeclarator"&&t.parent.parent.type==="VariableDeclaration"&&(t=t.parent.parent),(t.parent.type==="ExportNamedDeclaration"||t.parent.type==="ExportDefaultDeclaration")&&(t=t.parent),t}function ee(e){return e.parent?.type==="Program"}function te(e){if((e.type==="FunctionDeclaration"||e.type==="FunctionExpression")&&e.id)return e.id.name;if(e.parent.type==="VariableDeclarator"&&e.parent.id.type==="Identifier")return e.parent.id.name}var he=new Set(["FunctionDeclaration","FunctionExpression","ArrowFunctionExpression"]);function ie(e){return /^[A-Z]/.test(e)}function g(e){if(!e)return false;switch(e.type){case "JSXElement":case "JSXFragment":return true;case "ConditionalExpression":return g(e.consequent)||g(e.alternate);case "LogicalExpression":return g(e.left)||g(e.right);case "SequenceExpression":return g(e.expressions.at(-1));default:return false}}function ne(e,t){if(e.type==="ReturnStatement")return g(e.argument);for(let n of t[e.type]??[]){let i=e[n],o=Array.isArray(i)?i:[i];for(let s of o){let r=s;if(!(!r||typeof r.type!="string")&&!he.has(r.type)&&ne(r,t))return true}}return false}function oe(e,t){return e.type==="ArrowFunctionExpression"&&e.body.type!=="BlockStatement"?g(e.body):ne(e.body,t)}var D=class extends m{name="require-function-jsdoc";defaultOptions=[];meta={type:"suggestion",docs:{description:"Require a JSDoc comment on top-level functions, except React component functions.",recommended:true},schema:[],messages:{missingJSDoc:d({problem:"The function `{{name}}` has no JSDoc comment.",why:"Top-level functions must document their purpose, parameters, and return value, React component functions are the only exception.",fix:"Add a `/** ... */` JSDoc block immediately above the function describing what it does."})}};create(t){let{sourceCode:n}=t,i=(o,s)=>{let r=te(o);if(r===void 0)return;let p=Q(o);ee(p)&&(ie(r)&&oe(o,n.visitorKeys)||J(n,p)||t.report({node:s,messageId:"missingJSDoc",data:{name:r}}));};return {FunctionDeclaration(o){i(o,o.id??o);},VariableDeclarator(o){let{init:s}=o;s&&(s.type!=="ArrowFunctionExpression"&&s.type!=="FunctionExpression"||i(s,o.id));}}}},re=new D;var Ee=[_,j,$,G,V,q,K,Y,re],E=Object.fromEntries(Ee.map(e=>[e.name,e.toRuleModule()]));function S(e){let t={};for(let[n,i]of Object.entries(E))(i.meta.docs?.category??"base")===e&&(t[`${a.PLUGIN_NAME}/${n}`]="warn");return t}function se(){let e={};for(let t of Object.keys(E))e[`${a.PLUGIN_NAME}/${t}`]="warn";return e}function ae(e){return {name:`${a.PLUGIN_NAME}/all`,plugins:{[a.PLUGIN_NAME]:e},settings:{[a.PLUGIN_NAME]:{adonisjs:true,react:true}},rules:se()}}function T(e){return {name:`${a.PLUGIN_NAME}/base`,plugins:{[a.PLUGIN_NAME]:e},rules:S("base")}}function le(e){return {...T(e),name:`${a.PLUGIN_NAME}/recommended`}}var Te=["**/start/routes.ts","**/start/routes/**/*.ts"];function ce(e){return {name:`${a.PLUGIN_NAME}/adonisjs`,plugins:{[a.PLUGIN_NAME]:e},settings:{[a.PLUGIN_NAME]:{adonisjs:true}},rules:{...S("adonisjs"),[`${a.PLUGIN_NAME}/no-decorative-comment-separators`]:["warn",{allowIn:Te}]}}}function pe(e){return {name:`${a.PLUGIN_NAME}/react`,plugins:{[a.PLUGIN_NAME]:e},settings:{[a.PLUGIN_NAME]:{react:true}},rules:S("react")}}function me(e){return {base:T(e),recommended:le(e),adonisjs:ce(e),react:pe(e),all:ae(e)}}var de="0.1.0";var M={meta:{name:`eslint-plugin-${a.PLUGIN_NAME}`,version:de},rules:E,configs:{}};M.configs=me(M);var Ki=M;export{Ki as default};//# sourceMappingURL=index.js.map
1
+ import {ESLintUtils}from'@typescript-eslint/utils';var De={PLUGIN_NAME:"nitpicker",REPO_URL:"https://github.com/the-alien-club/eslint-plugin-nitpicker",EM_DASH:"\u2014",COMMENTS:{BOX_DRAWING:/[─-▟]/,PURE_SEPARATOR:/^[-=~*#_+]{3,}$/,WRAPPED_LABEL:/^[-=~*#_+]{2,}\s.*\s[-=~*#_+]{2,}$/},WORDS:{WORD_CHAR:/[\p{L}\p{N}_$]/u,SUB_WORD:/[A-Z]+(?![a-z])|[A-Z][a-z]+|[a-z]+/g},FRAMEWORKS:{ADONIS_SUBPATH:/^#(models|controllers|services|middleware|validators|policies|config|start|database|providers|lib)\b/,REACT_FILE:/\.[jt]sx$/},MIGRATIONS:{INDEX_METHODS:new Set(["index","unique","primary","foreign"]),TIMESTAMP_METHODS:new Set(["timestamp","dateTime","datetime"]),AUDIT_TIMESTAMPS:new Set(["created_at","updated_at","deleted_at"]),CATEGORY_ORDER:["column","timestamp","index"]}},s=De;var J=ESLintUtils.RuleCreator(t=>`${s.REPO_URL}/blob/main/docs/rules/${t}.md`);var p=class{toRuleModule(){return J({name:this.name,meta:this.meta,defaultOptions:this.defaultOptions,create:(e,i)=>this.create(e,i)})}};function m({problem:t,why:e,fix:i}){return `${t}
2
+ - why: ${e}
3
+ - fix: ${i}`}function U(t){return t.parent.type==="ExportDefaultDeclaration"&&t.superClass?.type==="Identifier"&&t.superClass.name==="BaseSchema"}function G(t){if(t.callee.type!=="MemberExpression"||t.callee.property.type!=="Identifier"||t.callee.property.name!=="createTable"||t.callee.object.type!=="MemberExpression"||t.callee.object.property.type!=="Identifier"||t.callee.object.property.name!=="schema")return null;let e=t.arguments.at(-1);return e?.type!=="ArrowFunctionExpression"&&e?.type!=="FunctionExpression"||e.body.type!=="BlockStatement"||e.params[0]?.type!=="Identifier"?null:{body:e.body.body,builderName:e.params[0].name}}function B(t,e){if(t.type!=="ExpressionStatement")return null;let i=Me(t.expression,e);return i===null?null:s.MIGRATIONS.INDEX_METHODS.has(i.method)?"index":i.method==="timestamps"||s.MIGRATIONS.TIMESTAMP_METHODS.has(i.method)&&i.firstArgument!==void 0&&s.MIGRATIONS.AUDIT_TIMESTAMPS.has(i.firstArgument)?"timestamp":"column"}function Me(t,e){let i=t;for(;i.type==="CallExpression"&&i.callee.type==="MemberExpression";){if(i.callee.object.type==="Identifier"&&i.callee.object.name===e){if(i.callee.property.type!=="Identifier")return null;let r=i.arguments[0],n=r?.type==="Literal"&&typeof r.value=="string"?r.value:void 0;return {method:i.callee.property.name,firstArgument:n}}i=i.callee.object;}return null}var R=class extends p{name="migration-table-order";defaultOptions=[];meta={type:"suggestion",docs:{description:"Group migration table statements as columns, then timestamps, then indexes and constraints.",recommended:true,category:"adonisjs"},schema:[],messages:{outOfOrder:m({problem:"This {{category}} is out of order in the table definition.",why:"A migration reads consistently when columns come first, then timestamps, then indexes and constraints, each grouped together",fix:"Move it into its group so the order stays columns, timestamps, then indexes and constraints"})}};create(e){return {CallExpression(i){let r=G(i);if(r===null)return;let n=0;for(let o of r.body){let c=B(o,r.builderName);if(c===null)continue;let u=s.MIGRATIONS.CATEGORY_ORDER.indexOf(c);u<n&&e.report({node:o,messageId:"outOfOrder",data:{category:c}}),n=Math.max(n,u);}}}}},W=new R;function f(t){return t.type==="Block"&&t.value.startsWith("*")}function T(t,e){let r=t.getCommentsBefore(e).at(-1);return r!==void 0&&f(r)}function x(t){return /^\s*\*\s*$/.test(t)}function $(t){return /^\s*\*\s*@/.test(t)}function V(t){let e=[];for(let i of t.value.split(`
4
+ `)){let r=i.replace(/^\s*\*? ?/,"").trimEnd();if(r.startsWith("@"))break;e.push(r);}return e.join(" ").replace(/\s+/g," ").trim()}var L=class extends p{name="require-migration-jsdoc";defaultOptions=[];meta={type:"suggestion",docs:{description:"Require a JSDoc comment describing an AdonisJS migration.",recommended:true,category:"adonisjs"},schema:[],messages:{missingJSDoc:m({problem:"This migration has no JSDoc describing what it does.",why:"A migration's intent should be readable at a glance, the timestamped filename does not convey the schema change",fix:"Add a `/** ... */` JSDoc above the migration class summarizing the change"})}};create(e){return {ClassDeclaration(i){U(i)&&(T(e.sourceCode,i.parent)||e.report({node:i.id??i,messageId:"missingJSDoc"}));}}}},H=new L;var q=250,O=class extends p{name="max-jsdoc-description-length";defaultOptions=[{max:q}];meta={type:"suggestion",docs:{description:"Enforce a maximum character length for a JSDoc description.",recommended:true,category:"base"},schema:[{type:"object",properties:{max:{type:"integer",minimum:1}},additionalProperties:false}],messages:{tooLong:m({problem:"This JSDoc description is {{length}} characters, over the {{max}}-character limit.",why:"A JSDoc description should summarize what something is, an oversized one usually restates the code or explains how it is used, which does not belong here",fix:'Trim it to a concise summary of what it does, and remove any note about how or where it is used (e.g "used by X to ...", "called from Y"), which is an anti-pattern'})}};create(e,i){let r=i[0]?.max??q;return {Program(){for(let n of e.sourceCode.getAllComments()){if(!f(n))continue;let o=V(n).length;o<=r||e.report({loc:n.loc,messageId:"tooLong",data:{length:o,max:r}});}}}}},K=new O;var N=class extends p{name="no-alias-variables";defaultOptions=[];meta={type:"suggestion",docs:{description:"Disallow a `const` whose whole value is another variable, use the source directly.",recommended:true,category:"base"},schema:[],messages:{alias:m({problem:"`{{name}}` only aliases `{{source}}`.",why:"A variable that just renames another hides the original and adds a name to track for no gain",fix:"Remove it and use `{{source}}` directly, or rename `{{source}}` itself if the new name is better"})}};create(e){return {VariableDeclarator(i){i.parent.type!=="VariableDeclaration"||i.parent.kind!=="const"||i.parent.parent.type!=="ExportNamedDeclaration"&&(i.id.type!=="Identifier"||i.init?.type!=="Identifier"||e.report({node:i,messageId:"alias",data:{name:i.id.name,source:i.init.name}}));}}}},X=new N;var Y={colour:"color",colours:"colors",coloured:"colored",colouring:"coloring",behaviour:"behavior",behaviours:"behaviors",favourite:"favorite",favourites:"favorites",flavour:"flavor",flavours:"flavors",honour:"honor",labour:"labor",neighbour:"neighbor",normalise:"normalize",normalised:"normalized",normalising:"normalizing",normalisation:"normalization",initialise:"initialize",initialised:"initialized",initialising:"initializing",initialisation:"initialization",serialise:"serialize",serialised:"serialized",serialising:"serializing",serialisation:"serialization",organise:"organize",organised:"organized",organising:"organizing",organisation:"organization",optimise:"optimize",optimised:"optimized",optimising:"optimizing",optimisation:"optimization",customise:"customize",customised:"customized",customising:"customizing",sanitise:"sanitize",sanitised:"sanitized",sanitising:"sanitizing",synchronise:"synchronize",synchronised:"synchronized",synchronising:"synchronizing",authorise:"authorize",authorised:"authorized",authorising:"authorizing",finalise:"finalize",finalised:"finalized",finalising:"finalizing",capitalise:"capitalize",capitalised:"capitalized",capitalising:"capitalizing",categorise:"categorize",categorised:"categorized",analyse:"analyze",analysed:"analyzed",analysing:"analyzing",centre:"center",centred:"centered",centres:"centers",fibre:"fiber",metre:"meter",licence:"license",defence:"defense",offence:"offense",cancelled:"canceled",cancelling:"canceling",labelled:"labeled",labelling:"labeling",modelling:"modeling",travelled:"traveled",grey:"gray",dialogue:"dialog",catalogue:"catalog"};function Z(t,e,i){let r={};for(let[n,o]of Object.entries(t))r[n.toLowerCase()]=o;for(let[n,o]of Object.entries(e))r[n.toLowerCase()]=o;for(let n of i)delete r[n.toLowerCase()];return r}function I(t){let e=[];for(let i of t.matchAll(s.WORDS.SUB_WORD))i.index!==void 0&&e.push({text:i[0],index:i.index});return e}function D(t,e){return t===t.toUpperCase()?e.toUpperCase():t.charAt(0)===t.charAt(0).toUpperCase()?e.charAt(0).toUpperCase()+e.slice(1):e}function Q(t){return t!==void 0&&s.WORDS.WORD_CHAR.test(t)}var C=class extends p{name="no-british-english";defaultOptions=[{extra:{},ignore:[]}];meta={type:"suggestion",docs:{description:"Disallow British English spellings in identifiers and comments.",recommended:true,category:"base"},fixable:"code",schema:[{type:"object",properties:{extra:{type:"object",additionalProperties:{type:"string"}},ignore:{type:"array",items:{type:"string"}}},additionalProperties:false}],messages:{british:m({problem:"British spelling `{{british}}`, this codebase uses American English.",why:"One spelling convention keeps identifiers and docs consistent and searchable",fix:"Use `{{american}}` instead"})}};create(e,i){let r=Z(Y,i[0]?.extra??{},i[0]?.ignore??[]);return {Identifier(n){if(!(n.parent.type==="MemberExpression"&&n.parent.property===n&&!n.parent.computed))for(let o of I(n.name)){let c=r[o.text.toLowerCase()];c!==void 0&&e.report({node:n,messageId:"british",data:{british:o.text,american:D(o.text,c)}});}},Program(){for(let n of e.sourceCode.getAllComments())for(let o of I(n.value)){let c=r[o.text.toLowerCase()];if(c===void 0)continue;let u=D(o.text,c),d=n.range[0]+2+o.index,y=d+o.text.length;e.report({loc:{start:e.sourceCode.getLocFromIndex(d),end:e.sourceCode.getLocFromIndex(y)},messageId:"british",data:{british:o.text,american:u},fix:Ie=>Ie.replaceTextRange([d,y],u)});}}}}},ee=new C;function te(t){let e=t.replace(/^\s*\*?\s*/,"").trimEnd();return e.length===0?false:s.COMMENTS.BOX_DRAWING.test(e)||s.COMMENTS.PURE_SEPARATOR.test(e)||s.COMMENTS.WRAPPED_LABEL.test(e)}function ke(t){let e=t.replace(/\\/g,"/"),i="^";for(let r=0;r<e.length;r++){let n=e[r];if(n===void 0)break;n==="*"?e[r+1]==="*"?(i+=".*",r++,e[r+1]==="/"&&r++):i+="[^/]*":"\\^$.|?+()[]{}".includes(n)?i+=`\\${n}`:i+=n;}return new RegExp(`${i}$`)}function ie(t,e){let i=t.replace(/\\/g,"/");return e.some(r=>ke(r).test(i))}var M=class extends p{name="no-decorative-comment-separators";defaultOptions=[{allowIn:[]}];meta={type:"layout",docs:{description:"Disallow decorative separators (banners, box-drawing, repeated dashes) inside comments.",recommended:true,category:"base"},schema:[{type:"object",properties:{allowIn:{type:"array",items:{type:"string"}}},additionalProperties:false}],messages:{decorative:m({problem:"This comment uses a decorative separator.",why:"Repeated separator characters and box-drawing lines are visual noise that add nothing over a plain label",fix:"Remove the separator, a one-line label or a blank line already divides sections clearly"})}};create(e,i){let r=i[0]?.allowIn??[];return r.length>0&&ie(e.filename,r)?{}:{Program(){for(let n of e.sourceCode.getAllComments()){let o=n.value.split(`
5
+ `);for(let c=0;c<o.length;c++){let u=o[c];if(u===void 0||!te(u))continue;let d=n.loc.start.line+c,y=e.sourceCode.lines[d-1]??"";e.report({loc:{start:{line:d,column:0},end:{line:d,column:y.length}},messageId:"decorative"});}}}}}},re=new M;var k=class extends p{name="no-em-dash";defaultOptions=[];meta={type:"suggestion",docs:{description:"Disallow the em dash (\u2014) character anywhere in the source.",recommended:true},schema:[],messages:{emDash:m({problem:"Found an em dash (\u2014) character.",why:"Em dashes are typically introduced by AI-generated or auto-formatted text and are discouraged here.",fix:"Replace the em dash with a hyphen (-), a comma (,), or reword the sentence to avoid it."})}};create(e){let i=e.sourceCode.getText();return {Program(){for(let r=0;r<i.length;r++)i[r]===s.EM_DASH&&e.report({loc:{start:e.sourceCode.getLocFromIndex(r),end:e.sourceCode.getLocFromIndex(r+1)},messageId:"emDash"});}}}},ne=new k;var A=class extends p{name="no-jsdoc-blank-before-tags";defaultOptions=[];meta={type:"layout",fixable:"code",docs:{description:"Disallow blank lines before JSDoc tags such as `@param` or `@returns`.",recommended:true},schema:[],messages:{blankBeforeTag:m({problem:"There is a blank line before a JSDoc tag.",why:"Tags should follow the description directly; an empty line there is noise that inflates the comment.",fix:"Remove the blank line so the tag follows on directly."})}};create(e){return {Program(){for(let i of e.sourceCode.getAllComments())if(f(i)&&i.loc.start.line!==i.loc.end.line)for(let r=i.loc.start.line;r<=i.loc.end.line;r++){let n=e.sourceCode.lines[r-1];if(n===void 0||!x(n))continue;let o=r;for(;o<i.loc.end.line&&x(e.sourceCode.lines[o]??"");)o++;let c=e.sourceCode.lines[o];if(c!==void 0&&$(c)){let u=e.sourceCode.getIndexFromLoc({line:r,column:0}),d=e.sourceCode.getIndexFromLoc({line:o+1,column:0});e.report({loc:{start:{line:r,column:0},end:{line:o,column:n.length}},messageId:"blankBeforeTag",fix:y=>y.removeRange([u,d])});}r=o;}}}}},oe=new A;var w=class extends p{name="no-line-comment-period";defaultOptions=[];meta={type:"layout",fixable:"code",docs:{description:"Disallow prose periods in `//` line comments (code-reference dots and ellipses are allowed).",recommended:true},schema:[],messages:{period:m({problem:"This line comment contains a period.",why:"Line comments should be short, clear fragments, not full sentences, so periods are just noise, dots inside code references like `foo.bar` are allowed.",fix:"Remove the period and keep the comment terse."})}};create(e){return {Program(){for(let i of e.sourceCode.getAllComments()){if(i.type!=="Line")continue;let r=i.range[0]+2;for(let n=0;n<i.value.length;n++){if(i.value[n]!==".")continue;if(i.value[n+1]==="."){for(;i.value[n+1]===".";)n++;continue}if(Q(i.value[n+1]))continue;let o=r+n;e.report({loc:{start:e.sourceCode.getLocFromIndex(o),end:e.sourceCode.getLocFromIndex(o+1)},messageId:"period",fix:c=>c.removeRange([o,o+1])});}}}}}},se=new w;function E(t){let e=t,i=false;for(;;){if(e.type==="ChainExpression"||e.type==="TSNonNullExpression"){e=e.expression;continue}if(e.type==="MemberExpression"){if(e.computed)return false;i=true,e=e.object;continue}break}return i&&(e.type==="Identifier"||e.type==="ThisExpression")}var v=class extends p{name="no-property-access-alias";defaultOptions=[];meta={type:"suggestion",docs:{description:"Disallow a `const` whose whole value is a single property access, inline the expression instead.",recommended:true,category:"base"},schema:[],messages:{propertyAccessAlias:m({problem:"`{{name}}` only aliases the property access `{{expression}}`.",why:"A variable that just renames a property hides where the value comes from when scanning the code",fix:"Remove it and use `{{expression}}` inline, or use `let` if it is reassigned later"})}};create(e){return {VariableDeclarator(i){i.parent.type!=="VariableDeclaration"||i.parent.kind!=="const"||i.parent.parent.type!=="ExportNamedDeclaration"&&(i.id.type!=="Identifier"||i.init===null||E(i.init)&&e.report({node:i,messageId:"propertyAccessAlias",data:{name:i.id.name,expression:e.sourceCode.getText(i.init)}}));}}}},ae=new v;var F=class extends p{name="no-property-destructuring";defaultOptions=[];meta={type:"suggestion",docs:{description:"Disallow shorthand destructuring off a plain object reference, access the property directly.",recommended:true,category:"base"},schema:[],messages:{destructure:m({problem:"Destructuring from `{{source}}` here just aliases its properties.",why:"Reading `{{source}}.x` at the use site keeps the origin visible, destructuring a plain object hides where a value comes from (destructuring a call or hook result is fine)",fix:"Access the properties on `{{source}}` directly instead of destructuring"})}};create(e){return {VariableDeclarator(i){i.parent.type!=="VariableDeclaration"||i.parent.kind!=="const"||i.parent.parent.type!=="ExportNamedDeclaration"&&(i.id.type!=="ObjectPattern"||i.init===null||i.init.type!=="Identifier"&&!E(i.init)||Ae(i.id)&&e.report({node:i,messageId:"destructure",data:{source:e.sourceCode.getText(i.init)}}));}}}};function Ae(t){return t.properties.length===0?false:t.properties.every(e=>e.type==="Property"&&e.shorthand&&!e.computed&&e.value.type==="Identifier")}var le=new F;var P=class extends p{name="no-single-line-jsdoc";defaultOptions=[];meta={type:"layout",fixable:"code",docs:{description:"Require JSDoc comments to span multiple lines rather than sit on a single line.",recommended:true},schema:[],messages:{singleLine:m({problem:"This JSDoc comment is written on a single line.",why:"Multi-line JSDoc is easier to read, diff, and extend with additional tags, and is the house style.",fix:"Put the opening `/**`, the ` * ` content, and the closing `*/` each on their own line."})}};create(e){return {Program(){for(let i of e.sourceCode.getAllComments()){if(!f(i)||i.loc.start.line!==i.loc.end.line)continue;let r=i.value.replace(/^\*/,"").trim();r.length!==0&&e.report({loc:i.loc,messageId:"singleLine",fix(n){let o=" ".repeat(i.loc.start.column),c=`/**
6
+ ${o} * ${r}
7
+ ${o} */`;return n.replaceTextRange(i.range,c)}});}}}}},ce=new P;var pe={adonisjs:"AdonisJS",react:"React"};function we(t){let e=[];for(let i of t.ast.body)i.type==="ImportDeclaration"&&e.push(String(i.source.value));return e}function me(t,e){let i=new Set,r=we(t);return r.some(o=>o.startsWith("@adonisjs/")||s.FRAMEWORKS.ADONIS_SUBPATH.test(o))&&i.add("adonisjs"),(r.some(o=>o==="react"||o.startsWith("react/")||o==="react-dom")||s.FRAMEWORKS.REACT_FILE.test(e))&&i.add("react"),i}var _=class extends p{name="require-framework-config";defaultOptions=[{ignore:[]}];meta={type:"suggestion",docs:{description:"Warn when a file uses a framework whose Nitpicker config is not enabled.",recommended:true,category:"base"},schema:[{type:"object",properties:{ignore:{type:"array",items:{type:"string",enum:["adonisjs","react"]}}},additionalProperties:false}],messages:{missingConfig:m({problem:"This file uses {{framework}} but the Nitpicker {{framework}} rules are not enabled.",why:"Framework rules only run when you opt into the matching config, so files like this one go unchecked",fix:"Add `nitpicker.configs.{{config}}` (scoped to these files) to your ESLint config, or turn off `nitpicker/require-framework-config`"})}};create(e,i){let r=new Set(i[0]?.ignore??[]),n=e.settings[s.PLUGIN_NAME]??{};return {Program(o){let c=me(e.sourceCode,e.filename);for(let u of c)r.has(u)||n[u]||e.report({node:o,messageId:"missingConfig",data:{framework:pe[u],config:u}});}}}},ue=new _;function de(t){let e=t;return e.parent.type==="VariableDeclarator"&&e.parent.parent.type==="VariableDeclaration"&&(e=e.parent.parent),(e.parent.type==="ExportNamedDeclaration"||e.parent.type==="ExportDefaultDeclaration")&&(e=e.parent),e}function fe(t){return t.parent?.type==="Program"}function ge(t){if((t.type==="FunctionDeclaration"||t.type==="FunctionExpression")&&t.id)return t.id.name;if(t.parent.type==="VariableDeclarator"&&t.parent.id.type==="Identifier")return t.parent.id.name}var ve=new Set(["FunctionDeclaration","FunctionExpression","ArrowFunctionExpression"]);function ye(t){return /^[A-Z]/.test(t)}function g(t){if(!t)return false;switch(t.type){case "JSXElement":case "JSXFragment":return true;case "ConditionalExpression":return g(t.consequent)||g(t.alternate);case "LogicalExpression":return g(t.left)||g(t.right);case "SequenceExpression":return g(t.expressions.at(-1));default:return false}}function Se(t,e){if(t.type==="ReturnStatement")return g(t.argument);for(let i of e[t.type]??[]){let r=t[i],n=Array.isArray(r)?r:[r];for(let o of n){let c=o;if(!(!c||typeof c.type!="string")&&!ve.has(c.type)&&Se(c,e))return true}}return false}function he(t,e){return t.type==="ArrowFunctionExpression"&&t.body.type!=="BlockStatement"?g(t.body):Se(t.body,e)}var j=class extends p{name="require-function-jsdoc";defaultOptions=[];meta={type:"suggestion",docs:{description:"Require a JSDoc comment on top-level functions, except React component functions.",recommended:true},schema:[],messages:{missingJSDoc:m({problem:"The function `{{name}}` has no JSDoc comment.",why:"Top-level functions must document their purpose, parameters, and return value, React component functions are the only exception.",fix:"Add a `/** ... */` JSDoc block immediately above the function describing what it does."})}};create(e){let i=(r,n)=>{let o=ge(r);if(o===void 0)return;let c=de(r);fe(c)&&(ye(o)&&he(r,e.sourceCode.visitorKeys)||T(e.sourceCode,c)||e.report({node:n,messageId:"missingJSDoc",data:{name:o}}));};return {FunctionDeclaration(r){i(r,r.id??r);},VariableDeclarator(r){r.init&&(r.init.type!=="ArrowFunctionExpression"&&r.init.type!=="FunctionExpression"||i(r.init,r.id));}}}},Te=new j;var Fe=[W,H,K,X,ee,re,ne,oe,se,ae,le,ce,ue,Te],h=Object.fromEntries(Fe.map(t=>[t.name,t.toRuleModule()]));function S(t){let e={};for(let[i,r]of Object.entries(h))(r.meta.docs?.category??"base")===t&&(e[`${s.PLUGIN_NAME}/${i}`]="warn");return e}function Ee(){let t={};for(let e of Object.keys(h))t[`${s.PLUGIN_NAME}/${e}`]="warn";return t}function be(t){return {name:`${s.PLUGIN_NAME}/all`,plugins:{[s.PLUGIN_NAME]:t},settings:{[s.PLUGIN_NAME]:{adonisjs:true,react:true}},rules:Ee()}}function b(t){return {name:`${s.PLUGIN_NAME}/base`,plugins:{[s.PLUGIN_NAME]:t},rules:S("base")}}function Re(t){return {...b(t),name:`${s.PLUGIN_NAME}/recommended`}}var Pe=["**/start/routes.ts","**/start/routes/**/*.ts"];function xe(t){return {name:`${s.PLUGIN_NAME}/adonisjs`,plugins:{[s.PLUGIN_NAME]:t},settings:{[s.PLUGIN_NAME]:{adonisjs:true}},rules:{...S("adonisjs"),[`${s.PLUGIN_NAME}/no-decorative-comment-separators`]:["warn",{allowIn:Pe}]}}}function Le(t){return {name:`${s.PLUGIN_NAME}/react`,plugins:{[s.PLUGIN_NAME]:t},settings:{[s.PLUGIN_NAME]:{react:true}},rules:S("react")}}function Oe(t){return {base:b(t),recommended:Re(t),adonisjs:xe(t),react:Le(t),all:be(t)}}var Ne="0.2.0";var z={meta:{name:`eslint-plugin-${s.PLUGIN_NAME}`,version:Ne},rules:h,configs:{}};z.configs=Oe(z);var Gr=z;export{Gr as default};//# sourceMappingURL=index.js.map
7
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/constants.ts","../src/lib/data/britishToAmerican.ts","../src/lib/utils/createRule.ts","../src/lib/rule.ts","../src/lib/utils/dictionary.ts","../src/lib/utils/nitpick.ts","../src/lib/utils/words.ts","../src/rules/base/noBritishEnglish.ts","../src/lib/utils/decoration.ts","../src/lib/utils/matchesGlob.ts","../src/rules/base/noDecorativeCommentSeparators.ts","../src/rules/base/noEmDash.ts","../src/lib/utils/JSDoc.ts","../src/rules/base/noJSDocBlankBeforeTags.ts","../src/lib/utils/isWordChar.ts","../src/rules/base/noLineCommentPeriod.ts","../src/lib/utils/aliases.ts","../src/rules/base/noPropertyAccessAlias.ts","../src/rules/base/noSingleLineJSDoc.ts","../src/lib/utils/framework.ts","../src/rules/base/requireFrameworkConfig.ts","../src/lib/utils/functions.ts","../src/lib/utils/react.ts","../src/rules/base/requireFunctionJSDoc.ts","../src/rules/index.ts","../src/configs/helpers.ts","../src/configs/presets/all.ts","../src/configs/rulesets/base.ts","../src/configs/presets/recommended.ts","../src/configs/rulesets/adonisjs.ts","../src/configs/rulesets/react.ts","../src/configs/index.ts","../package.json","../src/index.ts"],"names":["CONSTANTS","constants_default","BRITISH_TO_AMERICAN","createRule","ESLintUtils","name","NitpickerRule","context","options","buildDictionary","base","extra","ignore","dictionary","key","value","nitpick","problem","why","fix","extractWords","text","words","match","matchCase","source","replacement","NoBritishEnglish","sourceCode","node","word","american","comment","cased","from","to","fixer","noBritishEnglish_default","isDecorativeCommentLine","line","content","globToRegExp","glob","normalized","pattern","index","char","matchesGlob","filename","patterns","path","NoDecorativeCommentSeparators","allowIn","lines","reportedLine","noDecorativeCommentSeparators_default","NoEmDash","noEmDash_default","isJSDocComment","hasLeadingJSDoc","closest","isBlankJSDocLine","isJSDocTagLine","NoJSDocBlankBeforeTags","runEnd","nextLine","noJSDocBlankBeforeTags_default","isWordChar","NoLineCommentPeriod","valueStart","at","noLineCommentPeriod_default","isPropertyAccessAlias","expression","sawMemberAccess","NoPropertyAccessAlias","noPropertyAccessAlias_default","NoSingleLineJSDoc","indent","expanded","noSingleLineJSDoc_default","FRAMEWORK_LABELS","importSources","sources","statement","detectFrameworks","detected","RequireFrameworkConfig","ignored","enabled","framework","requireFrameworkConfig_default","getDocumentableNode","fn","isTopLevel","getFunctionName","FUNCTION_NODE_TYPES","isReactComponentName","isJsxExpression","subtreeReturnsJsx","visitorKeys","children","child","childNode","functionReturnsJsx","RequireFunctionJSDoc","check","reportNode","documentable","init","requireFunctionJSDoc_default","ruleInstances","rules","rule","categoryRules","category","allRules","all","plugin","recommended","ROUTE_FILE_GLOBS","adonisjs","react","buildConfigs","version","index_default"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The global set of constants shared across the plugin.\n */\nconst CONSTANTS = {\n /**\n * The short name the plugin is registered under inside an ESLint config,\n * e.g. `nitpicker/no-em-dash`.\n */\n PLUGIN_NAME: \"nitpicker\",\n\n /**\n * The base URL of the plugin's repository.\n */\n REPO_URL: \"https://github.com/the-alien-club/eslint-plugin-nitpicker\",\n\n /**\n * The em dash character (U+2014), e.g. \"—\".\n */\n EM_DASH: \"—\",\n\n /**\n * Matches a single \"word\" character, i.e. anything that can appear inside an\n * identifier or a number (letters, digits, underscore and dollar).\n */\n WORD_CHAR: /[\\p{L}\\p{N}_$]/u,\n\n /**\n * AdonisJS subpath import roots (`#models/...`, `#controllers/...`, etc.).\n */\n ADONIS_SUBPATH:\n /^#(models|controllers|services|middleware|validators|policies|config|start|database|providers|lib)\\b/,\n\n /**\n * React source files by extension.\n */\n REACT_FILE: /\\.[jt]sx$/,\n\n /**\n * Box-drawing and block-element characters, which are always decorative\n * when found inside a comment.\n */\n BOX_DRAWING: /[─-▟]/,\n\n /**\n * A comment line made entirely of three or more repeated separator\n * characters, e.g. `======` or `------`.\n */\n PURE_SEPARATOR: /^[-=~*#_+]{3,}$/,\n\n /**\n * A short label fenced by separator runs inside a comment, e.g `-- Section --`.\n */\n WRAPPED_LABEL: /^[-=~*#_+]{2,}\\s.*\\s[-=~*#_+]{2,}$/,\n\n /**\n * Matches a single sub-word: an all-caps acronym, a capitalized word, or a\n * lowercase run, so `getUserName` splits into \"get\", \"User\" and \"Name\"\n */\n SUB_WORD: /[A-Z]+(?![a-z])|[A-Z][a-z]+|[a-z]+/g,\n} as const\n\nexport default CONSTANTS\n","/**\n * A dictionary of British English spellings mapped to their American English\n * equivalents, keyed in lowercase, focused on the words that show up in code\n * and that AIs most often get wrong, consumers can extend it per project via the\n * `no-british-english` rule's `extra` option.\n */\nexport const BRITISH_TO_AMERICAN: Record<string, string> = {\n // \"-our\" to \"-or\"\n colour: \"color\",\n colours: \"colors\",\n coloured: \"colored\",\n colouring: \"coloring\",\n behaviour: \"behavior\",\n behaviours: \"behaviors\",\n favourite: \"favorite\",\n favourites: \"favorites\",\n flavour: \"flavor\",\n flavours: \"flavors\",\n honour: \"honor\",\n labour: \"labor\",\n neighbour: \"neighbor\",\n\n // \"-ise\" to \"-ize\" and their inflections\n normalise: \"normalize\",\n normalised: \"normalized\",\n normalising: \"normalizing\",\n normalisation: \"normalization\",\n initialise: \"initialize\",\n initialised: \"initialized\",\n initialising: \"initializing\",\n initialisation: \"initialization\",\n serialise: \"serialize\",\n serialised: \"serialized\",\n serialising: \"serializing\",\n serialisation: \"serialization\",\n organise: \"organize\",\n organised: \"organized\",\n organising: \"organizing\",\n organisation: \"organization\",\n optimise: \"optimize\",\n optimised: \"optimized\",\n optimising: \"optimizing\",\n optimisation: \"optimization\",\n customise: \"customize\",\n customised: \"customized\",\n customising: \"customizing\",\n sanitise: \"sanitize\",\n sanitised: \"sanitized\",\n sanitising: \"sanitizing\",\n synchronise: \"synchronize\",\n synchronised: \"synchronized\",\n synchronising: \"synchronizing\",\n authorise: \"authorize\",\n authorised: \"authorized\",\n authorising: \"authorizing\",\n finalise: \"finalize\",\n finalised: \"finalized\",\n finalising: \"finalizing\",\n capitalise: \"capitalize\",\n capitalised: \"capitalized\",\n capitalising: \"capitalizing\",\n categorise: \"categorize\",\n categorised: \"categorized\",\n\n // \"-yse\" to \"-yze\"\n analyse: \"analyze\",\n analysed: \"analyzed\",\n analysing: \"analyzing\",\n\n // \"-re\" to \"-er\"\n centre: \"center\",\n centred: \"centered\",\n centres: \"centers\",\n fibre: \"fiber\",\n metre: \"meter\",\n\n // \"-ce\" to \"-se\"\n licence: \"license\",\n defence: \"defense\",\n offence: \"offense\",\n\n // Doubled \"l\" in inflections\n cancelled: \"canceled\",\n cancelling: \"canceling\",\n labelled: \"labeled\",\n labelling: \"labeling\",\n modelling: \"modeling\",\n travelled: \"traveled\",\n\n // Miscellaneous\n grey: \"gray\",\n dialogue: \"dialog\",\n catalogue: \"catalog\",\n}\n","import { ESLintUtils } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * The category a rule belongs to, which decides the shared config it ships in,\n * `base` rules are universal, framework categories only apply when the consumer\n * opts into the matching config.\n */\nexport type RuleCategory = \"base\" | \"adonisjs\" | \"react\"\n\n/**\n * Extra metadata attached to every Nitpicker rule under `meta.docs`.\n */\nexport type NitpickerRuleDocs = {\n /**\n * A short, human-readable description of what the rule enforces.\n */\n description: string\n\n /**\n * Whether the rule is part of the `recommended` shared config.\n */\n recommended?: boolean\n\n /**\n * The category the rule belongs to, defaults to `base` when omitted.\n */\n category?: RuleCategory\n}\n\n/**\n * The shared rule factory for the whole plugin.\n *\n * It wires up strong typing for a rule's options and message IDs, and points\n * every rule at its documentation page on GitHub.\n */\nexport const createRule = ESLintUtils.RuleCreator<NitpickerRuleDocs>(\n name => `${CONSTANTS.REPO_URL}/blob/main/docs/rules/${name}.md`,\n)\n","import { ESLintUtils, type TSESLint } from \"@typescript-eslint/utils\"\nimport { createRule, type NitpickerRuleDocs } from \"@/lib/utils/createRule\"\n\n/**\n * The base class every Nitpicker rule extends.\n *\n * A rule is expressed as a class so that shared behavior, typing, and metadata\n * live in one place, while each concrete rule only has to declare its name,\n * metadata, default options, and visitor logic, and call {@link toRuleModule} to\n * turn an instance into the plain object ESLint expects.\n */\nexport abstract class NitpickerRule<MessageIds extends string = string, Options extends readonly unknown[] = []> {\n /**\n * The kebab-case name of the rule, without the plugin prefix\n * (e.g. `no-em-dash`).\n */\n abstract readonly name: string\n\n /**\n * The ESLint metadata describing the rule (type, docs, schema, messages).\n */\n abstract readonly meta: ESLintUtils.NamedCreateRuleMeta<MessageIds, NitpickerRuleDocs, Options>\n\n /**\n * The options applied when the rule is enabled without an explicit config.\n */\n abstract readonly defaultOptions: Options\n\n /**\n * The visitor factory ESLint calls for every linted file.\n * @param context The rule context for the current file.\n * @param options The user options merged with {@link defaultOptions}.\n * @returns The AST visitor listeners.\n */\n abstract create(\n context: Readonly<TSESLint.RuleContext<MessageIds, Options>>,\n options: Readonly<Options>,\n ): TSESLint.RuleListener\n\n /**\n * Builds the ESLint-compatible rule module from this instance.\n * @returns The plain rule module object consumed by ESLint.\n */\n toRuleModule(): TSESLint.RuleModule<MessageIds, Options, NitpickerRuleDocs> {\n return createRule<Options, MessageIds>({\n name: this.name,\n meta: this.meta,\n defaultOptions: this.defaultOptions,\n create: (context, options) => this.create(context, options),\n })\n }\n}\n","/**\n * Merges a base lookup with extra entries and removes ignored keys, keying everything in lowercase\n * for case-insensitive lookups. Used to let a rule's built-in table be extended or narrowed\n * through its options.\n * @param base The built-in lookup.\n * @param extra Additional entries to add or override.\n * @param ignore Keys to remove from the result.\n * @returns The merged, lowercase-keyed lookup.\n */\nexport function buildDictionary(\n base: Record<string, string>,\n extra: Record<string, string>,\n ignore: string[],\n): Record<string, string> {\n const dictionary: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(base)) {\n dictionary[key.toLowerCase()] = value\n }\n\n for (const [key, value] of Object.entries(extra)) {\n dictionary[key.toLowerCase()] = value\n }\n\n for (const key of ignore) {\n delete dictionary[key.toLowerCase()]\n }\n\n return dictionary\n}\n","/**\n * The building blocks of a Nitpicker message, every rule reports its findings\n * through this shape so that the output is consistent and, crucially,\n * self-explanatory enough for an AI (or a human) to fix the issue without\n * opening the rule's documentation.\n */\nexport type Nitpick = {\n /**\n * What is wrong, stated plainly. May contain ESLint `{{placeholders}}`.\n */\n problem: string\n\n /**\n * Why it is worth fixing, so the reader understands the intent.\n */\n why: string\n\n /**\n * A concrete, actionable instruction describing how to fix it.\n */\n fix: string\n}\n\n/**\n * Composes a {@link Nitpick} into a single, richly-contextualized message\n * string suitable for a rule's `meta.messages` entry.\n *\n * ESLint `{{placeholders}}` inside any field are preserved untouched, so they\n * can still be interpolated with `data` at report time.\n * @param nitpick The problem/why/fix triplet to format.\n * @returns The formatted, multi-line message.\n */\nexport function nitpick({ problem, why, fix }: Nitpick): string {\n return `${problem}\\n - why: ${why}\\n - fix: ${fix}`\n}\n","import CONSTANTS from \"@/lib/constants\"\n\n/**\n * A sub-word found in a piece of text, with its start offset.\n */\nexport type Word = {\n /**\n * The sub-word, in its original casing.\n */\n text: string\n\n /**\n * The offset of the sub-word within the source text.\n */\n index: number\n}\n\n/**\n * Splits a piece of text into its sub-words, handling camelCase, PascalCase,\n * snake_case, and plain prose.\n * @param text The text to split.\n * @returns The sub-words found, each with its offset in the text.\n */\nexport function extractWords(text: string): Word[] {\n const words: Word[] = []\n\n for (const match of text.matchAll(CONSTANTS.SUB_WORD)) {\n if (match.index !== undefined) {\n words.push({ text: match[0], index: match.index })\n }\n }\n\n return words\n}\n\n/**\n * Rewrites a replacement word to match the casing of the word it replaces, so a\n * capitalized source yields a capitalized result and an all-caps source an\n * all-caps one.\n * @param source The original word whose casing should be mirrored.\n * @param replacement The lowercase replacement word.\n * @returns The replacement, cased like the source.\n */\nexport function matchCase(source: string, replacement: string): string {\n if (source === source.toUpperCase()) {\n return replacement.toUpperCase()\n }\n\n if (source.charAt(0) === source.charAt(0).toUpperCase()) {\n return replacement.charAt(0).toUpperCase() + replacement.slice(1)\n }\n\n return replacement\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { BRITISH_TO_AMERICAN } from \"@/lib/data/britishToAmerican\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { buildDictionary } from \"@/lib/utils/dictionary\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\nimport { extractWords, matchCase } from \"@/lib/utils/words\"\n\ntype Options = [{ extra: Record<string, string>; ignore: string[] }]\ntype MessageIds = \"british\"\n\n/**\n * Flags British English spellings in identifiers and comments, reporting the\n * American equivalent. The built-in dictionary can be extended per project with\n * the `extra` option, or narrowed with `ignore`.\n */\nclass NoBritishEnglish extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-british-english\"\n\n readonly defaultOptions: Options = [{ extra: {}, ignore: [] }]\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Disallow British English spellings in identifiers and comments.\",\n recommended: true,\n category: \"base\",\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n extra: {\n type: \"object\",\n additionalProperties: { type: \"string\" },\n },\n ignore: {\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n british: nitpick({\n problem: \"British spelling `{{british}}`, this codebase uses American English.\",\n why: \"One spelling convention keeps identifiers and docs consistent and searchable\",\n fix: \"Use `{{american}}` instead\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const dictionary = buildDictionary(BRITISH_TO_AMERICAN, options[0]?.extra ?? {}, options[0]?.ignore ?? [])\n const { sourceCode } = context\n\n return {\n Identifier(node) {\n // Skip a member's property name (an external read), it cannot be\n // renamed from here\n if (node.parent.type === \"MemberExpression\" && node.parent.property === node && !node.parent.computed) {\n return\n }\n\n for (const word of extractWords(node.name)) {\n const american = dictionary[word.text.toLowerCase()]\n if (american === undefined) continue\n\n context.report({\n node,\n messageId: \"british\",\n data: { british: word.text, american: matchCase(word.text, american) },\n })\n }\n },\n Program() {\n for (const comment of sourceCode.getAllComments()) {\n for (const word of extractWords(comment.value)) {\n const american = dictionary[word.text.toLowerCase()]\n if (american === undefined) continue\n\n const cased = matchCase(word.text, american)\n\n // The comment value starts right after the `//` or `/*`\n const from = comment.range[0] + 2 + word.index\n const to = from + word.text.length\n\n context.report({\n loc: {\n start: sourceCode.getLocFromIndex(from),\n end: sourceCode.getLocFromIndex(to),\n },\n messageId: \"british\",\n data: { british: word.text, american: cased },\n fix: fixer => fixer.replaceTextRange([from, to], cased),\n })\n }\n }\n },\n }\n }\n}\n\nexport default new NoBritishEnglish()\n","import CONSTANTS from \"@/lib/constants\"\n\n/**\n * Checks whether a single comment line is a decorative separator, i.e. a banner,\n * a box-drawing rule, or a label fenced by repeated separator characters.\n * @param line The raw comment line, still carrying any leading ` * ` marker.\n * @returns `true` if the line is decorative.\n */\nexport function isDecorativeCommentLine(line: string): boolean {\n const content = line.replace(/^\\s*\\*?\\s*/, \"\").trimEnd()\n if (content.length === 0) return false\n\n return (\n CONSTANTS.BOX_DRAWING.test(content) ||\n CONSTANTS.PURE_SEPARATOR.test(content) ||\n CONSTANTS.WRAPPED_LABEL.test(content)\n )\n}\n","/**\n * Converts a glob pattern into an anchored regular expression, supporting `*`\n * (any run within a path segment) and `**` (any run across segments).\n * @param glob The glob pattern to convert.\n * @returns The equivalent regular expression.\n */\nfunction globToRegExp(glob: string): RegExp {\n const normalized = glob.replace(/\\\\/g, \"/\")\n let pattern = \"^\"\n\n for (let index = 0; index < normalized.length; index++) {\n const char = normalized[index]\n if (char === undefined) break\n\n if (char === \"*\") {\n if (normalized[index + 1] === \"*\") {\n pattern += \".*\"\n index++\n\n // If the `**` is followed by a `/`, skip it so that `**/` and `**` are equivalent\n if (normalized[index + 1] === \"/\") index++\n } else {\n pattern += \"[^/]*\"\n }\n } else if (\"\\\\^$.|?+()[]{}\".includes(char)) {\n pattern += `\\\\${char}`\n } else {\n pattern += char\n }\n }\n\n return new RegExp(`${pattern}$`)\n}\n\n/**\n * Checks whether a file path matches any of the given glob patterns, comparing\n * with forward slashes so it works the same on every platform.\n * @param filename The file path to test.\n * @param patterns The glob patterns to match against.\n * @returns `true` if the path matches at least one pattern.\n */\nexport function matchesGlob(filename: string, patterns: string[]): boolean {\n const path = filename.replace(/\\\\/g, \"/\")\n\n return patterns.some(pattern => globToRegExp(pattern).test(path))\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { isDecorativeCommentLine } from \"@/lib/utils/decoration\"\nimport { matchesGlob } from \"@/lib/utils/matchesGlob\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\n\ntype Options = [{ allowIn: string[] }]\ntype MessageIds = \"decorative\"\n\n/**\n * Flags decorative separators inside comments, such as banner rules\n * (`// ======`), box-drawing lines, and labels fenced by repeated dashes\n * (`// -- Section --`). The `allowIn` option lists globs where they are\n * tolerated, which the AdonisJS config uses to permit banners in route files.\n */\nclass NoDecorativeCommentSeparators extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-decorative-comment-separators\"\n\n readonly defaultOptions: Options = [{ allowIn: [] }]\n\n readonly meta = {\n type: \"layout\",\n docs: {\n description: \"Disallow decorative separators (banners, box-drawing, repeated dashes) inside comments.\",\n recommended: true,\n category: \"base\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowIn: {\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n decorative: nitpick({\n problem: \"This comment uses a decorative separator.\",\n why: \"Repeated separator characters and box-drawing lines are visual noise that add nothing over a plain label\",\n fix: \"Remove the separator, a one-line label or a blank line already divides sections clearly\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const allowIn = options[0]?.allowIn ?? []\n if (allowIn.length > 0 && matchesGlob(context.filename, allowIn)) {\n return {}\n }\n\n const { sourceCode } = context\n\n return {\n Program() {\n for (const comment of sourceCode.getAllComments()) {\n const lines = comment.value.split(\"\\n\")\n\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index]\n if (line === undefined || !isDecorativeCommentLine(line)) continue\n\n const reportedLine = comment.loc.start.line + index\n const source = sourceCode.lines[reportedLine - 1] ?? \"\"\n\n context.report({\n loc: {\n start: { line: reportedLine, column: 0 },\n end: { line: reportedLine, column: source.length },\n },\n messageId: \"decorative\",\n })\n }\n }\n },\n }\n }\n}\n\nexport default new NoDecorativeCommentSeparators()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\n\ntype Options = []\ntype MessageIds = \"emDash\"\n\n/**\n * Flags every em dash (—) character found anywhere in the source.\n */\nclass NoEmDash extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-em-dash\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Disallow the em dash (—) character anywhere in the source.\",\n recommended: true,\n },\n schema: [],\n messages: {\n emDash: nitpick({\n problem: \"Found an em dash (—) character.\",\n why: \"Em dashes are typically introduced by AI-generated or auto-formatted text and are discouraged here.\",\n fix: \"Replace the em dash with a hyphen (-), a comma (,), or reword the sentence to avoid it.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n const { sourceCode } = context\n const text = sourceCode.getText()\n\n return {\n Program() {\n // Scan the raw source so every em dash is caught, whether it appears\n // in code, strings, or comments\n for (let index = 0; index < text.length; index++) {\n if (text[index] !== CONSTANTS.EM_DASH) continue\n\n context.report({\n loc: {\n start: sourceCode.getLocFromIndex(index),\n end: sourceCode.getLocFromIndex(index + 1),\n },\n messageId: \"emDash\",\n })\n }\n },\n }\n }\n}\n\nexport default new NoEmDash()\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Checks whether a comment is a JSDoc comment, i.e. a block comment that opens\n * with `/**`.\n * @param comment The comment to test.\n * @returns `true` if the comment is a JSDoc block comment.\n */\nexport function isJSDocComment(comment: TSESTree.Comment): boolean {\n return comment.type === \"Block\" && comment.value.startsWith(\"*\")\n}\n\n/**\n * Checks whether a node is immediately preceded by a JSDoc comment.\n * @param sourceCode The source code of the linted file.\n * @param node The node to inspect the leading comments of.\n * @returns `true` if the comment right before the node is a JSDoc comment.\n */\nexport function hasLeadingJSDoc(sourceCode: Readonly<TSESLint.SourceCode>, node: TSESTree.Node): boolean {\n const commentsBefore = sourceCode.getCommentsBefore(node)\n const closest = commentsBefore.at(-1)\n\n return closest !== undefined && isJSDocComment(closest)\n}\n\n/**\n * Checks whether a physical JSDoc line is blank, i.e. just a ` * ` with no\n * content after it.\n * @param line The physical source line to test.\n * @returns `true` if the line is an empty JSDoc line.\n */\nexport function isBlankJSDocLine(line: string): boolean {\n return /^\\s*\\*\\s*$/.test(line)\n}\n\n/**\n * Checks whether a physical JSDoc line holds a block tag, i.e. a ` * ` followed\n * by an `@tag` such as `@param` or `@returns`.\n * @param line The physical source line to test.\n * @returns `true` if the line starts a JSDoc tag.\n */\nexport function isJSDocTagLine(line: string): boolean {\n return /^\\s*\\*\\s*@/.test(line)\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { isBlankJSDocLine, isJSDocComment, isJSDocTagLine } from \"@/lib/utils/JSDoc\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\n\ntype Options = []\ntype MessageIds = \"blankBeforeTag\"\n\n/**\n * Flags blank lines that sit between a JSDoc description and its tags (or\n * between tags) and removes them so the tags follow on directly.\n */\nclass NoJSDocBlankBeforeTags extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-jsdoc-blank-before-tags\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"layout\",\n fixable: \"code\",\n docs: {\n description: \"Disallow blank lines before JSDoc tags such as `@param` or `@returns`.\",\n recommended: true,\n },\n schema: [],\n messages: {\n blankBeforeTag: nitpick({\n problem: \"There is a blank line before a JSDoc tag.\",\n why: \"Tags should follow the description directly; an empty line there is noise that inflates the comment.\",\n fix: \"Remove the blank line so the tag follows on directly.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n const { sourceCode } = context\n\n return {\n Program() {\n for (const comment of sourceCode.getAllComments()) {\n if (!isJSDocComment(comment)) continue\n\n if (comment.loc.start.line === comment.loc.end.line) continue\n\n for (let line = comment.loc.start.line; line <= comment.loc.end.line; line++) {\n const text = sourceCode.lines[line - 1]\n if (text === undefined || !isBlankJSDocLine(text)) continue\n\n // Grow the run of consecutive blank lines\n let runEnd = line\n while (runEnd < comment.loc.end.line && isBlankJSDocLine(sourceCode.lines[runEnd] ?? \"\")) {\n runEnd++\n }\n\n // Only a blank run immediately before a tag is a problem\n const nextLine = sourceCode.lines[runEnd]\n if (nextLine !== undefined && isJSDocTagLine(nextLine)) {\n const from = sourceCode.getIndexFromLoc({ line, column: 0 })\n const to = sourceCode.getIndexFromLoc({ line: runEnd + 1, column: 0 })\n\n context.report({\n loc: {\n start: { line, column: 0 },\n end: { line: runEnd, column: text.length },\n },\n messageId: \"blankBeforeTag\",\n fix: fixer => fixer.removeRange([from, to]),\n })\n }\n\n line = runEnd\n }\n }\n },\n }\n }\n}\n\nexport default new NoJSDocBlankBeforeTags()\n","import CONSTANTS from \"@/lib/constants\"\n\n/**\n * Checks whether a character is a \"word\" character, i.e. something that can\n * appear inside an identifier or a number (letters, digits, underscore, dollar).\n * @param char The single character to test, or `undefined` (e.g. past the end\n * of a string).\n * @returns `true` if the character is a word character, `false` otherwise.\n */\nexport function isWordChar(char: string | undefined): boolean {\n return char !== undefined && CONSTANTS.WORD_CHAR.test(char)\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { isWordChar } from \"@/lib/utils/isWordChar\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\n\ntype Options = []\ntype MessageIds = \"period\"\n\n/**\n * Flags periods used as prose punctuation inside `//` line comments.\n *\n * Line comments should read as short, clear fragments rather than full\n * sentences, so periods are just noise. Dots that are part of a token, such as\n * `foo.bar`, `1.5`, `file.ts` or `.env`, and ellipses (`...`) are left alone.\n */\nclass NoLineCommentPeriod extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-line-comment-period\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"layout\",\n fixable: \"code\",\n docs: {\n description: \"Disallow prose periods in `//` line comments (code-reference dots and ellipses are allowed).\",\n recommended: true,\n },\n schema: [],\n messages: {\n period: nitpick({\n problem: \"This line comment contains a period.\",\n why: \"Line comments should be short, clear fragments, not full sentences, so periods are just noise, dots inside code references like `foo.bar` are allowed.\",\n fix: \"Remove the period and keep the comment terse.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n const { sourceCode } = context\n\n return {\n Program() {\n for (const comment of sourceCode.getAllComments()) {\n if (comment.type !== \"Line\") continue\n\n const { value } = comment\n // The comment value starts right after the leading `//`\n const valueStart = comment.range[0] + 2\n\n for (let index = 0; index < value.length; index++) {\n if (value[index] !== \".\") continue\n\n // A run of consecutive dots is an ellipsis, leave it alone\n if (value[index + 1] === \".\") {\n while (value[index + 1] === \".\") index++\n continue\n }\n\n // A lone dot immediately followed by a word character is\n // part of a token (`foo.bar`, `1.5`, `.env`), not prose\n if (isWordChar(value[index + 1])) continue\n\n const at = valueStart + index\n\n context.report({\n loc: {\n start: sourceCode.getLocFromIndex(at),\n end: sourceCode.getLocFromIndex(at + 1),\n },\n messageId: \"period\",\n fix: fixer => fixer.removeRange([at, at + 1]),\n })\n }\n }\n },\n }\n }\n}\n\nexport default new NoLineCommentPeriod()\n","import type { TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Checks whether an expression is nothing but a property access, i.e. a chain of\n * non-computed member accesses (with any `?.` or trailing `!`) that bottoms out\n * at an identifier or `this`, such as `auth.user!` or `menu.node.path`.\n *\n * Computed access (`arr[0]`), calls (`obj.method()`), and bare identifiers are\n * not property-access aliases.\n * @param node The expression to inspect.\n * @returns `true` if the expression is a plain property access.\n */\nexport function isPropertyAccessAlias(node: TSESTree.Expression): boolean {\n let expression: TSESTree.Node = node\n let sawMemberAccess = false\n\n while (true) {\n if (expression.type === \"ChainExpression\" || expression.type === \"TSNonNullExpression\") {\n expression = expression.expression\n continue\n }\n\n if (expression.type === \"MemberExpression\") {\n if (expression.computed) return false\n\n sawMemberAccess = true\n expression = expression.object\n continue\n }\n\n break\n }\n\n return sawMemberAccess && (expression.type === \"Identifier\" || expression.type === \"ThisExpression\")\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isPropertyAccessAlias } from \"@/lib/utils/aliases\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\n\ntype Options = []\ntype MessageIds = \"propertyAccessAlias\"\n\n/**\n * Flags a `const` whose entire value is a single property access, such as\n * `const user = auth.user!`, since it just renames a property and hides where\n * the value comes from, `let` is exempt, as it may be reassigned later.\n */\nclass NoPropertyAccessAlias extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-property-access-alias\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description:\n \"Disallow a `const` whose whole value is a single property access, inline the expression instead.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n propertyAccessAlias: nitpick({\n problem: \"`{{name}}` only aliases the property access `{{expression}}`.\",\n why: \"A variable that just renames a property hides where the value comes from when scanning the code\",\n fix: \"Remove it and use `{{expression}}` inline, or use `let` if it is reassigned later\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n const { sourceCode } = context\n\n return {\n VariableDeclarator(node) {\n if (node.parent.type !== \"VariableDeclaration\" || node.parent.kind !== \"const\") return\n\n // Exported bindings cannot be inlined away, so they are exempt\n if (node.parent.parent.type === \"ExportNamedDeclaration\") return\n\n if (node.id.type !== \"Identifier\" || node.init === null) return\n if (!isPropertyAccessAlias(node.init)) return\n\n context.report({\n node,\n messageId: \"propertyAccessAlias\",\n data: {\n name: node.id.name,\n expression: sourceCode.getText(node.init),\n },\n })\n },\n }\n }\n}\n\nexport default new NoPropertyAccessAlias()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { isJSDocComment } from \"@/lib/utils/JSDoc\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\n\ntype Options = []\ntype MessageIds = \"singleLine\"\n\n/**\n * Flags JSDoc comments (`/**`) that are written on a single line and expands\n * them into the multi-line form:\n * ```\n * /** blabla *​/ -> /**\n * * blabla\n * *​/\n * ```\n */\nclass NoSingleLineJSDoc extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-single-line-jsdoc\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"layout\",\n fixable: \"code\",\n docs: {\n description: \"Require JSDoc comments to span multiple lines rather than sit on a single line.\",\n recommended: true,\n },\n schema: [],\n messages: {\n singleLine: nitpick({\n problem: \"This JSDoc comment is written on a single line.\",\n why: \"Multi-line JSDoc is easier to read, diff, and extend with additional tags, and is the house style.\",\n fix: \"Put the opening `/**`, the ` * ` content, and the closing `*/` each on their own line.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n const { sourceCode } = context\n\n return {\n Program() {\n for (const comment of sourceCode.getAllComments()) {\n // Only JSDoc comments (`/**`) that fit on one line\n if (!isJSDocComment(comment)) continue\n if (comment.loc.start.line !== comment.loc.end.line) continue\n\n // Strip the leading `*` left over from `/**` and normalize\n const content = comment.value.replace(/^\\*/, \"\").trim()\n\n // An empty JSDoc (`/** */`) has nothing to expand onto its\n // own line, so it is left alone\n if (content.length === 0) continue\n\n context.report({\n loc: comment.loc,\n messageId: \"singleLine\",\n fix(fixer) {\n const indent = \" \".repeat(comment.loc.start.column)\n const expanded = `/**\\n${indent} * ${content}\\n${indent} */`\n return fixer.replaceTextRange(comment.range, expanded)\n },\n })\n }\n },\n }\n }\n}\n\nexport default new NoSingleLineJSDoc()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * A framework Nitpicker ships a dedicated rule category and shared config for.\n */\nexport type Framework = \"adonisjs\" | \"react\"\n\n/**\n * The human-readable label for each framework, used in messages.\n */\nexport const FRAMEWORK_LABELS: Record<Framework, string> = {\n adonisjs: \"AdonisJS\",\n react: \"React\",\n}\n\n/**\n * Collects the module specifiers imported by a source file.\n * @param sourceCode The source code of the linted file.\n * @returns The list of imported module specifiers.\n */\nfunction importSources(sourceCode: Readonly<TSESLint.SourceCode>): string[] {\n const sources: string[] = []\n\n for (const statement of sourceCode.ast.body) {\n if (statement.type === \"ImportDeclaration\") {\n sources.push(String(statement.source.value))\n }\n }\n\n return sources\n}\n\n/**\n * Detects which supported frameworks a file appears to use, based on its imports\n * and file name.\n * @param sourceCode The source code of the linted file.\n * @param filename The path of the linted file.\n * @returns The set of frameworks detected in the file.\n */\nexport function detectFrameworks(sourceCode: Readonly<TSESLint.SourceCode>, filename: string): Set<Framework> {\n const detected = new Set<Framework>()\n const sources = importSources(sourceCode)\n\n if (sources.some(source => source.startsWith(\"@adonisjs/\") || CONSTANTS.ADONIS_SUBPATH.test(source))) {\n detected.add(\"adonisjs\")\n }\n\n const importsReact = sources.some(\n source => source === \"react\" || source.startsWith(\"react/\") || source === \"react-dom\",\n )\n if (importsReact || CONSTANTS.REACT_FILE.test(filename)) {\n detected.add(\"react\")\n }\n\n return detected\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { detectFrameworks, FRAMEWORK_LABELS, type Framework } from \"@/lib/utils/framework\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\n\ntype Options = [{ ignore: Framework[] }]\ntype MessageIds = \"missingConfig\"\n\n/**\n * Warns when a file uses a framework (AdonisJS, React) whose Nitpicker config is\n * not enabled, so its framework-specific conventions are silently going\n * unchecked. The warning disappears once the matching config is added (each one\n * sets a settings flag), or the rule can be turned off.\n */\nclass RequireFrameworkConfig extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-framework-config\"\n\n readonly defaultOptions: Options = [{ ignore: [] }]\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Warn when a file uses a framework whose Nitpicker config is not enabled.\",\n recommended: true,\n category: \"base\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n ignore: {\n type: \"array\",\n items: {\n type: \"string\",\n enum: [\"adonisjs\", \"react\"],\n },\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingConfig: nitpick({\n problem: \"This file uses {{framework}} but the Nitpicker {{framework}} rules are not enabled.\",\n why: \"Framework rules only run when you opt into the matching config, so files like this one go unchecked\",\n fix: \"Add `nitpicker.configs.{{config}}` (scoped to these files) to your ESLint config, or turn off `nitpicker/require-framework-config`\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const ignored = new Set(options[0]?.ignore ?? [])\n\n // Each framework config stamps `settings.nitpicker<framework> = true`\n const enabled = (context.settings[CONSTANTS.PLUGIN_NAME] ?? {}) as Partial<Record<Framework, boolean>>\n\n return {\n Program(node) {\n const detected = detectFrameworks(context.sourceCode, context.filename)\n\n for (const framework of detected) {\n if (ignored.has(framework) || enabled[framework]) continue\n\n context.report({\n node,\n messageId: \"missingConfig\",\n data: { framework: FRAMEWORK_LABELS[framework], config: framework },\n })\n }\n },\n }\n }\n}\n\nexport default new RequireFrameworkConfig()\n","import type { TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Any node that introduces a callable function.\n */\nexport type FunctionNode = TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression\n\n/**\n * Resolves the node whose leading comments would document a function, walking\n * outwards through a variable declaration and/or an export statement.\n *\n * For `export const foo = () => {}` this is the `export` node, whereas for a\n * bare `function foo() {}` it is the declaration itself.\n * @param fn The function node to resolve from.\n * @returns The node a JSDoc comment would sit above.\n */\nexport function getDocumentableNode(fn: FunctionNode): TSESTree.Node {\n let node: TSESTree.Node = fn\n\n if (node.parent.type === \"VariableDeclarator\" && node.parent.parent.type === \"VariableDeclaration\") {\n node = node.parent.parent\n }\n\n if (node.parent.type === \"ExportNamedDeclaration\" || node.parent.type === \"ExportDefaultDeclaration\") {\n node = node.parent\n }\n\n return node\n}\n\n/**\n * Checks whether a node sits directly at the top level of the module.\n * @param node The node to test.\n * @returns `true` if the node's parent is the program root.\n */\nexport function isTopLevel(node: TSESTree.Node): boolean {\n return node.parent?.type === \"Program\"\n}\n\n/**\n * Resolves the declared name of a function, whether it comes from the function\n * itself or the variable it is assigned to.\n * @param fn The function node to name.\n * @returns The function name, or `undefined` if it is anonymous.\n */\nexport function getFunctionName(fn: FunctionNode): string | undefined {\n if ((fn.type === \"FunctionDeclaration\" || fn.type === \"FunctionExpression\") && fn.id) {\n return fn.id.name\n }\n\n if (fn.parent.type === \"VariableDeclarator\" && fn.parent.id.type === \"Identifier\") {\n return fn.parent.id.name\n }\n\n return undefined\n}\n","import type { TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * The AST node types that introduce a new function scope.\n */\nconst FUNCTION_NODE_TYPES = new Set<string>([\"FunctionDeclaration\", \"FunctionExpression\", \"ArrowFunctionExpression\"])\n\n/**\n * A lookup of AST node type to the property keys that hold its child nodes.\n */\ntype VisitorKeys = Record<string, readonly string[] | undefined>\n\n/**\n * Checks whether a name follows the `PascalCase` convention React uses to\n * distinguish component functions from plain functions and DOM tags.\n * @param name The function name to test.\n * @returns `true` if the name starts with an uppercase letter.\n */\nexport function isReactComponentName(name: string): boolean {\n return /^[A-Z]/.test(name)\n}\n\n/**\n * Checks whether an expression evaluates to JSX, following the branches a\n * component commonly returns through (ternaries, `&&`, comma sequences).\n * @param node The expression to inspect, if any.\n * @returns `true` if the expression can produce a JSX element or fragment.\n */\nexport function isJsxExpression(node: TSESTree.Expression | null | undefined): boolean {\n if (!node) return false\n\n switch (node.type) {\n case \"JSXElement\":\n case \"JSXFragment\":\n return true\n case \"ConditionalExpression\":\n return isJsxExpression(node.consequent) || isJsxExpression(node.alternate)\n case \"LogicalExpression\":\n return isJsxExpression(node.left) || isJsxExpression(node.right)\n case \"SequenceExpression\":\n return isJsxExpression(node.expressions.at(-1))\n default:\n return false\n }\n}\n\n/**\n * Recursively searches a subtree for a `return` that yields JSX, without\n * crossing into nested functions (whose returns belong to them, not us).\n * @param node The AST node to inspect.\n * @param visitorKeys The AST visitor keys, used to walk the subtree.\n */\nfunction subtreeReturnsJsx(node: TSESTree.Node, visitorKeys: VisitorKeys): boolean {\n if (node.type === \"ReturnStatement\") {\n return isJsxExpression(node.argument)\n }\n\n for (const key of visitorKeys[node.type] ?? []) {\n const value = (node as unknown as Record<string, unknown>)[key]\n const children = Array.isArray(value) ? value : [value]\n\n for (const child of children) {\n const childNode = child as TSESTree.Node | null | undefined\n if (!childNode || typeof childNode.type !== \"string\") continue\n\n // Nested functions own their own returns, so stop descending there\n if (FUNCTION_NODE_TYPES.has(childNode.type)) continue\n if (subtreeReturnsJsx(childNode, visitorKeys)) return true\n }\n }\n\n return false\n}\n\n/**\n * Checks whether a function returns JSX, i.e. whether it looks like it renders\n * a React element.\n * @param fn The function node to inspect.\n * @param visitorKeys The AST visitor keys, used to walk the function body.\n * @returns True if the function returns JSX.\n */\nexport function functionReturnsJsx(\n fn: TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression,\n visitorKeys: VisitorKeys,\n): boolean {\n // An arrow with an expression body returns that expression directly\n if (fn.type === \"ArrowFunctionExpression\" && fn.body.type !== \"BlockStatement\") {\n return isJsxExpression(fn.body)\n }\n\n return subtreeReturnsJsx(fn.body, visitorKeys)\n}\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport { type FunctionNode, getDocumentableNode, getFunctionName, isTopLevel } from \"@/lib/utils/functions\"\nimport { hasLeadingJSDoc } from \"@/lib/utils/JSDoc\"\nimport { nitpick } from \"@/lib/utils/nitpick\"\nimport { functionReturnsJsx, isReactComponentName } from \"@/lib/utils/react\"\n\ntype Options = []\ntype MessageIds = \"missingJSDoc\"\n\n/**\n * Requires a JSDoc comment on top-level functions, with React component\n * functions (`PascalCase` name returning JSX) being the sole exception.\n */\nclass RequireFunctionJSDoc extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-function-jsdoc\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Require a JSDoc comment on top-level functions, except React component functions.\",\n recommended: true,\n },\n schema: [],\n messages: {\n missingJSDoc: nitpick({\n problem: \"The function `{{name}}` has no JSDoc comment.\",\n why: \"Top-level functions must document their purpose, parameters, and return value, React component functions are the only exception.\",\n fix: \"Add a `/** ... */` JSDoc block immediately above the function describing what it does.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n const { sourceCode } = context\n\n const check = (fn: FunctionNode, reportNode: TSESTree.Node): void => {\n const name = getFunctionName(fn)\n // Anonymous functions (e.g `export default () => {}`) are skipped\n if (name === undefined) return\n\n const documentable = getDocumentableNode(fn)\n if (!isTopLevel(documentable)) return\n\n // React component functions are exempt from the JSDoc requirement\n if (isReactComponentName(name) && functionReturnsJsx(fn, sourceCode.visitorKeys)) return\n\n if (hasLeadingJSDoc(sourceCode, documentable)) return\n\n context.report({\n node: reportNode,\n messageId: \"missingJSDoc\",\n data: { name },\n })\n }\n\n return {\n FunctionDeclaration(node) {\n check(node, node.id ?? node)\n },\n VariableDeclarator(node) {\n const { init } = node\n if (!init) return\n if (init.type !== \"ArrowFunctionExpression\" && init.type !== \"FunctionExpression\") return\n\n check(init, node.id)\n },\n }\n }\n}\n\nexport default new RequireFunctionJSDoc()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/createRule\"\nimport noBritishEnglish from \"@/rules/base/noBritishEnglish\"\nimport noDecorativeCommentSeparators from \"@/rules/base/noDecorativeCommentSeparators\"\nimport noEmDash from \"@/rules/base/noEmDash\"\nimport noJSDocBlankBeforeTags from \"@/rules/base/noJSDocBlankBeforeTags\"\nimport noLineCommentPeriod from \"@/rules/base/noLineCommentPeriod\"\nimport noPropertyAccessAlias from \"@/rules/base/noPropertyAccessAlias\"\nimport noSingleLineJSDoc from \"@/rules/base/noSingleLineJSDoc\"\nimport requireFrameworkConfig from \"@/rules/base/requireFrameworkConfig\"\nimport requireFunctionJSDoc from \"@/rules/base/requireFunctionJSDoc\"\n\n/**\n * Every rule instance registered by the plugin.\n */\nconst ruleInstances = [\n noBritishEnglish,\n noDecorativeCommentSeparators,\n noEmDash,\n noJSDocBlankBeforeTags,\n noLineCommentPeriod,\n noPropertyAccessAlias,\n noSingleLineJSDoc,\n requireFrameworkConfig,\n requireFunctionJSDoc,\n]\n\n/**\n * The plugin's rules, keyed by name, as the plain modules ESLint consumes.\n */\nexport const rules = Object.fromEntries(ruleInstances.map(rule => [rule.name, rule.toRuleModule()])) as Record<\n string,\n TSESLint.RuleModule<string, readonly unknown[], NitpickerRuleDocs>\n>\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\nimport type { RuleCategory } from \"@/lib/utils/createRule\"\nimport { rules } from \"@/rules\"\n\n/**\n * Builds the rules record for a single category, each enabled as a warning,\n * rules with no explicit category are treated as `base`.\n * @param category The category to collect rules for.\n * @returns The flat-config rules record for that category.\n */\nexport function categoryRules(category: RuleCategory): TSESLint.FlatConfig.Rules {\n const enabled: TSESLint.FlatConfig.Rules = {}\n\n for (const [name, rule] of Object.entries(rules)) {\n if ((rule.meta.docs?.category ?? \"base\") === category) {\n enabled[`${CONSTANTS.PLUGIN_NAME}/${name}`] = \"warn\"\n }\n }\n\n return enabled\n}\n\n/**\n * Builds a rules record enabling every rule the plugin ships, as a warning.\n * @returns The flat-config rules record for all rules.\n */\nexport function allRules(): TSESLint.FlatConfig.Rules {\n const enabled: TSESLint.FlatConfig.Rules = {}\n\n for (const name of Object.keys(rules)) {\n enabled[`${CONSTANTS.PLUGIN_NAME}/${name}`] = \"warn\"\n }\n\n return enabled\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { allRules } from \"@/configs/helpers\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Builds the `all` flat config: every rule the plugin ships, each enabled as a\n * warning, this is the maximally-pedantic Nitpicker experience. Both framework\n * settings flags are set, since enabling everything already opts into them.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function all(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n name: `${CONSTANTS.PLUGIN_NAME}/all`,\n plugins: { [CONSTANTS.PLUGIN_NAME]: plugin },\n settings: { [CONSTANTS.PLUGIN_NAME]: { adonisjs: true, react: true } },\n rules: allRules(),\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { categoryRules } from \"@/configs/helpers\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Builds the `base` flat config: the universal rules that apply to every file\n * regardless of framework.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function base(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n name: `${CONSTANTS.PLUGIN_NAME}/base`,\n plugins: { [CONSTANTS.PLUGIN_NAME]: plugin },\n rules: categoryRules(\"base\"),\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { base } from \"@/configs/rulesets/base\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Builds the `recommended` flat config: the sensible default for any project,\n * which is the universal `base` ruleset.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function recommended(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n ...base(plugin),\n name: `${CONSTANTS.PLUGIN_NAME}/recommended`,\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { categoryRules } from \"@/configs/helpers\"\nimport CONSTANTS from \"@/lib/constants\"\n\n// AdonisJS route files where banner separators are the clearest way to group routes\nconst ROUTE_FILE_GLOBS = [\"**/start/routes.ts\", \"**/start/routes/**/*.ts\"]\n\n/**\n * Builds the `adonisjs` flat config: AdonisJS-specific rules, plus a settings\n * flag so `require-framework-config` knows AdonisJS is opted into for these files.\n * It also permits decorative banners in route files, where they aid readability.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function adonisjs(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n name: `${CONSTANTS.PLUGIN_NAME}/adonisjs`,\n plugins: { [CONSTANTS.PLUGIN_NAME]: plugin },\n settings: { [CONSTANTS.PLUGIN_NAME]: { adonisjs: true } },\n rules: {\n ...categoryRules(\"adonisjs\"),\n [`${CONSTANTS.PLUGIN_NAME}/no-decorative-comment-separators`]: [\"warn\", { allowIn: ROUTE_FILE_GLOBS }],\n },\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { categoryRules } from \"@/configs/helpers\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Builds the `react` flat config: React-specific rules, plus a settings flag so\n * `require-framework-config` knows React is opted into for these files.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function react(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n name: `${CONSTANTS.PLUGIN_NAME}/react`,\n plugins: { [CONSTANTS.PLUGIN_NAME]: plugin },\n settings: { [CONSTANTS.PLUGIN_NAME]: { react: true } },\n rules: categoryRules(\"react\"),\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { all } from \"@/configs/presets/all\"\nimport { recommended } from \"@/configs/presets/recommended\"\nimport { adonisjs } from \"@/configs/rulesets/adonisjs\"\nimport { base } from \"@/configs/rulesets/base\"\nimport { react } from \"@/configs/rulesets/react\"\n\n/**\n * Builds all shared configs bundled with the plugin.\n *\n * Note: Configs are built from a factory rather than declared statically\n * because each one needs a reference to the plugin instance it belongs to.\n * @param plugin The plugin instance to register the rules against.\n * @returns A record of config name to flat config object.\n */\nexport function buildConfigs(plugin: TSESLint.FlatConfig.Plugin): Record<string, TSESLint.FlatConfig.Config> {\n return {\n base: base(plugin),\n recommended: recommended(plugin),\n adonisjs: adonisjs(plugin),\n react: react(plugin),\n all: all(plugin),\n }\n}\n","{\n \"name\": \"@alien_intelligence/eslint-plugin-nitpicker\",\n \"productName\": \"Nitpicker\",\n \"version\": \"0.1.0\",\n \"description\": \"A hyper-pedantic ESLint plugin that flags every stylistic and semantic nit, with AI-friendly fix context.\",\n \"author\": \"Alien <contact@alien.club> (https://www.alien.club/)\",\n \"license\": \"MIT\",\n \"private\": false,\n \"packageManager\": \"npm@11.4.2\",\n \"type\": \"module\",\n \"keywords\": [\n \"alien\",\n \"eslint\",\n \"eslintplugin\",\n \"eslint-plugin\",\n \"nitpicker\",\n \"linting\",\n \"code-style\",\n \"ai\"\n ],\n \"homepage\": \"https://github.com/the-alien-club/eslint-plugin-nitpicker\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/the-alien-club/eslint-plugin-nitpicker.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/the-alien-club/eslint-plugin-nitpicker/issues\"\n },\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org/\",\n \"access\": \"public\",\n \"tag\": \"latest\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"lint\": \"biome check\",\n \"lint:fix\": \"biome check --fix && biome format --write\",\n \"lint:nitpicker\": \"eslint \\\"src/**/*.ts\\\" \\\"tests/**/*.ts\\\"\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"peerDependencies\": {\n \"eslint\": \">=9.0.0\"\n },\n \"dependencies\": {\n \"@typescript-eslint/utils\": \"^8.18.0\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.5.2\",\n \"@types/node\": \"^24.12.2\",\n \"@typescript-eslint/parser\": \"^8.64.0\",\n \"eslint\": \"^9.17.0\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.8.3\",\n \"vitest\": \"^4.1.5\"\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { buildConfigs } from \"@/configs\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { rules } from \"@/rules\"\n\n// Import the version from package.json to include in the plugin metadata\nimport { version } from \"../package.json\"\n\n/**\n * Main declaration of the `@alien_intelligence/eslint-plugin-nitpicker` plugin.\n */\nconst plugin: TSESLint.FlatConfig.Plugin = {\n meta: {\n name: `eslint-plugin-${CONSTANTS.PLUGIN_NAME}`,\n version,\n },\n rules,\n configs: {},\n}\n\n// Configs reference the plugin, so they are attached after it is created\nplugin.configs = buildConfigs(plugin)\n\nexport default plugin\n"]}
1
+ {"version":3,"sources":["../src/lib/constants.ts","../src/lib/utils/rules.ts","../src/lib/rule.ts","../src/lib/utils/messages.ts","../src/lib/utils/migrations.ts","../src/rules/adonisjs/migrationTableOrder.ts","../src/lib/utils/jsdocs.ts","../src/rules/adonisjs/requireMigrationJSDoc.ts","../src/rules/base/maxJSDocDescriptionLength.ts","../src/rules/base/noAliasVariables.ts","../src/lib/data/britishToAmerican.ts","../src/lib/utils/dictionaries.ts","../src/lib/utils/words.ts","../src/rules/base/noBritishEnglish.ts","../src/lib/utils/decorations.ts","../src/lib/utils/regex.ts","../src/rules/base/noDecorativeCommentSeparators.ts","../src/rules/base/noEmDash.ts","../src/rules/base/noJSDocBlankBeforeTags.ts","../src/rules/base/noLineCommentPeriod.ts","../src/lib/utils/aliases.ts","../src/rules/base/noPropertyAccessAlias.ts","../src/rules/base/noPropertyDestructuring.ts","../src/rules/base/noSingleLineJSDoc.ts","../src/lib/utils/frameworks.ts","../src/rules/base/requireFrameworkConfig.ts","../src/lib/utils/functions.ts","../src/lib/utils/react.ts","../src/rules/base/requireFunctionJSDoc.ts","../src/rules/index.ts","../src/configs/helpers.ts","../src/configs/presets/all.ts","../src/configs/rulesets/base.ts","../src/configs/presets/recommended.ts","../src/configs/rulesets/adonisjs.ts","../src/configs/rulesets/react.ts","../src/configs/index.ts","../package.json","../src/index.ts"],"names":["CONSTANTS","constants_default","createRule","ESLintUtils","name","NitpickerRule","context","options","nitpick","problem","why","fix","isMigrationClass","node","getCreateTableBuilder","callback","getTableStatementCategory","statement","builderName","root","rootBuilderCall","expression","current","firstArgument","literal","MigrationTableOrder","builder","maxRank","category","rank","migrationTableOrder_default","isJSDocComment","comment","hasLeadingJSDoc","sourceCode","closest","isBlankJSDocLine","line","isJSDocTagLine","getJSDocDescription","parts","content","RequireMigrationJSDoc","requireMigrationJSDoc_default","DEFAULT_MAX","MaxJSDocDescriptionLength","max","length","maxJSDocDescriptionLength_default","NoAliasVariables","noAliasVariables_default","BRITISH_TO_AMERICAN","buildDictionary","base","extra","ignore","dictionary","key","value","extractWords","text","words","match","matchCase","source","replacement","isWordChar","char","NoBritishEnglish","word","american","cased","from","to","fixer","noBritishEnglish_default","isDecorativeCommentLine","globToRegExp","glob","normalized","pattern","index","matchesGlob","filename","patterns","path","NoDecorativeCommentSeparators","allowIn","lines","reportedLine","noDecorativeCommentSeparators_default","NoEmDash","noEmDash_default","NoJSDocBlankBeforeTags","runEnd","nextLine","noJSDocBlankBeforeTags_default","NoLineCommentPeriod","valueStart","at","noLineCommentPeriod_default","isPropertyAccessAlias","sawMemberAccess","NoPropertyAccessAlias","noPropertyAccessAlias_default","NoPropertyDestructuring","isAllShorthand","property","noPropertyDestructuring_default","NoSingleLineJSDoc","indent","expanded","noSingleLineJSDoc_default","FRAMEWORK_LABELS","importSources","sources","detectFrameworks","detected","RequireFrameworkConfig","ignored","enabled","framework","requireFrameworkConfig_default","getDocumentableNode","fn","isTopLevel","getFunctionName","FUNCTION_NODE_TYPES","isReactComponentName","isJsxExpression","subtreeReturnsJsx","visitorKeys","children","child","childNode","functionReturnsJsx","RequireFunctionJSDoc","check","reportNode","documentable","requireFunctionJSDoc_default","ruleInstances","rules","rule","categoryRules","allRules","all","plugin","recommended","ROUTE_FILE_GLOBS","adonisjs","react","buildConfigs","version","index_default"],"mappings":"mDAGA,IAAMA,EAAAA,CAAY,CAKd,WAAA,CAAa,WAAA,CAKb,QAAA,CAAU,2DAAA,CAKV,OAAA,CAAS,QAAA,CAKT,QAAA,CAAU,CAKN,WAAA,CAAa,OAAA,CAMb,cAAA,CAAgB,iBAAA,CAKhB,aAAA,CAAe,oCACnB,CAAA,CAKA,KAAA,CAAO,CAKH,SAAA,CAAW,iBAAA,CAMX,QAAA,CAAU,qCACd,CAAA,CAKA,UAAA,CAAY,CAIR,cAAA,CACI,sGAAA,CAKJ,WAAY,WAChB,CAAA,CAKA,UAAA,CAAY,CAIR,aAAA,CAAe,IAAI,GAAA,CAAI,CAAC,OAAA,CAAS,QAAA,CAAU,SAAA,CAAW,SAAS,CAAC,CAAA,CAKhE,iBAAA,CAAmB,IAAI,IAAI,CAAC,WAAA,CAAa,UAAA,CAAY,UAAU,CAAC,CAAA,CAMhE,gBAAA,CAAkB,IAAI,GAAA,CAAI,CAAC,YAAA,CAAc,YAAA,CAAc,YAAY,CAAC,CAAA,CAMpE,cAAA,CAAgB,CAAC,QAAA,CAAU,WAAA,CAAa,OAAO,CACnD,CACJ,CAAA,CAEOC,CAAAA,CAAQD,EAAAA,CCxER,IAAME,CAAAA,CAAaC,WAAAA,CAAY,WAAA,CAClCC,GAAQ,CAAA,EAAGH,CAAAA,CAAU,QAAQ,CAAA,sBAAA,EAAyBG,CAAI,CAAA,GAAA,CAC9D,CAAA,CCzBO,IAAeC,CAAAA,CAAf,KAA0G,CAgC7G,YAAA,EAA4E,CACxE,OAAOH,CAAAA,CAAgC,CACnC,KAAM,IAAA,CAAK,IAAA,CACX,IAAA,CAAM,IAAA,CAAK,IAAA,CACX,cAAA,CAAgB,IAAA,CAAK,cAAA,CACrB,MAAA,CAAQ,CAACI,CAAAA,CAASC,CAAAA,GAAY,IAAA,CAAK,MAAA,CAAOD,CAAAA,CAASC,CAAO,CAC9D,CAAC,CACL,CACJ,CAAA,CCtBO,SAASC,CAAAA,CAAQ,CAAE,OAAA,CAAAC,CAAAA,CAAS,GAAA,CAAAC,CAAAA,CAAK,GAAA,CAAAC,CAAI,CAAA,CAAoB,CAC5D,OAAO,GAAGF,CAAO;AAAA,SAAA,EAAcC,CAAG;AAAA,SAAA,EAAcC,CAAG,EACvD,CCbO,SAASC,EAAiBC,CAAAA,CAA0C,CACvE,OACIA,CAAAA,CAAK,MAAA,CAAO,OAAS,0BAAA,EACrBA,CAAAA,CAAK,YAAY,IAAA,GAAS,YAAA,EAC1BA,EAAK,UAAA,CAAW,IAAA,GAAS,YAEjC,CAQO,SAASC,CAAAA,CAAsBD,EAG7B,CAML,GALIA,EAAK,MAAA,CAAO,IAAA,GAAS,oBAAsBA,CAAAA,CAAK,MAAA,CAAO,QAAA,CAAS,IAAA,GAAS,YAAA,EACzEA,CAAAA,CAAK,OAAO,QAAA,CAAS,IAAA,GAAS,eAG9BA,CAAAA,CAAK,MAAA,CAAO,OAAO,IAAA,GAAS,kBAAA,EAAsBA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,QAAA,CAAS,OAAS,YAAA,EACvFA,CAAAA,CAAK,OAAO,MAAA,CAAO,QAAA,CAAS,OAAS,QAAA,CAAU,OAAO,KAE1D,IAAME,CAAAA,CAAWF,EAAK,SAAA,CAAU,EAAA,CAAG,EAAE,CAAA,CAErC,OADIE,GAAU,IAAA,GAAS,yBAAA,EAA6BA,CAAAA,EAAU,IAAA,GAAS,oBAAA,EACnEA,CAAAA,CAAS,KAAK,IAAA,GAAS,gBAAA,EAAoBA,EAAS,MAAA,CAAO,CAAC,GAAG,IAAA,GAAS,YAAA,CAAqB,IAAA,CAE1F,CAAE,IAAA,CAAMA,CAAAA,CAAS,KAAK,IAAA,CAAM,WAAA,CAAaA,EAAS,MAAA,CAAO,CAAC,EAAE,IAAK,CAC5E,CAQO,SAASC,CAAAA,CAA0BC,CAAAA,CAA+BC,EAA2C,CAChH,GAAID,EAAU,IAAA,GAAS,qBAAA,CAAuB,OAAO,IAAA,CAErD,IAAME,EAAOC,EAAAA,CAAgBH,CAAAA,CAAU,WAAYC,CAAW,CAAA,CAC9D,OAAIC,CAAAA,GAAS,IAAA,CAAa,KAEtBlB,CAAAA,CAAU,UAAA,CAAW,aAAA,CAAc,GAAA,CAAIkB,CAAAA,CAAK,MAAM,EAAU,OAAA,CAC5DA,CAAAA,CAAK,SAAW,YAAA,EAEhBlB,CAAAA,CAAU,WAAW,iBAAA,CAAkB,GAAA,CAAIkB,CAAAA,CAAK,MAAM,CAAA,EACtDA,CAAAA,CAAK,gBAAkB,MAAA,EACvBlB,CAAAA,CAAU,WAAW,gBAAA,CAAiB,GAAA,CAAIkB,EAAK,aAAa,CAAA,CAErD,WAAA,CAGJ,QACX,CASA,SAASC,GACLC,CAAAA,CACAH,CAAAA,CAC4D,CAC5D,IAAII,CAAAA,CAAyBD,EAE7B,KAAOC,CAAAA,CAAQ,OAAS,gBAAA,EAAoBA,CAAAA,CAAQ,OAAO,IAAA,GAAS,kBAAA,EAAoB,CACpF,GAAIA,CAAAA,CAAQ,OAAO,MAAA,CAAO,IAAA,GAAS,YAAA,EAAgBA,CAAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,OAASJ,CAAAA,CAAa,CAC3F,GAAII,CAAAA,CAAQ,MAAA,CAAO,SAAS,IAAA,GAAS,YAAA,CAAc,OAAO,IAAA,CAE1D,IAAMC,CAAAA,CAAgBD,EAAQ,SAAA,CAAU,CAAC,EACnCE,CAAAA,CACFD,CAAAA,EAAe,OAAS,SAAA,EAAa,OAAOA,CAAAA,CAAc,KAAA,EAAU,QAAA,CAC9DA,CAAAA,CAAc,MACd,MAAA,CAEV,OAAO,CAAE,MAAA,CAAQD,CAAAA,CAAQ,OAAO,QAAA,CAAS,IAAA,CAAM,cAAeE,CAAQ,CAC1E,CAEAF,CAAAA,CAAUA,CAAAA,CAAQ,OAAO,OAC7B,CAEA,OAAO,IACX,CCvFA,IAAMG,CAAAA,CAAN,cAAkCpB,CAAmC,CACxD,IAAA,CAAO,uBAAA,CAEP,eAA0B,EAAC,CAE3B,KAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,8FACb,WAAA,CAAa,IAAA,CACb,SAAU,UACd,CAAA,CACA,OAAQ,EAAC,CACT,QAAA,CAAU,CACN,UAAA,CAAYG,CAAAA,CAAQ,CAChB,OAAA,CAAS,4DAAA,CACT,IAAK,8HAAA,CACL,GAAA,CAAK,6FACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,EAAqF,CACxF,OAAO,CACH,cAAA,CAAeO,CAAAA,CAAM,CACjB,IAAMa,CAAAA,CAAUZ,CAAAA,CAAsBD,CAAI,CAAA,CAC1C,GAAIa,IAAY,IAAA,CAAM,OAEtB,IAAIC,CAAAA,CAAU,CAAA,CAEd,QAAWV,CAAAA,IAAaS,CAAAA,CAAQ,IAAA,CAAM,CAClC,IAAME,CAAAA,CAAWZ,EAA0BC,CAAAA,CAAWS,CAAAA,CAAQ,WAAW,CAAA,CACzE,GAAIE,IAAa,IAAA,CAAM,SAEvB,IAAMC,CAAAA,CAAO5B,CAAAA,CAAU,UAAA,CAAW,eAAe,OAAA,CAAQ2B,CAAQ,EAC7DC,CAAAA,CAAOF,CAAAA,EACPrB,EAAQ,MAAA,CAAO,CAAE,KAAMW,CAAAA,CAAW,SAAA,CAAW,aAAc,IAAA,CAAM,CAAE,SAAAW,CAAS,CAAE,CAAC,CAAA,CAGnFD,CAAAA,CAAU,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAASE,CAAI,EACpC,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOC,EAAQ,IAAIL,CAAAA,CCrDZ,SAASM,CAAAA,CAAeC,CAAAA,CAAoC,CAC/D,OAAOA,CAAAA,CAAQ,IAAA,GAAS,SAAWA,CAAAA,CAAQ,KAAA,CAAM,WAAW,GAAG,CACnE,CAQO,SAASC,CAAAA,CAAgBC,CAAAA,CAA2CrB,EAA8B,CAErG,IAAMsB,EADiBD,CAAAA,CAAW,iBAAA,CAAkBrB,CAAI,CAAA,CACzB,EAAA,CAAG,EAAE,CAAA,CAEpC,OAAOsB,CAAAA,GAAY,QAAaJ,CAAAA,CAAeI,CAAO,CAC1D,CAQO,SAASC,EAAiBC,CAAAA,CAAuB,CACpD,OAAO,YAAA,CAAa,IAAA,CAAKA,CAAI,CACjC,CAQO,SAASC,EAAeD,CAAAA,CAAuB,CAClD,OAAO,YAAA,CAAa,IAAA,CAAKA,CAAI,CACjC,CASO,SAASE,EAAoBP,CAAAA,CAAmC,CACnE,IAAMQ,CAAAA,CAAkB,GAExB,IAAA,IAAWH,CAAAA,IAAQL,CAAAA,CAAQ,KAAA,CAAM,KAAA,CAAM;AAAA,CAAI,CAAA,CAAG,CAC1C,IAAMS,CAAAA,CAAUJ,CAAAA,CAAK,OAAA,CAAQ,WAAA,CAAa,EAAE,CAAA,CAAE,OAAA,EAAQ,CACtD,GAAII,EAAQ,UAAA,CAAW,GAAG,CAAA,CAAG,MAE7BD,CAAAA,CAAM,IAAA,CAAKC,CAAO,EACtB,CAEA,OAAOD,CAAAA,CAAM,IAAA,CAAK,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAA,CAAQ,GAAG,CAAA,CAAE,IAAA,EAChD,CChDA,IAAME,CAAAA,CAAN,cAAoCrC,CAAmC,CAC1D,IAAA,CAAO,yBAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,KAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,2DAAA,CACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,UACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,YAAA,CAAcG,CAAAA,CAAQ,CAClB,OAAA,CAAS,sDAAA,CACT,GAAA,CAAK,iHAAA,CACL,GAAA,CAAK,2EACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,gBAAA,CAAiBO,EAAM,CACdD,CAAAA,CAAiBC,CAAI,CAAA,GACtBoB,CAAAA,CAAgB3B,CAAAA,CAAQ,UAAA,CAAYO,CAAAA,CAAK,MAAM,CAAA,EAEnDP,CAAAA,CAAQ,MAAA,CAAO,CAAE,IAAA,CAAMO,CAAAA,CAAK,EAAA,EAAMA,EAAM,SAAA,CAAW,cAAe,CAAC,CAAA,EACvE,CACJ,CACJ,CACJ,CAAA,CAEO8B,CAAAA,CAAQ,IAAID,CAAAA,CCxCnB,IAAME,CAAAA,CAAc,GAAA,CAOdC,CAAAA,CAAN,cAAwCxC,CAAmC,CAC9D,IAAA,CAAO,8BAAA,CAEP,cAAA,CAA0B,CAAC,CAAE,GAAA,CAAKuC,CAAY,CAAC,CAAA,CAE/C,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,8DACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,CACJ,CACI,IAAA,CAAM,QAAA,CACN,UAAA,CAAY,CACR,GAAA,CAAK,CAAE,IAAA,CAAM,SAAA,CAAW,QAAS,CAAE,CACvC,CAAA,CACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,QAAA,CAAU,CACN,OAAA,CAASpC,CAAAA,CAAQ,CACb,OAAA,CAAS,oFAAA,CACT,GAAA,CAAK,2JAAA,CACL,IAAK,qKACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAA8DC,CAAAA,CAAyC,CAC1G,IAAMuC,CAAAA,CAAMvC,CAAAA,CAAQ,CAAC,CAAA,EAAG,GAAA,EAAOqC,CAAAA,CAE/B,OAAO,CACH,OAAA,EAAU,CACN,IAAA,IAAWZ,CAAAA,IAAW1B,CAAAA,CAAQ,UAAA,CAAW,cAAA,GAAkB,CACvD,GAAI,CAACyB,CAAAA,CAAeC,CAAO,CAAA,CAAG,SAE9B,IAAMe,EAASR,CAAAA,CAAoBP,CAAO,CAAA,CAAE,MAAA,CACxCe,CAAAA,EAAUD,CAAAA,EAEdxC,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK0B,CAAAA,CAAQ,GAAA,CACb,SAAA,CAAW,SAAA,CACX,IAAA,CAAM,CAAE,OAAAe,CAAAA,CAAQ,GAAA,CAAAD,CAAI,CACxB,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOE,CAAAA,CAAQ,IAAIH,CAAAA,CCvDnB,IAAMI,CAAAA,CAAN,cAA+B5C,CAAmC,CACrD,IAAA,CAAO,oBAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,oFAAA,CACb,WAAA,CAAa,KACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,MAAOG,CAAAA,CAAQ,CACX,OAAA,CAAS,uCAAA,CACT,GAAA,CAAK,8FAAA,CACL,GAAA,CAAK,kGACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,kBAAA,CAAmBO,CAAAA,CAAM,CACjBA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,qBAAA,EAAyBA,CAAAA,CAAK,OAAO,IAAA,GAAS,OAAA,EAGnEA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAA,GAAS,wBAAA,GAE5BA,CAAAA,CAAK,EAAA,CAAG,IAAA,GAAS,YAAA,EAAgBA,CAAAA,CAAK,IAAA,EAAM,IAAA,GAAS,YAAA,EAEzDP,CAAAA,CAAQ,OAAO,CACX,IAAA,CAAAO,CAAAA,CACA,SAAA,CAAW,OAAA,CACX,IAAA,CAAM,CACF,IAAA,CAAMA,CAAAA,CAAK,EAAA,CAAG,IAAA,CACd,MAAA,CAAQA,CAAAA,CAAK,IAAA,CAAK,IACtB,CACJ,CAAC,CAAA,EACL,CACJ,CACJ,CACJ,CAAA,CAEOqC,CAAAA,CAAQ,IAAID,CAAAA,CCrDZ,IAAME,CAAAA,CAA8C,CAEvD,MAAA,CAAQ,OAAA,CACR,OAAA,CAAS,QAAA,CACT,QAAA,CAAU,SAAA,CACV,UAAW,UAAA,CACX,SAAA,CAAW,UAAA,CACX,UAAA,CAAY,WAAA,CACZ,SAAA,CAAW,UAAA,CACX,UAAA,CAAY,WAAA,CACZ,OAAA,CAAS,QAAA,CACT,QAAA,CAAU,SAAA,CACV,MAAA,CAAQ,OAAA,CACR,MAAA,CAAQ,QACR,SAAA,CAAW,UAAA,CAGX,SAAA,CAAW,WAAA,CACX,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CACb,aAAA,CAAe,eAAA,CACf,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CACb,YAAA,CAAc,cAAA,CACd,eAAgB,gBAAA,CAChB,SAAA,CAAW,WAAA,CACX,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CACb,aAAA,CAAe,eAAA,CACf,QAAA,CAAU,UAAA,CACV,SAAA,CAAW,WAAA,CACX,UAAA,CAAY,YAAA,CACZ,YAAA,CAAc,eACd,QAAA,CAAU,UAAA,CACV,SAAA,CAAW,WAAA,CACX,UAAA,CAAY,YAAA,CACZ,YAAA,CAAc,cAAA,CACd,UAAW,WAAA,CACX,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CACb,QAAA,CAAU,UAAA,CACV,SAAA,CAAW,YACX,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CACb,YAAA,CAAc,cAAA,CACd,aAAA,CAAe,eAAA,CACf,SAAA,CAAW,WAAA,CACX,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CACb,QAAA,CAAU,UAAA,CACV,UAAW,WAAA,CACX,UAAA,CAAY,YAAA,CACZ,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CACb,YAAA,CAAc,cAAA,CACd,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CAGb,OAAA,CAAS,SAAA,CACT,QAAA,CAAU,WACV,SAAA,CAAW,WAAA,CAGX,MAAA,CAAQ,QAAA,CACR,OAAA,CAAS,UAAA,CACT,OAAA,CAAS,SAAA,CACT,KAAA,CAAO,OAAA,CACP,KAAA,CAAO,OAAA,CAGP,OAAA,CAAS,SAAA,CACT,OAAA,CAAS,SAAA,CACT,QAAS,SAAA,CAGT,SAAA,CAAW,UAAA,CACX,UAAA,CAAY,WAAA,CACZ,QAAA,CAAU,SAAA,CACV,SAAA,CAAW,WACX,SAAA,CAAW,UAAA,CACX,SAAA,CAAW,UAAA,CAGX,IAAA,CAAM,MAAA,CACN,QAAA,CAAU,QAAA,CACV,UAAW,SACf,CAAA,CCnFO,SAASC,CAAAA,CACZC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACsB,CACtB,IAAMC,CAAAA,CAAqC,EAAC,CAE5C,IAAA,GAAW,CAACC,CAAAA,CAAKC,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQL,CAAI,CAAA,CAC1CG,CAAAA,CAAWC,CAAAA,CAAI,WAAA,EAAa,CAAA,CAAIC,CAAAA,CAGpC,IAAA,GAAW,CAACD,CAAAA,CAAKC,CAAK,CAAA,GAAK,MAAA,CAAO,QAAQJ,CAAK,CAAA,CAC3CE,CAAAA,CAAWC,CAAAA,CAAI,WAAA,EAAa,CAAA,CAAIC,CAAAA,CAGpC,IAAA,IAAWD,CAAAA,IAAOF,CAAAA,CACd,OAAOC,CAAAA,CAAWC,CAAAA,CAAI,WAAA,EAAa,EAGvC,OAAOD,CACX,CCNO,SAASG,CAAAA,CAAaC,CAAAA,CAAsB,CAC/C,IAAMC,EAAgB,EAAC,CAEvB,IAAA,IAAWC,CAAAA,IAASF,CAAAA,CAAK,QAAA,CAAS3D,CAAAA,CAAU,KAAA,CAAM,QAAQ,CAAA,CAClD6D,CAAAA,CAAM,KAAA,GAAU,MAAA,EAChBD,CAAAA,CAAM,IAAA,CAAK,CAAE,IAAA,CAAMC,CAAAA,CAAM,CAAC,CAAA,CAAG,KAAA,CAAOA,CAAAA,CAAM,KAAM,CAAC,CAAA,CAIzD,OAAOD,CACX,CAUO,SAASE,CAAAA,CAAUC,CAAAA,CAAgBC,CAAAA,CAA6B,CACnE,OAAID,CAAAA,GAAWA,CAAAA,CAAO,WAAA,EAAY,CACvBC,CAAAA,CAAY,WAAA,EAAY,CAG/BD,CAAAA,CAAO,OAAO,CAAC,CAAA,GAAMA,CAAAA,CAAO,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAY,CAC3CC,CAAAA,CAAY,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAY,CAAIA,CAAAA,CAAY,KAAA,CAAM,CAAC,CAAA,CAG7DA,CACX,CASO,SAASC,CAAAA,CAAWC,CAAAA,CAAmC,CAC1D,OAAOA,IAAS,MAAA,EAAalE,CAAAA,CAAU,KAAA,CAAM,SAAA,CAAU,IAAA,CAAKkE,CAAI,CACpE,CChDA,IAAMC,CAAAA,CAAN,cAA+B/D,CAAmC,CACrD,IAAA,CAAO,oBAAA,CAEP,cAAA,CAA0B,CAAC,CAAE,KAAA,CAAO,EAAC,CAAG,MAAA,CAAQ,EAAG,CAAC,EAEpD,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,iEAAA,CACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,OAAA,CAAS,MAAA,CACT,MAAA,CAAQ,CACJ,CACI,IAAA,CAAM,QAAA,CACN,UAAA,CAAY,CACR,KAAA,CAAO,CACH,IAAA,CAAM,QAAA,CACN,oBAAA,CAAsB,CAAE,IAAA,CAAM,QAAS,CAC3C,CAAA,CACA,MAAA,CAAQ,CACJ,IAAA,CAAM,OAAA,CACN,KAAA,CAAO,CAAE,IAAA,CAAM,QAAS,CAC5B,CACJ,EACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,QAAA,CAAU,CACN,OAAA,CAASG,CAAAA,CAAQ,CACb,OAAA,CAAS,sEAAA,CACT,GAAA,CAAK,8EAAA,CACL,GAAA,CAAK,4BACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAA8DC,CAAAA,CAAyC,CAC1G,IAAMiD,CAAAA,CAAaJ,EAAgBD,CAAAA,CAAqB5C,CAAAA,CAAQ,CAAC,CAAA,EAAG,KAAA,EAAS,EAAC,CAAGA,CAAAA,CAAQ,CAAC,CAAA,EAAG,MAAA,EAAU,EAAE,CAAA,CAEzG,OAAO,CACH,WAAWM,CAAAA,CAAM,CAGb,GAAI,EAAAA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,kBAAA,EAAsBA,CAAAA,CAAK,MAAA,CAAO,QAAA,GAAaA,CAAAA,EAAQ,CAACA,CAAAA,CAAK,MAAA,CAAO,QAAA,CAAA,CAI7F,QAAWwD,CAAAA,IAAQV,CAAAA,CAAa9C,CAAAA,CAAK,IAAI,CAAA,CAAG,CACxC,IAAMyD,CAAAA,CAAWd,EAAWa,CAAAA,CAAK,IAAA,CAAK,WAAA,EAAa,CAAA,CAC/CC,CAAAA,GAAa,MAAA,EAEjBhE,CAAAA,CAAQ,OAAO,CACX,IAAA,CAAAO,CAAAA,CACA,SAAA,CAAW,SAAA,CACX,IAAA,CAAM,CAAE,OAAA,CAASwD,CAAAA,CAAK,IAAA,CAAM,QAAA,CAAUN,CAAAA,CAAUM,CAAAA,CAAK,IAAA,CAAMC,CAAQ,CAAE,CACzE,CAAC,EACL,CACJ,CAAA,CACA,OAAA,EAAU,CACN,IAAA,IAAWtC,CAAAA,IAAW1B,CAAAA,CAAQ,UAAA,CAAW,cAAA,EAAe,CACpD,IAAA,IAAW+D,CAAAA,IAAQV,CAAAA,CAAa3B,CAAAA,CAAQ,KAAK,CAAA,CAAG,CAC5C,IAAMsC,CAAAA,CAAWd,CAAAA,CAAWa,CAAAA,CAAK,IAAA,CAAK,WAAA,EAAa,CAAA,CACnD,GAAIC,CAAAA,GAAa,MAAA,CAAW,SAE5B,IAAMC,CAAAA,CAAQR,EAAUM,CAAAA,CAAK,IAAA,CAAMC,CAAQ,CAAA,CAGrCE,CAAAA,CAAOxC,CAAAA,CAAQ,KAAA,CAAM,CAAC,EAAI,CAAA,CAAIqC,CAAAA,CAAK,KAAA,CACnCI,CAAAA,CAAKD,CAAAA,CAAOH,CAAAA,CAAK,IAAA,CAAK,MAAA,CAE5B/D,EAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAOA,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgBkE,CAAI,CAAA,CAC9C,GAAA,CAAKlE,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgBmE,CAAE,CAC9C,EACA,SAAA,CAAW,SAAA,CACX,IAAA,CAAM,CAAE,OAAA,CAASJ,CAAAA,CAAK,IAAA,CAAM,QAAA,CAAUE,CAAM,CAAA,CAC5C,GAAA,CAAKG,EAAAA,EAASA,EAAAA,CAAM,gBAAA,CAAiB,CAACF,CAAAA,CAAMC,CAAE,CAAA,CAAGF,CAAK,CAC1D,CAAC,EACL,CAER,CACJ,CACJ,CACJ,CAAA,CAEOI,EAAAA,CAAQ,IAAIP,CAAAA,CChGZ,SAASQ,EAAAA,CAAwBvC,CAAAA,CAAuB,CAC3D,IAAMI,CAAAA,CAAUJ,CAAAA,CAAK,OAAA,CAAQ,YAAA,CAAc,EAAE,CAAA,CAAE,OAAA,GAC/C,OAAII,CAAAA,CAAQ,MAAA,GAAW,CAAA,CAAU,KAAA,CAG7BxC,CAAAA,CAAU,QAAA,CAAS,WAAA,CAAY,KAAKwC,CAAO,CAAA,EAC3CxC,CAAAA,CAAU,QAAA,CAAS,cAAA,CAAe,IAAA,CAAKwC,CAAO,CAAA,EAC9CxC,CAAAA,CAAU,QAAA,CAAS,aAAA,CAAc,IAAA,CAAKwC,CAAO,CAErD,CCXA,SAASoC,GAAaC,CAAAA,CAAsB,CACxC,IAAMC,CAAAA,CAAaD,CAAAA,CAAK,OAAA,CAAQ,KAAA,CAAO,GAAG,CAAA,CACtCE,CAAAA,CAAU,GAAA,CAEd,IAAA,IAASC,CAAAA,CAAQ,CAAA,CAAGA,CAAAA,CAAQF,CAAAA,CAAW,OAAQE,CAAAA,EAAAA,CAAS,CACpD,IAAMd,CAAAA,CAAOY,CAAAA,CAAWE,CAAK,CAAA,CAC7B,GAAId,CAAAA,GAAS,MAAA,CAAW,MAEpBA,CAAAA,GAAS,GAAA,CACLY,CAAAA,CAAWE,CAAAA,CAAQ,CAAC,IAAM,GAAA,EAC1BD,CAAAA,EAAW,IAAA,CACXC,CAAAA,EAAAA,CAGIF,CAAAA,CAAWE,CAAAA,CAAQ,CAAC,CAAA,GAAM,KAAKA,CAAAA,EAAAA,EAEnCD,CAAAA,EAAW,OAAA,CAER,gBAAA,CAAiB,QAAA,CAASb,CAAI,CAAA,CACrCa,CAAAA,EAAW,KAAKb,CAAI,CAAA,CAAA,CAEpBa,CAAAA,EAAWb,EAEnB,CAEA,OAAO,IAAI,MAAA,CAAO,CAAA,EAAGa,CAAO,CAAA,CAAA,CAAG,CACnC,CASO,SAASE,EAAAA,CAAYC,CAAAA,CAAkBC,EAA6B,CACvE,IAAMC,CAAAA,CAAOF,CAAAA,CAAS,OAAA,CAAQ,KAAA,CAAO,GAAG,CAAA,CAExC,OAAOC,CAAAA,CAAS,IAAA,CAAKJ,CAAAA,EAAWH,EAAAA,CAAaG,CAAO,CAAA,CAAE,IAAA,CAAKK,CAAI,CAAC,CACpE,CC9BA,IAAMC,CAAAA,CAAN,cAA4CjF,CAAmC,CAClE,IAAA,CAAO,kCAAA,CAEP,cAAA,CAA0B,CAAC,CAAE,OAAA,CAAS,EAAG,CAAC,CAAA,CAE1C,IAAA,CAAO,CACZ,IAAA,CAAM,QAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,0FACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,CACJ,CACI,KAAM,QAAA,CACN,UAAA,CAAY,CACR,OAAA,CAAS,CACL,IAAA,CAAM,OAAA,CACN,KAAA,CAAO,CAAE,IAAA,CAAM,QAAS,CAC5B,CACJ,CAAA,CACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,QAAA,CAAU,CACN,UAAA,CAAYG,CAAAA,CAAQ,CAChB,OAAA,CAAS,2CAAA,CACT,IAAK,0GAAA,CACL,GAAA,CAAK,yFACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,EAA8DC,CAAAA,CAAyC,CAC1G,IAAMgF,CAAAA,CAAUhF,CAAAA,CAAQ,CAAC,CAAA,EAAG,OAAA,EAAW,EAAC,CACxC,OAAIgF,CAAAA,CAAQ,MAAA,CAAS,CAAA,EAAKL,EAAAA,CAAY5E,CAAAA,CAAQ,SAAUiF,CAAO,CAAA,CACpD,EAAC,CAGL,CACH,OAAA,EAAU,CACN,IAAA,IAAWvD,KAAW1B,CAAAA,CAAQ,UAAA,CAAW,cAAA,EAAe,CAAG,CACvD,IAAMkF,CAAAA,CAAQxD,CAAAA,CAAQ,MAAM,KAAA,CAAM;AAAA,CAAI,CAAA,CAEtC,IAAA,IAASiD,CAAAA,CAAQ,CAAA,CAAGA,CAAAA,CAAQO,EAAM,MAAA,CAAQP,CAAAA,EAAAA,CAAS,CAC/C,IAAM5C,CAAAA,CAAOmD,CAAAA,CAAMP,CAAK,CAAA,CACxB,GAAI5C,CAAAA,GAAS,MAAA,EAAa,CAACuC,EAAAA,CAAwBvC,CAAI,CAAA,CAAG,SAE1D,IAAMoD,CAAAA,CAAezD,CAAAA,CAAQ,GAAA,CAAI,MAAM,IAAA,CAAOiD,CAAAA,CACxCjB,CAAAA,CAAS1D,CAAAA,CAAQ,UAAA,CAAW,KAAA,CAAMmF,EAAe,CAAC,CAAA,EAAK,EAAA,CAE7DnF,CAAAA,CAAQ,MAAA,CAAO,CACX,IAAK,CACD,KAAA,CAAO,CAAE,IAAA,CAAMmF,CAAAA,CAAc,MAAA,CAAQ,CAAE,CAAA,CACvC,GAAA,CAAK,CAAE,IAAA,CAAMA,CAAAA,CAAc,MAAA,CAAQzB,CAAAA,CAAO,MAAO,CACrD,CAAA,CACA,SAAA,CAAW,YACf,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CACJ,CAAA,CAEO0B,EAAAA,CAAQ,IAAIJ,CAAAA,CCpEnB,IAAMK,CAAAA,CAAN,cAAuBtF,CAAmC,CAC7C,KAAO,YAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,KAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,iEAAA,CACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,OAAQG,CAAAA,CAAQ,CACZ,OAAA,CAAS,sCAAA,CACT,GAAA,CAAK,qGAAA,CACL,GAAA,CAAK,yFACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,IAAMsD,CAAAA,CAAOtD,CAAAA,CAAQ,UAAA,CAAW,OAAA,EAAQ,CAExC,OAAO,CACH,OAAA,EAAU,CAGN,IAAA,IAAS2E,CAAAA,CAAQ,CAAA,CAAGA,EAAQrB,CAAAA,CAAK,MAAA,CAAQqB,CAAAA,EAAAA,CACjCrB,CAAAA,CAAKqB,CAAK,CAAA,GAAMhF,EAAU,OAAA,EAE9BK,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,MAAOA,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB2E,CAAK,CAAA,CAC/C,GAAA,CAAK3E,EAAQ,UAAA,CAAW,eAAA,CAAgB2E,CAAAA,CAAQ,CAAC,CACrD,CAAA,CACA,UAAW,QACf,CAAC,EAET,CACJ,CACJ,CACJ,CAAA,CAEOW,EAAAA,CAAQ,IAAID,CAAAA,CC3CnB,IAAME,CAAAA,CAAN,cAAqCxF,CAAmC,CAC3D,IAAA,CAAO,4BAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,QAAA,CACN,OAAA,CAAS,MAAA,CACT,IAAA,CAAM,CACF,YAAa,wEAAA,CACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,GACR,QAAA,CAAU,CACN,cAAA,CAAgBG,CAAAA,CAAQ,CACpB,OAAA,CAAS,4CACT,GAAA,CAAK,sGAAA,CACL,GAAA,CAAK,uDACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,SAAU,CACN,IAAA,IAAW0B,CAAAA,IAAW1B,CAAAA,CAAQ,UAAA,CAAW,cAAA,EAAe,CACpD,GAAKyB,CAAAA,CAAeC,CAAO,CAAA,EAEvBA,CAAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,OAASA,CAAAA,CAAQ,GAAA,CAAI,GAAA,CAAI,IAAA,CAE/C,IAAA,IAASK,CAAAA,CAAOL,EAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAMK,CAAAA,EAAQL,CAAAA,CAAQ,GAAA,CAAI,IAAI,IAAA,CAAMK,CAAAA,EAAAA,CAAQ,CAC1E,IAAMuB,CAAAA,CAAOtD,CAAAA,CAAQ,WAAW,KAAA,CAAM+B,CAAAA,CAAO,CAAC,CAAA,CAC9C,GAAIuB,CAAAA,GAAS,QAAa,CAACxB,CAAAA,CAAiBwB,CAAI,CAAA,CAAG,SAGnD,IAAIkC,EAASzD,CAAAA,CACb,KACIyD,CAAAA,CAAS9D,CAAAA,CAAQ,GAAA,CAAI,GAAA,CAAI,MACzBI,CAAAA,CAAiB9B,CAAAA,CAAQ,UAAA,CAAW,KAAA,CAAMwF,CAAM,CAAA,EAAK,EAAE,CAAA,EAEvDA,CAAAA,EAAAA,CAIJ,IAAMC,CAAAA,CAAWzF,CAAAA,CAAQ,UAAA,CAAW,KAAA,CAAMwF,CAAM,CAAA,CAChD,GAAIC,CAAAA,GAAa,MAAA,EAAazD,CAAAA,CAAeyD,CAAQ,EAAG,CACpD,IAAMvB,CAAAA,CAAOlE,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB,CAAE,IAAA,CAAA+B,CAAAA,CAAM,MAAA,CAAQ,CAAE,CAAC,CAAA,CAC7DoC,EAAKnE,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB,CAAE,IAAA,CAAMwF,CAAAA,CAAS,EAAG,MAAA,CAAQ,CAAE,CAAC,CAAA,CAE7ExF,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAO,CAAE,IAAA,CAAA+B,CAAAA,CAAM,OAAQ,CAAE,CAAA,CACzB,GAAA,CAAK,CAAE,IAAA,CAAMyD,CAAAA,CAAQ,MAAA,CAAQlC,CAAAA,CAAK,MAAO,CAC7C,CAAA,CACA,SAAA,CAAW,gBAAA,CACX,GAAA,CAAKc,GAASA,CAAAA,CAAM,WAAA,CAAY,CAACF,CAAAA,CAAMC,CAAE,CAAC,CAC9C,CAAC,EACL,CAEApC,CAAAA,CAAOyD,EACX,CAER,CACJ,CACJ,CACJ,CAAA,CAEOE,EAAAA,CAAQ,IAAIH,CAAAA,CClEnB,IAAMI,CAAAA,CAAN,cAAkC5F,CAAmC,CACxD,IAAA,CAAO,wBAAA,CAEP,eAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,QAAA,CACN,QAAS,MAAA,CACT,IAAA,CAAM,CACF,WAAA,CAAa,8FAAA,CACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,MAAA,CAAQG,CAAAA,CAAQ,CACZ,OAAA,CAAS,sCAAA,CACT,GAAA,CAAK,wJAAA,CACL,GAAA,CAAK,+CACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,OAAA,EAAU,CACN,IAAA,IAAW0B,CAAAA,IAAW1B,EAAQ,UAAA,CAAW,cAAA,EAAe,CAAG,CACvD,GAAI0B,CAAAA,CAAQ,IAAA,GAAS,MAAA,CAAQ,SAG7B,IAAMkE,CAAAA,CAAalE,CAAAA,CAAQ,KAAA,CAAM,CAAC,EAAI,CAAA,CAEtC,IAAA,IAASiD,CAAAA,CAAQ,CAAA,CAAGA,CAAAA,CAAQjD,CAAAA,CAAQ,MAAM,MAAA,CAAQiD,CAAAA,EAAAA,CAAS,CACvD,GAAIjD,CAAAA,CAAQ,KAAA,CAAMiD,CAAK,CAAA,GAAM,GAAA,CAAK,SAGlC,GAAIjD,CAAAA,CAAQ,KAAA,CAAMiD,CAAAA,CAAQ,CAAC,CAAA,GAAM,GAAA,CAAK,CAClC,KAAOjD,CAAAA,CAAQ,KAAA,CAAMiD,EAAQ,CAAC,CAAA,GAAM,GAAA,EAAKA,CAAAA,EAAAA,CACzC,QACJ,CAIA,GAAIf,CAAAA,CAAWlC,CAAAA,CAAQ,KAAA,CAAMiD,CAAAA,CAAQ,CAAC,CAAC,EAAG,SAE1C,IAAMkB,CAAAA,CAAKD,CAAAA,CAAajB,CAAAA,CAExB3E,CAAAA,CAAQ,OAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAOA,CAAAA,CAAQ,UAAA,CAAW,gBAAgB6F,CAAE,CAAA,CAC5C,GAAA,CAAK7F,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB6F,EAAK,CAAC,CAClD,CAAA,CACA,SAAA,CAAW,QAAA,CACX,GAAA,CAAKzB,GAASA,CAAAA,CAAM,WAAA,CAAY,CAACyB,CAAAA,CAAIA,CAAAA,CAAK,CAAC,CAAC,CAChD,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOC,EAAAA,CAAQ,IAAIH,CAAAA,CClEZ,SAASI,CAAAA,CAAsBxF,EAAoC,CACtE,IAAIQ,CAAAA,CAA4BR,CAAAA,CAC5ByF,CAAAA,CAAkB,KAAA,CAEtB,OAAa,CACT,GAAIjF,CAAAA,CAAW,IAAA,GAAS,iBAAA,EAAqBA,CAAAA,CAAW,OAAS,qBAAA,CAAuB,CACpFA,CAAAA,CAAaA,CAAAA,CAAW,UAAA,CACxB,QACJ,CAEA,GAAIA,CAAAA,CAAW,IAAA,GAAS,kBAAA,CAAoB,CACxC,GAAIA,EAAW,QAAA,CAAU,OAAO,MAAA,CAEhCiF,CAAAA,CAAkB,IAAA,CAClBjF,CAAAA,CAAaA,EAAW,MAAA,CACxB,QACJ,CAEA,KACJ,CAEA,OAAOiF,CAAAA,GAAoBjF,CAAAA,CAAW,IAAA,GAAS,YAAA,EAAgBA,CAAAA,CAAW,IAAA,GAAS,gBAAA,CACvF,CCjBA,IAAMkF,CAAAA,CAAN,cAAoClG,CAAmC,CAC1D,IAAA,CAAO,0BAAA,CAEP,eAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,KAAM,CACF,WAAA,CACI,kGAAA,CACJ,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,oBAAqBG,CAAAA,CAAQ,CACzB,OAAA,CAAS,+DAAA,CACT,GAAA,CAAK,iGAAA,CACL,IAAK,mFACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,EAAqF,CACxF,OAAO,CACH,kBAAA,CAAmBO,CAAAA,CAAM,CACjBA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,qBAAA,EAAyBA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,OAAA,EAGnEA,EAAK,MAAA,CAAO,MAAA,CAAO,IAAA,GAAS,wBAAA,GAE5BA,CAAAA,CAAK,EAAA,CAAG,OAAS,YAAA,EAAgBA,CAAAA,CAAK,IAAA,GAAS,IAAA,EAC9CwF,CAAAA,CAAsBxF,CAAAA,CAAK,IAAI,CAAA,EAEpCP,CAAAA,CAAQ,MAAA,CAAO,CACX,IAAA,CAAAO,CAAAA,CACA,SAAA,CAAW,qBAAA,CACX,IAAA,CAAM,CACF,IAAA,CAAMA,CAAAA,CAAK,EAAA,CAAG,IAAA,CACd,WAAYP,CAAAA,CAAQ,UAAA,CAAW,OAAA,CAAQO,CAAAA,CAAK,IAAI,CACpD,CACJ,CAAC,CAAA,EACL,CACJ,CACJ,CACJ,CAAA,CAEO2F,GAAQ,IAAID,CAAAA,CC/CnB,IAAME,CAAAA,CAAN,cAAsCpG,CAAmC,CAC5D,IAAA,CAAO,2BAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,KAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,8FAAA,CACb,WAAA,CAAa,KACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,SAAU,CACN,WAAA,CAAaG,CAAAA,CAAQ,CACjB,OAAA,CAAS,mEAAA,CACT,IAAK,4KAAA,CACL,GAAA,CAAK,yEACT,CAAC,CACL,CACJ,EAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,kBAAA,CAAmBO,EAAM,CACjBA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,qBAAA,EAAyBA,CAAAA,CAAK,OAAO,IAAA,GAAS,OAAA,EACnEA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAA,GAAS,wBAAA,GAC5BA,CAAAA,CAAK,EAAA,CAAG,IAAA,GAAS,eAAA,EAAmBA,CAAAA,CAAK,IAAA,GAAS,IAAA,EAIlDA,EAAK,IAAA,CAAK,IAAA,GAAS,YAAA,EAAgB,CAACwF,CAAAA,CAAsBxF,CAAAA,CAAK,IAAI,CAAA,EAIlE6F,EAAAA,CAAe7F,CAAAA,CAAK,EAAE,CAAA,EAE3BP,CAAAA,CAAQ,OAAO,CACX,IAAA,CAAAO,CAAAA,CACA,SAAA,CAAW,aAAA,CACX,IAAA,CAAM,CAAE,MAAA,CAAQP,CAAAA,CAAQ,UAAA,CAAW,OAAA,CAAQO,CAAAA,CAAK,IAAI,CAAE,CAC1D,CAAC,CAAA,EACL,CACJ,CACJ,CACJ,EAQA,SAAS6F,EAAAA,CAAe1B,CAAAA,CAA0C,CAC9D,OAAIA,CAAAA,CAAQ,WAAW,MAAA,GAAW,CAAA,CAAU,KAAA,CAErCA,CAAAA,CAAQ,UAAA,CAAW,KAAA,CACtB2B,CAAAA,EACIA,CAAAA,CAAS,IAAA,GAAS,UAAA,EAClBA,CAAAA,CAAS,SAAA,EACT,CAACA,CAAAA,CAAS,UACVA,CAAAA,CAAS,KAAA,CAAM,IAAA,GAAS,YAChC,CACJ,CAEA,IAAOC,EAAAA,CAAQ,IAAIH,CAAAA,CC7DnB,IAAMI,CAAAA,CAAN,cAAgCxG,CAAmC,CACtD,IAAA,CAAO,sBAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,KAAO,CACZ,IAAA,CAAM,QAAA,CACN,OAAA,CAAS,MAAA,CACT,IAAA,CAAM,CACF,WAAA,CAAa,iFAAA,CACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,UAAA,CAAYG,CAAAA,CAAQ,CAChB,QAAS,iDAAA,CACT,GAAA,CAAK,oGAAA,CACL,GAAA,CAAK,wFACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,SAAU,CACN,IAAA,IAAW0B,CAAAA,IAAW1B,CAAAA,CAAQ,UAAA,CAAW,cAAA,GAAkB,CAGvD,GADI,CAACyB,CAAAA,CAAeC,CAAO,CAAA,EACvBA,EAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,GAASA,CAAAA,CAAQ,GAAA,CAAI,GAAA,CAAI,IAAA,CAAM,SAGrD,IAAMS,CAAAA,CAAUT,CAAAA,CAAQ,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAO,EAAE,CAAA,CAAE,IAAA,EAAK,CAIlDS,CAAAA,CAAQ,MAAA,GAAW,CAAA,EAEvBnC,EAAQ,MAAA,CAAO,CACX,GAAA,CAAK0B,CAAAA,CAAQ,GAAA,CACb,SAAA,CAAW,aACX,GAAA,CAAI0C,CAAAA,CAAO,CACP,IAAMoC,CAAAA,CAAS,GAAA,CAAI,MAAA,CAAO9E,CAAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA,CAC5C+E,CAAAA,CAAW,CAAA;AAAA,EAAQD,CAAM,MAAMrE,CAAO;AAAA,EAAKqE,CAAM,CAAA,GAAA,CAAA,CACvD,OAAOpC,CAAAA,CAAM,gBAAA,CAAiB1C,EAAQ,KAAA,CAAO+E,CAAQ,CACzD,CACJ,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOC,EAAAA,CAAQ,IAAIH,CAAAA,CC3DZ,IAAMI,EAAAA,CAA8C,CACvD,QAAA,CAAU,UAAA,CACV,KAAA,CAAO,OACX,EAOA,SAASC,EAAAA,CAAchF,CAAAA,CAAqD,CACxE,IAAMiF,CAAAA,CAAoB,EAAC,CAE3B,IAAA,IAAWlG,CAAAA,IAAaiB,CAAAA,CAAW,GAAA,CAAI,IAAA,CAC/BjB,CAAAA,CAAU,OAAS,mBAAA,EACnBkG,CAAAA,CAAQ,IAAA,CAAK,MAAA,CAAOlG,CAAAA,CAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAInD,OAAOkG,CACX,CASO,SAASC,EAAAA,CAAiBlF,EAA2CiD,CAAAA,CAAkC,CAC1G,IAAMkC,CAAAA,CAAW,IAAI,GAAA,CACfF,CAAAA,CAAUD,EAAAA,CAAchF,CAAU,CAAA,CAExC,OAAIiF,CAAAA,CAAQ,IAAA,CAAKnD,CAAAA,EAAUA,EAAO,UAAA,CAAW,YAAY,CAAA,EAAK/D,CAAAA,CAAU,UAAA,CAAW,cAAA,CAAe,IAAA,CAAK+D,CAAM,CAAC,CAAA,EAC1GqD,CAAAA,CAAS,GAAA,CAAI,UAAU,CAAA,CAAA,CAGNF,EAAQ,IAAA,CACzBnD,CAAAA,EAAUA,CAAAA,GAAW,OAAA,EAAWA,CAAAA,CAAO,UAAA,CAAW,QAAQ,CAAA,EAAKA,CAAAA,GAAW,WAC9E,CAAA,EACoB/D,CAAAA,CAAU,UAAA,CAAW,UAAA,CAAW,KAAKkF,CAAQ,CAAA,GAC7DkC,CAAAA,CAAS,GAAA,CAAI,OAAO,CAAA,CAGjBA,CACX,CCzCA,IAAMC,CAAAA,CAAN,cAAqCjH,CAAmC,CAC3D,IAAA,CAAO,2BAEP,cAAA,CAA0B,CAAC,CAAE,MAAA,CAAQ,EAAG,CAAC,CAAA,CAEzC,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,0EAAA,CACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,CACJ,CACI,IAAA,CAAM,QAAA,CACN,UAAA,CAAY,CACR,OAAQ,CACJ,IAAA,CAAM,OAAA,CACN,KAAA,CAAO,CACH,IAAA,CAAM,QAAA,CACN,IAAA,CAAM,CAAC,UAAA,CAAY,OAAO,CAC9B,CACJ,CACJ,EACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,QAAA,CAAU,CACN,aAAA,CAAeG,CAAAA,CAAQ,CACnB,OAAA,CAAS,qFAAA,CACT,GAAA,CAAK,qGAAA,CACL,GAAA,CAAK,oIACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAA8DC,CAAAA,CAAyC,CAC1G,IAAMgH,CAAAA,CAAU,IAAI,GAAA,CAAIhH,CAAAA,CAAQ,CAAC,GAAG,MAAA,EAAU,EAAE,CAAA,CAG1CiH,CAAAA,CAAWlH,CAAAA,CAAQ,QAAA,CAASL,CAAAA,CAAU,WAAW,CAAA,EAAK,EAAC,CAE7D,OAAO,CACH,QAAQY,CAAAA,CAAM,CACV,IAAMwG,CAAAA,CAAWD,EAAAA,CAAiB9G,CAAAA,CAAQ,UAAA,CAAYA,CAAAA,CAAQ,QAAQ,CAAA,CAEtE,IAAA,IAAWmH,CAAAA,IAAaJ,CAAAA,CAChBE,CAAAA,CAAQ,IAAIE,CAAS,CAAA,EAAKD,CAAAA,CAAQC,CAAS,CAAA,EAE/CnH,CAAAA,CAAQ,MAAA,CAAO,CACX,IAAA,CAAAO,CAAAA,CACA,SAAA,CAAW,eAAA,CACX,IAAA,CAAM,CAAE,UAAWoG,EAAAA,CAAiBQ,CAAS,CAAA,CAAG,MAAA,CAAQA,CAAU,CACtE,CAAC,EAET,CACJ,CACJ,CACJ,CAAA,CAEOC,EAAAA,CAAQ,IAAIJ,CAAAA,CC7DZ,SAASK,EAAAA,CAAoBC,CAAAA,CAAiC,CACjE,IAAI/G,CAAAA,CAAsB+G,CAAAA,CAE1B,OAAI/G,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,oBAAA,EAAwBA,CAAAA,CAAK,OAAO,MAAA,CAAO,IAAA,GAAS,qBAAA,GACzEA,CAAAA,CAAOA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAA,CAAA,CAGnBA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,wBAAA,EAA4BA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,8BACtEA,CAAAA,CAAOA,CAAAA,CAAK,MAAA,CAAA,CAGTA,CACX,CAOO,SAASgH,EAAAA,CAAWhH,CAAAA,CAA8B,CACrD,OAAOA,CAAAA,CAAK,MAAA,EAAQ,IAAA,GAAS,SACjC,CAQO,SAASiH,EAAAA,CAAgBF,CAAAA,CAAsC,CAClE,GAAA,CAAKA,CAAAA,CAAG,IAAA,GAAS,qBAAA,EAAyBA,CAAAA,CAAG,IAAA,GAAS,oBAAA,GAAyBA,CAAAA,CAAG,EAAA,CAC9E,OAAOA,EAAG,EAAA,CAAG,IAAA,CAGjB,GAAIA,CAAAA,CAAG,MAAA,CAAO,IAAA,GAAS,oBAAA,EAAwBA,CAAAA,CAAG,MAAA,CAAO,EAAA,CAAG,IAAA,GAAS,YAAA,CACjE,OAAOA,CAAAA,CAAG,OAAO,EAAA,CAAG,IAI5B,CChDA,IAAMG,EAAAA,CAAsB,IAAI,GAAA,CAAY,CAAC,qBAAA,CAAuB,oBAAA,CAAsB,yBAAyB,CAAC,CAAA,CAa7G,SAASC,GAAqB5H,CAAAA,CAAuB,CACxD,OAAO,QAAA,CAAS,IAAA,CAAKA,CAAI,CAC7B,CAQO,SAAS6H,CAAAA,CAAgBpH,CAAAA,CAAuD,CACnF,GAAI,CAACA,EAAM,OAAO,MAAA,CAElB,OAAQA,CAAAA,CAAK,IAAA,EACT,KAAK,YAAA,CACL,KAAK,aAAA,CACD,OAAO,KAAA,CACX,KAAK,uBAAA,CACD,OAAOoH,CAAAA,CAAgBpH,CAAAA,CAAK,UAAU,CAAA,EAAKoH,CAAAA,CAAgBpH,CAAAA,CAAK,SAAS,CAAA,CAC7E,KAAK,mBAAA,CACD,OAAOoH,CAAAA,CAAgBpH,CAAAA,CAAK,IAAI,GAAKoH,CAAAA,CAAgBpH,CAAAA,CAAK,KAAK,CAAA,CACnE,KAAK,oBAAA,CACD,OAAOoH,CAAAA,CAAgBpH,CAAAA,CAAK,WAAA,CAAY,EAAA,CAAG,EAAE,CAAC,CAAA,CAClD,QACI,OAAO,MACf,CACJ,CAQA,SAASqH,EAAAA,CAAkBrH,CAAAA,CAAqBsH,CAAAA,CAAmC,CAC/E,GAAItH,CAAAA,CAAK,IAAA,GAAS,iBAAA,CACd,OAAOoH,EAAgBpH,CAAAA,CAAK,QAAQ,CAAA,CAGxC,IAAA,IAAW4C,CAAAA,IAAO0E,CAAAA,CAAYtH,CAAAA,CAAK,IAAI,CAAA,EAAK,EAAC,CAAG,CAC5C,IAAM6C,CAAAA,CAAS7C,EAA4C4C,CAAG,CAAA,CACxD2E,CAAAA,CAAW,KAAA,CAAM,OAAA,CAAQ1E,CAAK,CAAA,CAAIA,CAAAA,CAAQ,CAACA,CAAK,CAAA,CAEtD,IAAA,IAAW2E,CAAAA,IAASD,CAAAA,CAAU,CAC1B,IAAME,CAAAA,CAAYD,CAAAA,CAClB,GAAI,EAAA,CAACC,CAAAA,EAAa,OAAOA,CAAAA,CAAU,IAAA,EAAS,QAAA,CAAA,EAGxC,CAAAP,EAAAA,CAAoB,GAAA,CAAIO,CAAAA,CAAU,IAAI,CAAA,EACtCJ,EAAAA,CAAkBI,CAAAA,CAAWH,CAAW,CAAA,CAAG,OAAO,KAC1D,CACJ,CAEA,OAAO,MACX,CASO,SAASI,EAAAA,CACZX,EACAO,CAAAA,CACO,CAEP,OAAIP,CAAAA,CAAG,IAAA,GAAS,yBAAA,EAA6BA,EAAG,IAAA,CAAK,IAAA,GAAS,gBAAA,CACnDK,CAAAA,CAAgBL,CAAAA,CAAG,IAAI,EAG3BM,EAAAA,CAAkBN,CAAAA,CAAG,IAAA,CAAMO,CAAW,CACjD,CC5EA,IAAMK,CAAAA,CAAN,cAAmCnI,CAAmC,CACzD,IAAA,CAAO,wBAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,mFAAA,CACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,GACR,QAAA,CAAU,CACN,YAAA,CAAcG,CAAAA,CAAQ,CAClB,OAAA,CAAS,+CAAA,CACT,GAAA,CAAK,kIAAA,CACL,GAAA,CAAK,wFACT,CAAC,CACL,CACJ,EAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,IAAMmI,CAAAA,CAAQ,CAACb,CAAAA,CAAkBc,CAAAA,GAAoC,CACjE,IAAMtI,CAAAA,CAAO0H,EAAAA,CAAgBF,CAAE,CAAA,CAE/B,GAAIxH,CAAAA,GAAS,MAAA,CAAW,OAExB,IAAMuI,CAAAA,CAAehB,EAAAA,CAAoBC,CAAE,CAAA,CACtCC,EAAAA,CAAWc,CAAY,CAAA,GAGxBX,EAAAA,CAAqB5H,CAAI,CAAA,EAAKmI,GAAmBX,CAAAA,CAAItH,CAAAA,CAAQ,UAAA,CAAW,WAAW,CAAA,EAEnF2B,CAAAA,CAAgB3B,CAAAA,CAAQ,UAAA,CAAYqI,CAAY,CAAA,EAEpDrI,CAAAA,CAAQ,MAAA,CAAO,CACX,IAAA,CAAMoI,EACN,SAAA,CAAW,cAAA,CACX,IAAA,CAAM,CAAE,IAAA,CAAAtI,CAAK,CACjB,CAAC,CAAA,EACL,CAAA,CAEA,OAAO,CACH,mBAAA,CAAoBS,CAAAA,CAAM,CACtB4H,CAAAA,CAAM5H,CAAAA,CAAMA,CAAAA,CAAK,EAAA,EAAMA,CAAI,EAC/B,EACA,kBAAA,CAAmBA,CAAAA,CAAM,CAChBA,CAAAA,CAAK,IAAA,GACNA,CAAAA,CAAK,KAAK,IAAA,GAAS,yBAAA,EAA6BA,CAAAA,CAAK,IAAA,CAAK,IAAA,GAAS,oBAAA,EAEvE4H,CAAAA,CAAM5H,CAAAA,CAAK,IAAA,CAAMA,CAAAA,CAAK,EAAE,CAAA,EAC5B,CACJ,CACJ,CACJ,CAAA,CAEO+H,EAAAA,CAAQ,IAAIJ,CAAAA,CClDnB,IAAMK,EAAAA,CAAgB,CAClB/G,CAAAA,CACAa,CAAAA,CACAK,CAAAA,CACAE,CAAAA,CACAyB,EAAAA,CACAe,EAAAA,CACAE,EAAAA,CACAI,GACAI,EAAAA,CACAI,EAAAA,CACAI,EAAAA,CACAI,EAAAA,CACAU,EAAAA,CACAkB,EACJ,CAAA,CAKaE,CAAAA,CAAQ,MAAA,CAAO,WAAA,CAAYD,EAAAA,CAAc,GAAA,CAAIE,CAAAA,EAAQ,CAACA,EAAK,IAAA,CAAMA,CAAAA,CAAK,YAAA,EAAc,CAAC,CAAC,CAAA,CC9B5F,SAASC,CAAAA,CAAcpH,CAAAA,CAAmD,CAC7E,IAAM4F,CAAAA,CAAqC,GAE3C,IAAA,GAAW,CAACpH,CAAAA,CAAM2I,CAAI,CAAA,GAAK,MAAA,CAAO,OAAA,CAAQD,CAAK,CAAA,CAAA,CACtCC,CAAAA,CAAK,IAAA,CAAK,IAAA,EAAM,QAAA,EAAY,MAAA,IAAYnH,IACzC4F,CAAAA,CAAQ,CAAA,EAAGvH,CAAAA,CAAU,WAAW,CAAA,CAAA,EAAIG,CAAI,CAAA,CAAE,CAAA,CAAI,MAAA,CAAA,CAItD,OAAOoH,CACX,CAMO,SAASyB,EAAAA,EAAsC,CAClD,IAAMzB,CAAAA,CAAqC,EAAC,CAE5C,IAAA,IAAWpH,CAAAA,IAAQ,MAAA,CAAO,IAAA,CAAK0I,CAAK,CAAA,CAChCtB,CAAAA,CAAQ,CAAA,EAAGvH,CAAAA,CAAU,WAAW,IAAIG,CAAI,CAAA,CAAE,CAAA,CAAI,MAAA,CAGlD,OAAOoH,CACX,CCxBO,SAAS0B,EAAAA,CAAIC,CAAAA,CAAgE,CAChF,OAAO,CACH,KAAM,CAAA,EAAGlJ,CAAAA,CAAU,WAAW,CAAA,IAAA,CAAA,CAC9B,OAAA,CAAS,CAAE,CAACA,CAAAA,CAAU,WAAW,EAAGkJ,CAAO,CAAA,CAC3C,QAAA,CAAU,CAAE,CAAClJ,CAAAA,CAAU,WAAW,EAAG,CAAE,QAAA,CAAU,IAAA,CAAM,KAAA,CAAO,IAAK,CAAE,CAAA,CACrE,KAAA,CAAOgJ,EAAAA,EACX,CACJ,CCRO,SAAS5F,CAAAA,CAAK8F,CAAAA,CAAgE,CACjF,OAAO,CACH,IAAA,CAAM,CAAA,EAAGlJ,CAAAA,CAAU,WAAW,CAAA,KAAA,CAAA,CAC9B,OAAA,CAAS,CAAE,CAACA,EAAU,WAAW,EAAGkJ,CAAO,CAAA,CAC3C,KAAA,CAAOH,CAAAA,CAAc,MAAM,CAC/B,CACJ,CCNO,SAASI,EAAAA,CAAYD,CAAAA,CAAgE,CACxF,OAAO,CACH,GAAG9F,CAAAA,CAAK8F,CAAM,CAAA,CACd,IAAA,CAAM,CAAA,EAAGlJ,CAAAA,CAAU,WAAW,CAAA,YAAA,CAClC,CACJ,CCVA,IAAMoJ,EAAAA,CAAmB,CAAC,oBAAA,CAAsB,yBAAyB,CAAA,CASlE,SAASC,EAAAA,CAASH,CAAAA,CAAgE,CACrF,OAAO,CACH,IAAA,CAAM,CAAA,EAAGlJ,CAAAA,CAAU,WAAW,CAAA,SAAA,CAAA,CAC9B,QAAS,CAAE,CAACA,CAAAA,CAAU,WAAW,EAAGkJ,CAAO,CAAA,CAC3C,QAAA,CAAU,CAAE,CAAClJ,CAAAA,CAAU,WAAW,EAAG,CAAE,SAAU,IAAK,CAAE,CAAA,CACxD,KAAA,CAAO,CACH,GAAG+I,CAAAA,CAAc,UAAU,CAAA,CAC3B,CAAC,CAAA,EAAG/I,CAAAA,CAAU,WAAW,CAAA,iCAAA,CAAmC,EAAG,CAAC,MAAA,CAAQ,CAAE,OAAA,CAASoJ,EAAiB,CAAC,CACzG,CACJ,CACJ,CCdO,SAASE,EAAAA,CAAMJ,CAAAA,CAAgE,CAClF,OAAO,CACH,IAAA,CAAM,CAAA,EAAGlJ,CAAAA,CAAU,WAAW,CAAA,MAAA,CAAA,CAC9B,OAAA,CAAS,CAAE,CAACA,CAAAA,CAAU,WAAW,EAAGkJ,CAAO,CAAA,CAC3C,SAAU,CAAE,CAAClJ,CAAAA,CAAU,WAAW,EAAG,CAAE,KAAA,CAAO,IAAK,CAAE,CAAA,CACrD,KAAA,CAAO+I,CAAAA,CAAc,OAAO,CAChC,CACJ,CCFO,SAASQ,EAAAA,CAAaL,CAAAA,CAAgF,CACzG,OAAO,CACH,IAAA,CAAM9F,CAAAA,CAAK8F,CAAM,CAAA,CACjB,WAAA,CAAaC,EAAAA,CAAYD,CAAM,EAC/B,QAAA,CAAUG,EAAAA,CAASH,CAAM,CAAA,CACzB,KAAA,CAAOI,EAAAA,CAAMJ,CAAM,CAAA,CACnB,GAAA,CAAKD,EAAAA,CAAIC,CAAM,CACnB,CACJ,CCpBE,IAAAM,EAAAA,CAAW,OAAA,CCQb,IAAMN,CAAAA,CAAqC,CACvC,IAAA,CAAM,CACF,IAAA,CAAM,CAAA,cAAA,EAAiBlJ,CAAAA,CAAU,WAAW,CAAA,CAAA,CAC5C,OAAA,CAAAwJ,EACJ,EACA,KAAA,CAAAX,CAAAA,CACA,OAAA,CAAS,EACb,CAAA,CAGAK,CAAAA,CAAO,OAAA,CAAUK,EAAAA,CAAaL,CAAM,CAAA,CAEpC,IAAOO,EAAAA,CAAQP","file":"index.js","sourcesContent":["/**\n * The global set of constants shared across the plugin, grouped by domain.\n */\nconst CONSTANTS = {\n /**\n * The short name the plugin is registered under inside an ESLint config,\n * e.g. `nitpicker/no-em-dash`.\n */\n PLUGIN_NAME: \"nitpicker\",\n\n /**\n * The base URL of the plugin's repository.\n */\n REPO_URL: \"https://github.com/the-alien-club/eslint-plugin-nitpicker\",\n\n /**\n * The em dash character (U+2014), e.g. \"—\".\n */\n EM_DASH: \"—\",\n\n /**\n * Constants for scanning comments.\n */\n COMMENTS: {\n /**\n * Box-drawing and block-element characters, which are always decorative\n * when found inside a comment.\n */\n BOX_DRAWING: /[─-▟]/,\n\n /**\n * A comment line made entirely of three or more repeated separator\n * characters, e.g. `======` or `------`.\n */\n PURE_SEPARATOR: /^[-=~*#_+]{3,}$/,\n\n /**\n * A short label fenced by separator runs inside a comment, e.g `-- Section --`.\n */\n WRAPPED_LABEL: /^[-=~*#_+]{2,}\\s.*\\s[-=~*#_+]{2,}$/,\n },\n\n /**\n * Constants for splitting and inspecting words.\n */\n WORDS: {\n /**\n * Matches a single \"word\" character, i.e. anything that can appear inside\n * an identifier or a number (letters, digits, underscore and dollar).\n */\n WORD_CHAR: /[\\p{L}\\p{N}_$]/u,\n\n /**\n * Matches a single sub-word: an all-caps acronym, a capitalized word, or a\n * lowercase run, so `getUserName` splits into \"get\", \"User\" and \"Name\"\n */\n SUB_WORD: /[A-Z]+(?![a-z])|[A-Z][a-z]+|[a-z]+/g,\n },\n\n /**\n * Constants for detecting framework usage.\n */\n FRAMEWORKS: {\n /**\n * AdonisJS subpath import roots (`#models/...`, `#controllers/...`, etc.).\n */\n ADONIS_SUBPATH:\n /^#(models|controllers|services|middleware|validators|policies|config|start|database|providers|lib)\\b/,\n\n /**\n * React source files by extension.\n */\n REACT_FILE: /\\.[jt]sx$/,\n },\n\n /**\n * Constants for AdonisJS migrations.\n */\n MIGRATIONS: {\n /**\n * Table-builder methods that declare an index or a constraint.\n */\n INDEX_METHODS: new Set([\"index\", \"unique\", \"primary\", \"foreign\"]),\n\n /**\n * Table-builder methods that declare a timestamp column.\n */\n TIMESTAMP_METHODS: new Set([\"timestamp\", \"dateTime\", \"datetime\"]),\n\n /**\n * Audit timestamp column names that form a migration's dedicated\n * timestamps group.\n */\n AUDIT_TIMESTAMPS: new Set([\"created_at\", \"updated_at\", \"deleted_at\"]),\n\n /**\n * The order table statements must be grouped in: columns first, then\n * timestamps, then indexes and constraints.\n */\n CATEGORY_ORDER: [\"column\", \"timestamp\", \"index\"],\n },\n} as const\n\nexport default CONSTANTS\n","import { ESLintUtils } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * The category a rule belongs to, which decides the shared config it ships in.\n */\nexport type RuleCategory = \"base\" | \"adonisjs\" | \"react\"\n\n/**\n * Extra metadata attached to every Nitpicker rule under `meta.docs`.\n */\nexport type NitpickerRuleDocs = {\n /**\n * A short, human-readable description of what the rule enforces.\n */\n description: string\n\n /**\n * Whether the rule is part of the `recommended` shared config.\n */\n recommended?: boolean\n\n /**\n * The category the rule belongs to, defaults to `base` when omitted.\n */\n category?: RuleCategory\n}\n\n/**\n * The shared rule factory for the whole plugin.\n */\nexport const createRule = ESLintUtils.RuleCreator<NitpickerRuleDocs>(\n name => `${CONSTANTS.REPO_URL}/blob/main/docs/rules/${name}.md`,\n)\n","import { ESLintUtils, type TSESLint } from \"@typescript-eslint/utils\"\nimport { createRule, type NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\n/**\n * The base class every Nitpicker rule extends, so a rule only declares its name,\n * metadata, options, and visitor logic. Call {@link toRuleModule} to turn an\n * instance into the plain object ESLint expects.\n */\nexport abstract class NitpickerRule<MessageIds extends string = string, Options extends readonly unknown[] = []> {\n /**\n * The kebab-case name of the rule, without the plugin prefix\n * (e.g. `no-em-dash`).\n */\n abstract readonly name: string\n\n /**\n * The ESLint metadata describing the rule (type, docs, schema, messages).\n */\n abstract readonly meta: ESLintUtils.NamedCreateRuleMeta<MessageIds, NitpickerRuleDocs, Options>\n\n /**\n * The options applied when the rule is enabled without an explicit config.\n */\n abstract readonly defaultOptions: Options\n\n /**\n * The visitor factory ESLint calls for every linted file.\n * @param context The rule context for the current file.\n * @param options The user options merged with {@link defaultOptions}.\n * @returns The AST visitor listeners.\n */\n abstract create(\n context: Readonly<TSESLint.RuleContext<MessageIds, Options>>,\n options: Readonly<Options>,\n ): TSESLint.RuleListener\n\n /**\n * Builds the ESLint-compatible rule module from this instance.\n * @returns The plain rule module object consumed by ESLint.\n */\n toRuleModule(): TSESLint.RuleModule<MessageIds, Options, NitpickerRuleDocs> {\n return createRule<Options, MessageIds>({\n name: this.name,\n meta: this.meta,\n defaultOptions: this.defaultOptions,\n create: (context, options) => this.create(context, options),\n })\n }\n}\n","/**\n * The building blocks of a Nitpicker message.\n */\nexport type Nitpick = {\n /**\n * What is wrong, stated plainly, may contain ESLint `{{placeholders}}`.\n */\n problem: string\n\n /**\n * Why it is worth fixing, so the reader understands the intent.\n */\n why: string\n\n /**\n * A concrete, actionable instruction describing how to fix it.\n */\n fix: string\n}\n\n/**\n * Composes a {@link Nitpick} into one message string for a rule's\n * `meta.messages` entry, leaving any ESLint `{{placeholders}}` intact.\n * @param nitpick The problem/why/fix triplet to format.\n * @returns The formatted, multi-line message.\n */\nexport function nitpick({ problem, why, fix }: Nitpick): string {\n return `${problem}\\n - why: ${why}\\n - fix: ${fix}`\n}\n","import type { TSESTree } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * A category a `createTable` builder statement falls into, used to keep a\n * migration's columns, timestamps, and indexes grouped in that order.\n */\nexport type TableCategory = \"column\" | \"timestamp\" | \"index\"\n\n/**\n * Checks whether a class is an AdonisJS migration, i.e. a default-exported class\n * that extends `BaseSchema`.\n * @param node The class declaration to inspect.\n * @returns `true` if the class is a migration.\n */\nexport function isMigrationClass(node: TSESTree.ClassDeclaration): boolean {\n return (\n node.parent.type === \"ExportDefaultDeclaration\" &&\n node.superClass?.type === \"Identifier\" &&\n node.superClass.name === \"BaseSchema\"\n )\n}\n\n/**\n * Resolves the `this.schema.createTable(name, builder => { ... })` builder body\n * from a call expression, if the call is one.\n * @param node The call expression to inspect.\n * @returns The builder statements and parameter name, or `null`.\n */\nexport function getCreateTableBuilder(node: TSESTree.CallExpression): {\n body: TSESTree.Statement[]\n builderName: string\n} | null {\n if (node.callee.type !== \"MemberExpression\" || node.callee.property.type !== \"Identifier\") return null\n if (node.callee.property.name !== \"createTable\") return null\n\n // Require a schema receiver so only Lucid migration calls match\n if (node.callee.object.type !== \"MemberExpression\" || node.callee.object.property.type !== \"Identifier\") return null\n if (node.callee.object.property.name !== \"schema\") return null\n\n const callback = node.arguments.at(-1)\n if (callback?.type !== \"ArrowFunctionExpression\" && callback?.type !== \"FunctionExpression\") return null\n if (callback.body.type !== \"BlockStatement\" || callback.params[0]?.type !== \"Identifier\") return null\n\n return { body: callback.body.body, builderName: callback.params[0].name }\n}\n\n/**\n * Resolves the category of a single `createTable` builder statement.\n * @param statement The statement to categorize.\n * @param builderName The name of the table builder parameter.\n * @returns The category, or `null` if the statement is not a builder call.\n */\nexport function getTableStatementCategory(statement: TSESTree.Statement, builderName: string): TableCategory | null {\n if (statement.type !== \"ExpressionStatement\") return null\n\n const root = rootBuilderCall(statement.expression, builderName)\n if (root === null) return null\n\n if (CONSTANTS.MIGRATIONS.INDEX_METHODS.has(root.method)) return \"index\"\n if (root.method === \"timestamps\") return \"timestamp\"\n if (\n CONSTANTS.MIGRATIONS.TIMESTAMP_METHODS.has(root.method) &&\n root.firstArgument !== undefined &&\n CONSTANTS.MIGRATIONS.AUDIT_TIMESTAMPS.has(root.firstArgument)\n ) {\n return \"timestamp\"\n }\n\n return \"column\"\n}\n\n/**\n * Walks a chained builder expression down to the first call on the builder, e.g.\n * `table.integer(\"x\").notNullable()` resolves to `integer` with argument `\"x\"`.\n * @param expression The (possibly chained) expression to walk.\n * @param builderName The name of the table builder parameter.\n * @returns The base method and its first string argument, or `null`.\n */\nfunction rootBuilderCall(\n expression: TSESTree.Expression,\n builderName: string,\n): { method: string; firstArgument: string | undefined } | null {\n let current: TSESTree.Node = expression\n\n while (current.type === \"CallExpression\" && current.callee.type === \"MemberExpression\") {\n if (current.callee.object.type === \"Identifier\" && current.callee.object.name === builderName) {\n if (current.callee.property.type !== \"Identifier\") return null\n\n const firstArgument = current.arguments[0]\n const literal =\n firstArgument?.type === \"Literal\" && typeof firstArgument.value === \"string\"\n ? firstArgument.value\n : undefined\n\n return { method: current.callee.property.name, firstArgument: literal }\n }\n\n current = current.callee.object\n }\n\n return null\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport { getCreateTableBuilder, getTableStatementCategory } from \"@/lib/utils/migrations\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"outOfOrder\"\n\n/**\n * Enforces that a migration's `createTable` statements stay grouped in order:\n * columns, then audit timestamps, then indexes and constraints, this keeps every\n * migration structured the same way without needing section-label comments.\n */\nclass MigrationTableOrder extends NitpickerRule<MessageIds, Options> {\n readonly name = \"migration-table-order\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Group migration table statements as columns, then timestamps, then indexes and constraints.\",\n recommended: true,\n category: \"adonisjs\",\n },\n schema: [],\n messages: {\n outOfOrder: nitpick({\n problem: \"This {{category}} is out of order in the table definition.\",\n why: \"A migration reads consistently when columns come first, then timestamps, then indexes and constraints, each grouped together\",\n fix: \"Move it into its group so the order stays columns, timestamps, then indexes and constraints\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n return {\n CallExpression(node) {\n const builder = getCreateTableBuilder(node)\n if (builder === null) return\n\n let maxRank = 0\n\n for (const statement of builder.body) {\n const category = getTableStatementCategory(statement, builder.builderName)\n if (category === null) continue\n\n const rank = CONSTANTS.MIGRATIONS.CATEGORY_ORDER.indexOf(category)\n if (rank < maxRank) {\n context.report({ node: statement, messageId: \"outOfOrder\", data: { category } })\n }\n\n maxRank = Math.max(maxRank, rank)\n }\n },\n }\n }\n}\n\nexport default new MigrationTableOrder()\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Checks whether a comment is a JSDoc comment, i.e. a block comment that opens\n * with `/**`.\n * @param comment The comment to test.\n * @returns `true` if the comment is a JSDoc block comment.\n */\nexport function isJSDocComment(comment: TSESTree.Comment): boolean {\n return comment.type === \"Block\" && comment.value.startsWith(\"*\")\n}\n\n/**\n * Checks whether a node is immediately preceded by a JSDoc comment.\n * @param sourceCode The source code of the linted file.\n * @param node The node to inspect the leading comments of.\n * @returns `true` if the comment right before the node is a JSDoc comment.\n */\nexport function hasLeadingJSDoc(sourceCode: Readonly<TSESLint.SourceCode>, node: TSESTree.Node): boolean {\n const commentsBefore = sourceCode.getCommentsBefore(node)\n const closest = commentsBefore.at(-1)\n\n return closest !== undefined && isJSDocComment(closest)\n}\n\n/**\n * Checks whether a physical JSDoc line is blank, i.e. just a ` * ` with no\n * content after it.\n * @param line The physical source line to test.\n * @returns `true` if the line is an empty JSDoc line.\n */\nexport function isBlankJSDocLine(line: string): boolean {\n return /^\\s*\\*\\s*$/.test(line)\n}\n\n/**\n * Checks whether a physical JSDoc line holds a block tag, i.e. a ` * ` followed\n * by an `@tag` such as `@param` or `@returns`.\n * @param line The physical source line to test.\n * @returns `true` if the line starts a JSDoc tag.\n */\nexport function isJSDocTagLine(line: string): boolean {\n return /^\\s*\\*\\s*@/.test(line)\n}\n\n/**\n * Extracts the description prose of a JSDoc comment, i.e. everything before the\n * first block tag, with the ` * ` markers stripped and wrapped lines joined into\n * a single space-separated string.\n * @param comment The JSDoc comment to read.\n * @returns The description as one collapsed prose string.\n */\nexport function getJSDocDescription(comment: TSESTree.Comment): string {\n const parts: string[] = []\n\n for (const line of comment.value.split(\"\\n\")) {\n const content = line.replace(/^\\s*\\*? ?/, \"\").trimEnd()\n if (content.startsWith(\"@\")) break\n\n parts.push(content)\n }\n\n return parts.join(\" \").replace(/\\s+/g, \" \").trim()\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { hasLeadingJSDoc } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport { isMigrationClass } from \"@/lib/utils/migrations\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"missingJSDoc\"\n\n/**\n * Requires a JSDoc comment above an AdonisJS migration (a default-exported class\n * extending `BaseSchema`) so its intent is documented, the timestamped filename\n * alone does not convey what the migration changes.\n */\nclass RequireMigrationJSDoc extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-migration-jsdoc\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Require a JSDoc comment describing an AdonisJS migration.\",\n recommended: true,\n category: \"adonisjs\",\n },\n schema: [],\n messages: {\n missingJSDoc: nitpick({\n problem: \"This migration has no JSDoc describing what it does.\",\n why: \"A migration's intent should be readable at a glance, the timestamped filename does not convey the schema change\",\n fix: \"Add a `/** ... */` JSDoc above the migration class summarizing the change\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n return {\n ClassDeclaration(node) {\n if (!isMigrationClass(node)) return\n if (hasLeadingJSDoc(context.sourceCode, node.parent)) return\n\n context.report({ node: node.id ?? node, messageId: \"missingJSDoc\" })\n },\n }\n }\n}\n\nexport default new RequireMigrationJSDoc()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { getJSDocDescription, isJSDocComment } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = [{ max: number }]\ntype MessageIds = \"tooLong\"\n\nconst DEFAULT_MAX = 250\n\n/**\n * Flags JSDoc comments whose description (the prose before the first tag) is\n * longer than the configured character limit, catching the oversized,\n * essay-like blocks AI models tend to produce.\n */\nclass MaxJSDocDescriptionLength extends NitpickerRule<MessageIds, Options> {\n readonly name = \"max-jsdoc-description-length\"\n\n readonly defaultOptions: Options = [{ max: DEFAULT_MAX }]\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Enforce a maximum character length for a JSDoc description.\",\n recommended: true,\n category: \"base\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n max: { type: \"integer\", minimum: 1 },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n tooLong: nitpick({\n problem: \"This JSDoc description is {{length}} characters, over the {{max}}-character limit.\",\n why: \"A JSDoc description should summarize what something is, an oversized one usually restates the code or explains how it is used, which does not belong here\",\n fix: 'Trim it to a concise summary of what it does, and remove any note about how or where it is used (e.g \"used by X to ...\", \"called from Y\"), which is an anti-pattern',\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const max = options[0]?.max ?? DEFAULT_MAX\n\n return {\n Program() {\n for (const comment of context.sourceCode.getAllComments()) {\n if (!isJSDocComment(comment)) continue\n\n const length = getJSDocDescription(comment).length\n if (length <= max) continue\n\n context.report({\n loc: comment.loc,\n messageId: \"tooLong\",\n data: { length, max },\n })\n }\n },\n }\n }\n}\n\nexport default new MaxJSDocDescriptionLength()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"alias\"\n\n/**\n * Flags a `const` whose entire value is another variable, such as\n * `const accessTokens = rawAccessTokens`, since it just renames the source and\n * adds a name to track. `let` and exported bindings are exempt.\n */\nclass NoAliasVariables extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-alias-variables\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Disallow a `const` whose whole value is another variable, use the source directly.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n alias: nitpick({\n problem: \"`{{name}}` only aliases `{{source}}`.\",\n why: \"A variable that just renames another hides the original and adds a name to track for no gain\",\n fix: \"Remove it and use `{{source}}` directly, or rename `{{source}}` itself if the new name is better\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n return {\n VariableDeclarator(node) {\n if (node.parent.type !== \"VariableDeclaration\" || node.parent.kind !== \"const\") return\n\n // Exported bindings cannot be inlined away, so they are exempt\n if (node.parent.parent.type === \"ExportNamedDeclaration\") return\n\n if (node.id.type !== \"Identifier\" || node.init?.type !== \"Identifier\") return\n\n context.report({\n node,\n messageId: \"alias\",\n data: {\n name: node.id.name,\n source: node.init.name,\n },\n })\n },\n }\n }\n}\n\nexport default new NoAliasVariables()\n","/**\n * British English spellings mapped to their American equivalents, keyed in\n * lowercase. Extend it per project via the `no-british-english` rule's `extra`\n * option.\n */\nexport const BRITISH_TO_AMERICAN: Record<string, string> = {\n // \"-our\" to \"-or\"\n colour: \"color\",\n colours: \"colors\",\n coloured: \"colored\",\n colouring: \"coloring\",\n behaviour: \"behavior\",\n behaviours: \"behaviors\",\n favourite: \"favorite\",\n favourites: \"favorites\",\n flavour: \"flavor\",\n flavours: \"flavors\",\n honour: \"honor\",\n labour: \"labor\",\n neighbour: \"neighbor\",\n\n // \"-ise\" to \"-ize\" and their inflections\n normalise: \"normalize\",\n normalised: \"normalized\",\n normalising: \"normalizing\",\n normalisation: \"normalization\",\n initialise: \"initialize\",\n initialised: \"initialized\",\n initialising: \"initializing\",\n initialisation: \"initialization\",\n serialise: \"serialize\",\n serialised: \"serialized\",\n serialising: \"serializing\",\n serialisation: \"serialization\",\n organise: \"organize\",\n organised: \"organized\",\n organising: \"organizing\",\n organisation: \"organization\",\n optimise: \"optimize\",\n optimised: \"optimized\",\n optimising: \"optimizing\",\n optimisation: \"optimization\",\n customise: \"customize\",\n customised: \"customized\",\n customising: \"customizing\",\n sanitise: \"sanitize\",\n sanitised: \"sanitized\",\n sanitising: \"sanitizing\",\n synchronise: \"synchronize\",\n synchronised: \"synchronized\",\n synchronising: \"synchronizing\",\n authorise: \"authorize\",\n authorised: \"authorized\",\n authorising: \"authorizing\",\n finalise: \"finalize\",\n finalised: \"finalized\",\n finalising: \"finalizing\",\n capitalise: \"capitalize\",\n capitalised: \"capitalized\",\n capitalising: \"capitalizing\",\n categorise: \"categorize\",\n categorised: \"categorized\",\n\n // \"-yse\" to \"-yze\"\n analyse: \"analyze\",\n analysed: \"analyzed\",\n analysing: \"analyzing\",\n\n // \"-re\" to \"-er\"\n centre: \"center\",\n centred: \"centered\",\n centres: \"centers\",\n fibre: \"fiber\",\n metre: \"meter\",\n\n // \"-ce\" to \"-se\"\n licence: \"license\",\n defence: \"defense\",\n offence: \"offense\",\n\n // Doubled \"l\" in inflections\n cancelled: \"canceled\",\n cancelling: \"canceling\",\n labelled: \"labeled\",\n labelling: \"labeling\",\n modelling: \"modeling\",\n travelled: \"traveled\",\n\n // Miscellaneous\n grey: \"gray\",\n dialogue: \"dialog\",\n catalogue: \"catalog\",\n}\n","/**\n * Merges a base lookup with extra entries and removes ignored keys, keying everything in lowercase\n * for case-insensitive lookups. Used to let a rule's built-in table be extended or narrowed\n * through its options.\n * @param base The built-in lookup.\n * @param extra Additional entries to add or override.\n * @param ignore Keys to remove from the result.\n * @returns The merged, lowercase-keyed lookup.\n */\nexport function buildDictionary(\n base: Record<string, string>,\n extra: Record<string, string>,\n ignore: string[],\n): Record<string, string> {\n const dictionary: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(base)) {\n dictionary[key.toLowerCase()] = value\n }\n\n for (const [key, value] of Object.entries(extra)) {\n dictionary[key.toLowerCase()] = value\n }\n\n for (const key of ignore) {\n delete dictionary[key.toLowerCase()]\n }\n\n return dictionary\n}\n","import CONSTANTS from \"@/lib/constants\"\n\n/**\n * A sub-word found in a piece of text, with its start offset.\n */\nexport type Word = {\n /**\n * The sub-word, in its original casing.\n */\n text: string\n\n /**\n * The offset of the sub-word within the source text.\n */\n index: number\n}\n\n/**\n * Splits a piece of text into its sub-words, handling camelCase, PascalCase,\n * snake_case, and plain prose.\n * @param text The text to split.\n * @returns The sub-words found, each with its offset in the text.\n */\nexport function extractWords(text: string): Word[] {\n const words: Word[] = []\n\n for (const match of text.matchAll(CONSTANTS.WORDS.SUB_WORD)) {\n if (match.index !== undefined) {\n words.push({ text: match[0], index: match.index })\n }\n }\n\n return words\n}\n\n/**\n * Rewrites a replacement word to match the casing of the word it replaces, so a\n * capitalized source yields a capitalized result and an all-caps source an\n * all-caps one.\n * @param source The original word whose casing should be mirrored.\n * @param replacement The lowercase replacement word.\n * @returns The replacement, cased like the source.\n */\nexport function matchCase(source: string, replacement: string): string {\n if (source === source.toUpperCase()) {\n return replacement.toUpperCase()\n }\n\n if (source.charAt(0) === source.charAt(0).toUpperCase()) {\n return replacement.charAt(0).toUpperCase() + replacement.slice(1)\n }\n\n return replacement\n}\n\n/**\n * Checks whether a character is a \"word\" character, i.e. something that can\n * appear inside an identifier or a number (letters, digits, underscore, dollar).\n * @param char The single character to test, or `undefined` (e.g. past the end\n * of a string).\n * @returns `true` if the character is a word character, `false` otherwise.\n */\nexport function isWordChar(char: string | undefined): boolean {\n return char !== undefined && CONSTANTS.WORDS.WORD_CHAR.test(char)\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { BRITISH_TO_AMERICAN } from \"@/lib/data/britishToAmerican\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { buildDictionary } from \"@/lib/utils/dictionaries\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\nimport { extractWords, matchCase } from \"@/lib/utils/words\"\n\ntype Options = [{ extra: Record<string, string>; ignore: string[] }]\ntype MessageIds = \"british\"\n\n/**\n * Flags British English spellings in identifiers and comments, reporting the\n * American equivalent. The built-in dictionary can be extended per project with\n * the `extra` option, or narrowed with `ignore`.\n */\nclass NoBritishEnglish extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-british-english\"\n\n readonly defaultOptions: Options = [{ extra: {}, ignore: [] }]\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Disallow British English spellings in identifiers and comments.\",\n recommended: true,\n category: \"base\",\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n extra: {\n type: \"object\",\n additionalProperties: { type: \"string\" },\n },\n ignore: {\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n british: nitpick({\n problem: \"British spelling `{{british}}`, this codebase uses American English.\",\n why: \"One spelling convention keeps identifiers and docs consistent and searchable\",\n fix: \"Use `{{american}}` instead\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const dictionary = buildDictionary(BRITISH_TO_AMERICAN, options[0]?.extra ?? {}, options[0]?.ignore ?? [])\n\n return {\n Identifier(node) {\n // Skip a member's property name (an external read), it cannot be\n // renamed from here\n if (node.parent.type === \"MemberExpression\" && node.parent.property === node && !node.parent.computed) {\n return\n }\n\n for (const word of extractWords(node.name)) {\n const american = dictionary[word.text.toLowerCase()]\n if (american === undefined) continue\n\n context.report({\n node,\n messageId: \"british\",\n data: { british: word.text, american: matchCase(word.text, american) },\n })\n }\n },\n Program() {\n for (const comment of context.sourceCode.getAllComments()) {\n for (const word of extractWords(comment.value)) {\n const american = dictionary[word.text.toLowerCase()]\n if (american === undefined) continue\n\n const cased = matchCase(word.text, american)\n\n // The comment value starts right after the `//` or `/*`\n const from = comment.range[0] + 2 + word.index\n const to = from + word.text.length\n\n context.report({\n loc: {\n start: context.sourceCode.getLocFromIndex(from),\n end: context.sourceCode.getLocFromIndex(to),\n },\n messageId: \"british\",\n data: { british: word.text, american: cased },\n fix: fixer => fixer.replaceTextRange([from, to], cased),\n })\n }\n }\n },\n }\n }\n}\n\nexport default new NoBritishEnglish()\n","import CONSTANTS from \"@/lib/constants\"\n\n/**\n * Checks whether a single comment line is a decorative separator, i.e. a banner,\n * a box-drawing rule, or a label fenced by repeated separator characters.\n * @param line The raw comment line, still carrying any leading ` * ` marker.\n * @returns `true` if the line is decorative.\n */\nexport function isDecorativeCommentLine(line: string): boolean {\n const content = line.replace(/^\\s*\\*?\\s*/, \"\").trimEnd()\n if (content.length === 0) return false\n\n return (\n CONSTANTS.COMMENTS.BOX_DRAWING.test(content) ||\n CONSTANTS.COMMENTS.PURE_SEPARATOR.test(content) ||\n CONSTANTS.COMMENTS.WRAPPED_LABEL.test(content)\n )\n}\n","/**\n * Converts a glob pattern into an anchored regular expression, supporting `*`\n * (any run within a path segment) and `**` (any run across segments).\n * @param glob The glob pattern to convert.\n * @returns The equivalent regular expression.\n */\nfunction globToRegExp(glob: string): RegExp {\n const normalized = glob.replace(/\\\\/g, \"/\")\n let pattern = \"^\"\n\n for (let index = 0; index < normalized.length; index++) {\n const char = normalized[index]\n if (char === undefined) break\n\n if (char === \"*\") {\n if (normalized[index + 1] === \"*\") {\n pattern += \".*\"\n index++\n\n // If the `**` is followed by a `/`, skip it so that `**/` and `**` are equivalent\n if (normalized[index + 1] === \"/\") index++\n } else {\n pattern += \"[^/]*\"\n }\n } else if (\"\\\\^$.|?+()[]{}\".includes(char)) {\n pattern += `\\\\${char}`\n } else {\n pattern += char\n }\n }\n\n return new RegExp(`${pattern}$`)\n}\n\n/**\n * Checks whether a file path matches any of the given glob patterns, comparing\n * with forward slashes so it works the same on every platform.\n * @param filename The file path to test.\n * @param patterns The glob patterns to match against.\n * @returns `true` if the path matches at least one pattern.\n */\nexport function matchesGlob(filename: string, patterns: string[]): boolean {\n const path = filename.replace(/\\\\/g, \"/\")\n\n return patterns.some(pattern => globToRegExp(pattern).test(path))\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isDecorativeCommentLine } from \"@/lib/utils/decorations\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport { matchesGlob } from \"@/lib/utils/regex\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = [{ allowIn: string[] }]\ntype MessageIds = \"decorative\"\n\n/**\n * Flags decorative separators inside comments: banner rules (`// ======`),\n * box-drawing lines, and labels fenced by repeated dashes (`// -- Section --`),\n * the `allowIn` option lists globs where they are tolerated.\n */\nclass NoDecorativeCommentSeparators extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-decorative-comment-separators\"\n\n readonly defaultOptions: Options = [{ allowIn: [] }]\n\n readonly meta = {\n type: \"layout\",\n docs: {\n description: \"Disallow decorative separators (banners, box-drawing, repeated dashes) inside comments.\",\n recommended: true,\n category: \"base\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowIn: {\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n decorative: nitpick({\n problem: \"This comment uses a decorative separator.\",\n why: \"Repeated separator characters and box-drawing lines are visual noise that add nothing over a plain label\",\n fix: \"Remove the separator, a one-line label or a blank line already divides sections clearly\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const allowIn = options[0]?.allowIn ?? []\n if (allowIn.length > 0 && matchesGlob(context.filename, allowIn)) {\n return {}\n }\n\n return {\n Program() {\n for (const comment of context.sourceCode.getAllComments()) {\n const lines = comment.value.split(\"\\n\")\n\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index]\n if (line === undefined || !isDecorativeCommentLine(line)) continue\n\n const reportedLine = comment.loc.start.line + index\n const source = context.sourceCode.lines[reportedLine - 1] ?? \"\"\n\n context.report({\n loc: {\n start: { line: reportedLine, column: 0 },\n end: { line: reportedLine, column: source.length },\n },\n messageId: \"decorative\",\n })\n }\n }\n },\n }\n }\n}\n\nexport default new NoDecorativeCommentSeparators()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"emDash\"\n\n/**\n * Flags every em dash (—) character found anywhere in the source.\n */\nclass NoEmDash extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-em-dash\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Disallow the em dash (—) character anywhere in the source.\",\n recommended: true,\n },\n schema: [],\n messages: {\n emDash: nitpick({\n problem: \"Found an em dash (—) character.\",\n why: \"Em dashes are typically introduced by AI-generated or auto-formatted text and are discouraged here.\",\n fix: \"Replace the em dash with a hyphen (-), a comma (,), or reword the sentence to avoid it.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n const text = context.sourceCode.getText()\n\n return {\n Program() {\n // Scan the raw source so every em dash is caught, whether it appears\n // in code, strings, or comments\n for (let index = 0; index < text.length; index++) {\n if (text[index] !== CONSTANTS.EM_DASH) continue\n\n context.report({\n loc: {\n start: context.sourceCode.getLocFromIndex(index),\n end: context.sourceCode.getLocFromIndex(index + 1),\n },\n messageId: \"emDash\",\n })\n }\n },\n }\n }\n}\n\nexport default new NoEmDash()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isBlankJSDocLine, isJSDocComment, isJSDocTagLine } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"blankBeforeTag\"\n\n/**\n * Flags blank lines that sit between a JSDoc description and its tags (or\n * between tags) and removes them so the tags follow on directly.\n */\nclass NoJSDocBlankBeforeTags extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-jsdoc-blank-before-tags\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"layout\",\n fixable: \"code\",\n docs: {\n description: \"Disallow blank lines before JSDoc tags such as `@param` or `@returns`.\",\n recommended: true,\n },\n schema: [],\n messages: {\n blankBeforeTag: nitpick({\n problem: \"There is a blank line before a JSDoc tag.\",\n why: \"Tags should follow the description directly; an empty line there is noise that inflates the comment.\",\n fix: \"Remove the blank line so the tag follows on directly.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n return {\n Program() {\n for (const comment of context.sourceCode.getAllComments()) {\n if (!isJSDocComment(comment)) continue\n\n if (comment.loc.start.line === comment.loc.end.line) continue\n\n for (let line = comment.loc.start.line; line <= comment.loc.end.line; line++) {\n const text = context.sourceCode.lines[line - 1]\n if (text === undefined || !isBlankJSDocLine(text)) continue\n\n // Grow the run of consecutive blank lines\n let runEnd = line\n while (\n runEnd < comment.loc.end.line &&\n isBlankJSDocLine(context.sourceCode.lines[runEnd] ?? \"\")\n ) {\n runEnd++\n }\n\n // Only a blank run immediately before a tag is a problem\n const nextLine = context.sourceCode.lines[runEnd]\n if (nextLine !== undefined && isJSDocTagLine(nextLine)) {\n const from = context.sourceCode.getIndexFromLoc({ line, column: 0 })\n const to = context.sourceCode.getIndexFromLoc({ line: runEnd + 1, column: 0 })\n\n context.report({\n loc: {\n start: { line, column: 0 },\n end: { line: runEnd, column: text.length },\n },\n messageId: \"blankBeforeTag\",\n fix: fixer => fixer.removeRange([from, to]),\n })\n }\n\n line = runEnd\n }\n }\n },\n }\n }\n}\n\nexport default new NoJSDocBlankBeforeTags()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\nimport { isWordChar } from \"@/lib/utils/words\"\n\ntype Options = []\ntype MessageIds = \"period\"\n\n/**\n * Flags periods used as prose punctuation inside `//` line comments. Dots that\n * are part of a token (`foo.bar`, `1.5`, `.env`) and ellipses (`...`) are left\n * alone.\n */\nclass NoLineCommentPeriod extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-line-comment-period\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"layout\",\n fixable: \"code\",\n docs: {\n description: \"Disallow prose periods in `//` line comments (code-reference dots and ellipses are allowed).\",\n recommended: true,\n },\n schema: [],\n messages: {\n period: nitpick({\n problem: \"This line comment contains a period.\",\n why: \"Line comments should be short, clear fragments, not full sentences, so periods are just noise, dots inside code references like `foo.bar` are allowed.\",\n fix: \"Remove the period and keep the comment terse.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n return {\n Program() {\n for (const comment of context.sourceCode.getAllComments()) {\n if (comment.type !== \"Line\") continue\n\n // The comment value starts right after the leading `//`\n const valueStart = comment.range[0] + 2\n\n for (let index = 0; index < comment.value.length; index++) {\n if (comment.value[index] !== \".\") continue\n\n // A run of consecutive dots is an ellipsis, leave it alone\n if (comment.value[index + 1] === \".\") {\n while (comment.value[index + 1] === \".\") index++\n continue\n }\n\n // A lone dot immediately followed by a word character is\n // part of a token (`foo.bar`, `1.5`, `.env`), not prose\n if (isWordChar(comment.value[index + 1])) continue\n\n const at = valueStart + index\n\n context.report({\n loc: {\n start: context.sourceCode.getLocFromIndex(at),\n end: context.sourceCode.getLocFromIndex(at + 1),\n },\n messageId: \"period\",\n fix: fixer => fixer.removeRange([at, at + 1]),\n })\n }\n }\n },\n }\n }\n}\n\nexport default new NoLineCommentPeriod()\n","import type { TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Checks whether an expression is nothing but a non-computed property access\n * chain (with any `?.` or `!`) bottoming out at an identifier or `this`, such as\n * `auth.user!` or `menu.node.path`.\n * @param node The expression to inspect.\n * @returns `true` if the expression is a plain property access.\n */\nexport function isPropertyAccessAlias(node: TSESTree.Expression): boolean {\n let expression: TSESTree.Node = node\n let sawMemberAccess = false\n\n while (true) {\n if (expression.type === \"ChainExpression\" || expression.type === \"TSNonNullExpression\") {\n expression = expression.expression\n continue\n }\n\n if (expression.type === \"MemberExpression\") {\n if (expression.computed) return false\n\n sawMemberAccess = true\n expression = expression.object\n continue\n }\n\n break\n }\n\n return sawMemberAccess && (expression.type === \"Identifier\" || expression.type === \"ThisExpression\")\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isPropertyAccessAlias } from \"@/lib/utils/aliases\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"propertyAccessAlias\"\n\n/**\n * Flags a `const` whose entire value is a single property access, such as\n * `const user = auth.user!`, since it just renames a property and hides where\n * the value comes from, `let` is exempt, as it may be reassigned later.\n */\nclass NoPropertyAccessAlias extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-property-access-alias\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description:\n \"Disallow a `const` whose whole value is a single property access, inline the expression instead.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n propertyAccessAlias: nitpick({\n problem: \"`{{name}}` only aliases the property access `{{expression}}`.\",\n why: \"A variable that just renames a property hides where the value comes from when scanning the code\",\n fix: \"Remove it and use `{{expression}}` inline, or use `let` if it is reassigned later\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n return {\n VariableDeclarator(node) {\n if (node.parent.type !== \"VariableDeclaration\" || node.parent.kind !== \"const\") return\n\n // Exported bindings cannot be inlined away, so they are exempt\n if (node.parent.parent.type === \"ExportNamedDeclaration\") return\n\n if (node.id.type !== \"Identifier\" || node.init === null) return\n if (!isPropertyAccessAlias(node.init)) return\n\n context.report({\n node,\n messageId: \"propertyAccessAlias\",\n data: {\n name: node.id.name,\n expression: context.sourceCode.getText(node.init),\n },\n })\n },\n }\n }\n}\n\nexport default new NoPropertyAccessAlias()\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isPropertyAccessAlias } from \"@/lib/utils/aliases\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"destructure\"\n\n/**\n * Flags shorthand object destructuring off a plain object reference\n * (`const { a } = object`), which just aliases `object.a`. Destructuring a call\n * or hook result, renames, defaults, and rest elements are left alone.\n */\nclass NoPropertyDestructuring extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-property-destructuring\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Disallow shorthand destructuring off a plain object reference, access the property directly.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n destructure: nitpick({\n problem: \"Destructuring from `{{source}}` here just aliases its properties.\",\n why: \"Reading `{{source}}.x` at the use site keeps the origin visible, destructuring a plain object hides where a value comes from (destructuring a call or hook result is fine)\",\n fix: \"Access the properties on `{{source}}` directly instead of destructuring\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n return {\n VariableDeclarator(node) {\n if (node.parent.type !== \"VariableDeclaration\" || node.parent.kind !== \"const\") return\n if (node.parent.parent.type === \"ExportNamedDeclaration\") return\n if (node.id.type !== \"ObjectPattern\" || node.init === null) return\n\n // Only a plain object reference is an alias, a call, await, or new\n // result is a computed value worth destructuring\n if (node.init.type !== \"Identifier\" && !isPropertyAccessAlias(node.init)) return\n\n // Only pure shorthand grabs (`{ a }`) are aliases, renames,\n // defaults, and rest elements are deliberate\n if (!isAllShorthand(node.id)) return\n\n context.report({\n node,\n messageId: \"destructure\",\n data: { source: context.sourceCode.getText(node.init) },\n })\n },\n }\n }\n}\n\n/**\n * Checks whether an object pattern is nothing but plain shorthand properties,\n * i.e. `{ a, b }` with no rename, default, computed key, or rest element.\n * @param pattern The object pattern to inspect.\n * @returns `true` if every property is a pure shorthand grab.\n */\nfunction isAllShorthand(pattern: TSESTree.ObjectPattern): boolean {\n if (pattern.properties.length === 0) return false\n\n return pattern.properties.every(\n property =>\n property.type === \"Property\" &&\n property.shorthand &&\n !property.computed &&\n property.value.type === \"Identifier\",\n )\n}\n\nexport default new NoPropertyDestructuring()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isJSDocComment } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"singleLine\"\n\n/**\n * Flags JSDoc comments (`/**`) that are written on a single line and expands\n * them into the multi-line form:\n * ```\n * /** blabla *​/ -> /**\n * * blabla\n * *​/\n * ```\n */\nclass NoSingleLineJSDoc extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-single-line-jsdoc\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"layout\",\n fixable: \"code\",\n docs: {\n description: \"Require JSDoc comments to span multiple lines rather than sit on a single line.\",\n recommended: true,\n },\n schema: [],\n messages: {\n singleLine: nitpick({\n problem: \"This JSDoc comment is written on a single line.\",\n why: \"Multi-line JSDoc is easier to read, diff, and extend with additional tags, and is the house style.\",\n fix: \"Put the opening `/**`, the ` * ` content, and the closing `*/` each on their own line.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n return {\n Program() {\n for (const comment of context.sourceCode.getAllComments()) {\n // Only JSDoc comments (`/**`) that fit on one line\n if (!isJSDocComment(comment)) continue\n if (comment.loc.start.line !== comment.loc.end.line) continue\n\n // Strip the leading `*` left over from `/**` and normalize\n const content = comment.value.replace(/^\\*/, \"\").trim()\n\n // An empty JSDoc (`/** */`) has nothing to expand onto its\n // own line, so it is left alone\n if (content.length === 0) continue\n\n context.report({\n loc: comment.loc,\n messageId: \"singleLine\",\n fix(fixer) {\n const indent = \" \".repeat(comment.loc.start.column)\n const expanded = `/**\\n${indent} * ${content}\\n${indent} */`\n return fixer.replaceTextRange(comment.range, expanded)\n },\n })\n }\n },\n }\n }\n}\n\nexport default new NoSingleLineJSDoc()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * A framework Nitpicker ships a dedicated rule category and shared config for.\n */\nexport type Framework = \"adonisjs\" | \"react\"\n\n/**\n * The human-readable label for each framework, used in messages.\n */\nexport const FRAMEWORK_LABELS: Record<Framework, string> = {\n adonisjs: \"AdonisJS\",\n react: \"React\",\n}\n\n/**\n * Collects the module specifiers imported by a source file.\n * @param sourceCode The source code of the linted file.\n * @returns The list of imported module specifiers.\n */\nfunction importSources(sourceCode: Readonly<TSESLint.SourceCode>): string[] {\n const sources: string[] = []\n\n for (const statement of sourceCode.ast.body) {\n if (statement.type === \"ImportDeclaration\") {\n sources.push(String(statement.source.value))\n }\n }\n\n return sources\n}\n\n/**\n * Detects which supported frameworks a file appears to use, based on its imports\n * and file name.\n * @param sourceCode The source code of the linted file.\n * @param filename The path of the linted file.\n * @returns The set of frameworks detected in the file.\n */\nexport function detectFrameworks(sourceCode: Readonly<TSESLint.SourceCode>, filename: string): Set<Framework> {\n const detected = new Set<Framework>()\n const sources = importSources(sourceCode)\n\n if (sources.some(source => source.startsWith(\"@adonisjs/\") || CONSTANTS.FRAMEWORKS.ADONIS_SUBPATH.test(source))) {\n detected.add(\"adonisjs\")\n }\n\n const importsReact = sources.some(\n source => source === \"react\" || source.startsWith(\"react/\") || source === \"react-dom\",\n )\n if (importsReact || CONSTANTS.FRAMEWORKS.REACT_FILE.test(filename)) {\n detected.add(\"react\")\n }\n\n return detected\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { detectFrameworks, FRAMEWORK_LABELS, type Framework } from \"@/lib/utils/frameworks\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = [{ ignore: Framework[] }]\ntype MessageIds = \"missingConfig\"\n\n/**\n * Warns when a file uses a framework (AdonisJS, React) whose Nitpicker config is\n * not enabled. Enabling the matching config (which sets a settings flag) or\n * turning off this rule silences it.\n */\nclass RequireFrameworkConfig extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-framework-config\"\n\n readonly defaultOptions: Options = [{ ignore: [] }]\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Warn when a file uses a framework whose Nitpicker config is not enabled.\",\n recommended: true,\n category: \"base\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n ignore: {\n type: \"array\",\n items: {\n type: \"string\",\n enum: [\"adonisjs\", \"react\"],\n },\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingConfig: nitpick({\n problem: \"This file uses {{framework}} but the Nitpicker {{framework}} rules are not enabled.\",\n why: \"Framework rules only run when you opt into the matching config, so files like this one go unchecked\",\n fix: \"Add `nitpicker.configs.{{config}}` (scoped to these files) to your ESLint config, or turn off `nitpicker/require-framework-config`\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const ignored = new Set(options[0]?.ignore ?? [])\n\n // Each framework config stamps `settings.nitpicker<framework> = true`\n const enabled = (context.settings[CONSTANTS.PLUGIN_NAME] ?? {}) as Partial<Record<Framework, boolean>>\n\n return {\n Program(node) {\n const detected = detectFrameworks(context.sourceCode, context.filename)\n\n for (const framework of detected) {\n if (ignored.has(framework) || enabled[framework]) continue\n\n context.report({\n node,\n messageId: \"missingConfig\",\n data: { framework: FRAMEWORK_LABELS[framework], config: framework },\n })\n }\n },\n }\n }\n}\n\nexport default new RequireFrameworkConfig()\n","import type { TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Any node that introduces a callable function.\n */\nexport type FunctionNode = TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression\n\n/**\n * Resolves the node whose leading comments would document a function, walking\n * out through a variable declaration and/or an export statement (so\n * `export const foo = () => {}` resolves to the `export` node).\n * @param fn The function node to resolve from.\n * @returns The node a JSDoc comment would sit above.\n */\nexport function getDocumentableNode(fn: FunctionNode): TSESTree.Node {\n let node: TSESTree.Node = fn\n\n if (node.parent.type === \"VariableDeclarator\" && node.parent.parent.type === \"VariableDeclaration\") {\n node = node.parent.parent\n }\n\n if (node.parent.type === \"ExportNamedDeclaration\" || node.parent.type === \"ExportDefaultDeclaration\") {\n node = node.parent\n }\n\n return node\n}\n\n/**\n * Checks whether a node sits directly at the top level of the module.\n * @param node The node to test.\n * @returns `true` if the node's parent is the program root.\n */\nexport function isTopLevel(node: TSESTree.Node): boolean {\n return node.parent?.type === \"Program\"\n}\n\n/**\n * Resolves the declared name of a function, whether it comes from the function\n * itself or the variable it is assigned to.\n * @param fn The function node to name.\n * @returns The function name, or `undefined` if it is anonymous.\n */\nexport function getFunctionName(fn: FunctionNode): string | undefined {\n if ((fn.type === \"FunctionDeclaration\" || fn.type === \"FunctionExpression\") && fn.id) {\n return fn.id.name\n }\n\n if (fn.parent.type === \"VariableDeclarator\" && fn.parent.id.type === \"Identifier\") {\n return fn.parent.id.name\n }\n\n return undefined\n}\n","import type { TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * The AST node types that introduce a new function scope.\n */\nconst FUNCTION_NODE_TYPES = new Set<string>([\"FunctionDeclaration\", \"FunctionExpression\", \"ArrowFunctionExpression\"])\n\n/**\n * A lookup of AST node type to the property keys that hold its child nodes.\n */\ntype VisitorKeys = Record<string, readonly string[] | undefined>\n\n/**\n * Checks whether a name follows the `PascalCase` convention React uses to\n * distinguish component functions from plain functions and DOM tags.\n * @param name The function name to test.\n * @returns `true` if the name starts with an uppercase letter.\n */\nexport function isReactComponentName(name: string): boolean {\n return /^[A-Z]/.test(name)\n}\n\n/**\n * Checks whether an expression evaluates to JSX, following the branches a\n * component commonly returns through (ternaries, `&&`, comma sequences).\n * @param node The expression to inspect, if any.\n * @returns `true` if the expression can produce a JSX element or fragment.\n */\nexport function isJsxExpression(node: TSESTree.Expression | null | undefined): boolean {\n if (!node) return false\n\n switch (node.type) {\n case \"JSXElement\":\n case \"JSXFragment\":\n return true\n case \"ConditionalExpression\":\n return isJsxExpression(node.consequent) || isJsxExpression(node.alternate)\n case \"LogicalExpression\":\n return isJsxExpression(node.left) || isJsxExpression(node.right)\n case \"SequenceExpression\":\n return isJsxExpression(node.expressions.at(-1))\n default:\n return false\n }\n}\n\n/**\n * Recursively searches a subtree for a `return` that yields JSX, without\n * crossing into nested functions (whose returns belong to them, not us).\n * @param node The AST node to inspect.\n * @param visitorKeys The AST visitor keys, used to walk the subtree.\n */\nfunction subtreeReturnsJsx(node: TSESTree.Node, visitorKeys: VisitorKeys): boolean {\n if (node.type === \"ReturnStatement\") {\n return isJsxExpression(node.argument)\n }\n\n for (const key of visitorKeys[node.type] ?? []) {\n const value = (node as unknown as Record<string, unknown>)[key]\n const children = Array.isArray(value) ? value : [value]\n\n for (const child of children) {\n const childNode = child as TSESTree.Node | null | undefined\n if (!childNode || typeof childNode.type !== \"string\") continue\n\n // Nested functions own their own returns, so stop descending there\n if (FUNCTION_NODE_TYPES.has(childNode.type)) continue\n if (subtreeReturnsJsx(childNode, visitorKeys)) return true\n }\n }\n\n return false\n}\n\n/**\n * Checks whether a function returns JSX, i.e. whether it looks like it renders\n * a React element.\n * @param fn The function node to inspect.\n * @param visitorKeys The AST visitor keys, used to walk the function body.\n * @returns True if the function returns JSX.\n */\nexport function functionReturnsJsx(\n fn: TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression,\n visitorKeys: VisitorKeys,\n): boolean {\n // An arrow with an expression body returns that expression directly\n if (fn.type === \"ArrowFunctionExpression\" && fn.body.type !== \"BlockStatement\") {\n return isJsxExpression(fn.body)\n }\n\n return subtreeReturnsJsx(fn.body, visitorKeys)\n}\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { type FunctionNode, getDocumentableNode, getFunctionName, isTopLevel } from \"@/lib/utils/functions\"\nimport { hasLeadingJSDoc } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport { functionReturnsJsx, isReactComponentName } from \"@/lib/utils/react\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"missingJSDoc\"\n\n/**\n * Requires a JSDoc comment on top-level functions, with React component\n * functions (`PascalCase` name returning JSX) being the sole exception.\n */\nclass RequireFunctionJSDoc extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-function-jsdoc\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Require a JSDoc comment on top-level functions, except React component functions.\",\n recommended: true,\n },\n schema: [],\n messages: {\n missingJSDoc: nitpick({\n problem: \"The function `{{name}}` has no JSDoc comment.\",\n why: \"Top-level functions must document their purpose, parameters, and return value, React component functions are the only exception.\",\n fix: \"Add a `/** ... */` JSDoc block immediately above the function describing what it does.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n const check = (fn: FunctionNode, reportNode: TSESTree.Node): void => {\n const name = getFunctionName(fn)\n // Anonymous functions (e.g `export default () => {}`) are skipped\n if (name === undefined) return\n\n const documentable = getDocumentableNode(fn)\n if (!isTopLevel(documentable)) return\n\n // React component functions are exempt from the JSDoc requirement\n if (isReactComponentName(name) && functionReturnsJsx(fn, context.sourceCode.visitorKeys)) return\n\n if (hasLeadingJSDoc(context.sourceCode, documentable)) return\n\n context.report({\n node: reportNode,\n messageId: \"missingJSDoc\",\n data: { name },\n })\n }\n\n return {\n FunctionDeclaration(node) {\n check(node, node.id ?? node)\n },\n VariableDeclarator(node) {\n if (!node.init) return\n if (node.init.type !== \"ArrowFunctionExpression\" && node.init.type !== \"FunctionExpression\") return\n\n check(node.init, node.id)\n },\n }\n }\n}\n\nexport default new RequireFunctionJSDoc()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\nimport migrationTableOrder from \"@/rules/adonisjs/migrationTableOrder\"\nimport requireMigrationJSDoc from \"@/rules/adonisjs/requireMigrationJSDoc\"\nimport maxJSDocDescriptionLength from \"@/rules/base/maxJSDocDescriptionLength\"\nimport noAliasVariables from \"@/rules/base/noAliasVariables\"\nimport noBritishEnglish from \"@/rules/base/noBritishEnglish\"\nimport noDecorativeCommentSeparators from \"@/rules/base/noDecorativeCommentSeparators\"\nimport noEmDash from \"@/rules/base/noEmDash\"\nimport noJSDocBlankBeforeTags from \"@/rules/base/noJSDocBlankBeforeTags\"\nimport noLineCommentPeriod from \"@/rules/base/noLineCommentPeriod\"\nimport noPropertyAccessAlias from \"@/rules/base/noPropertyAccessAlias\"\nimport noPropertyDestructuring from \"@/rules/base/noPropertyDestructuring\"\nimport noSingleLineJSDoc from \"@/rules/base/noSingleLineJSDoc\"\nimport requireFrameworkConfig from \"@/rules/base/requireFrameworkConfig\"\nimport requireFunctionJSDoc from \"@/rules/base/requireFunctionJSDoc\"\n\n/**\n * Every rule instance registered by the plugin.\n */\nconst ruleInstances = [\n migrationTableOrder,\n requireMigrationJSDoc,\n maxJSDocDescriptionLength,\n noAliasVariables,\n noBritishEnglish,\n noDecorativeCommentSeparators,\n noEmDash,\n noJSDocBlankBeforeTags,\n noLineCommentPeriod,\n noPropertyAccessAlias,\n noPropertyDestructuring,\n noSingleLineJSDoc,\n requireFrameworkConfig,\n requireFunctionJSDoc,\n]\n\n/**\n * The plugin's rules, keyed by name, as the plain modules ESLint consumes.\n */\nexport const rules = Object.fromEntries(ruleInstances.map(rule => [rule.name, rule.toRuleModule()])) as Record<\n string,\n TSESLint.RuleModule<string, readonly unknown[], NitpickerRuleDocs>\n>\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\nimport type { RuleCategory } from \"@/lib/utils/rules\"\nimport { rules } from \"@/rules\"\n\n/**\n * Builds the rules record for a single category, each enabled as a warning,\n * rules with no explicit category are treated as `base`.\n * @param category The category to collect rules for.\n * @returns The flat-config rules record for that category.\n */\nexport function categoryRules(category: RuleCategory): TSESLint.FlatConfig.Rules {\n const enabled: TSESLint.FlatConfig.Rules = {}\n\n for (const [name, rule] of Object.entries(rules)) {\n if ((rule.meta.docs?.category ?? \"base\") === category) {\n enabled[`${CONSTANTS.PLUGIN_NAME}/${name}`] = \"warn\"\n }\n }\n\n return enabled\n}\n\n/**\n * Builds a rules record enabling every rule the plugin ships, as a warning.\n * @returns The flat-config rules record for all rules.\n */\nexport function allRules(): TSESLint.FlatConfig.Rules {\n const enabled: TSESLint.FlatConfig.Rules = {}\n\n for (const name of Object.keys(rules)) {\n enabled[`${CONSTANTS.PLUGIN_NAME}/${name}`] = \"warn\"\n }\n\n return enabled\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { allRules } from \"@/configs/helpers\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Builds the `all` flat config: every rule the plugin ships, each enabled as a\n * warning, this is the maximally-pedantic Nitpicker experience. Both framework\n * settings flags are set, since enabling everything already opts into them.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function all(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n name: `${CONSTANTS.PLUGIN_NAME}/all`,\n plugins: { [CONSTANTS.PLUGIN_NAME]: plugin },\n settings: { [CONSTANTS.PLUGIN_NAME]: { adonisjs: true, react: true } },\n rules: allRules(),\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { categoryRules } from \"@/configs/helpers\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Builds the `base` flat config: the universal rules that apply to every file\n * regardless of framework.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function base(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n name: `${CONSTANTS.PLUGIN_NAME}/base`,\n plugins: { [CONSTANTS.PLUGIN_NAME]: plugin },\n rules: categoryRules(\"base\"),\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { base } from \"@/configs/rulesets/base\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Builds the `recommended` flat config: the sensible default for any project,\n * which is the universal `base` ruleset.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function recommended(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n ...base(plugin),\n name: `${CONSTANTS.PLUGIN_NAME}/recommended`,\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { categoryRules } from \"@/configs/helpers\"\nimport CONSTANTS from \"@/lib/constants\"\n\n// AdonisJS route files where banner separators are the clearest way to group routes\nconst ROUTE_FILE_GLOBS = [\"**/start/routes.ts\", \"**/start/routes/**/*.ts\"]\n\n/**\n * Builds the `adonisjs` flat config: AdonisJS-specific rules, plus a settings\n * flag so `require-framework-config` knows AdonisJS is opted into for these files.\n * It also permits decorative banners in route files, where they aid readability.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function adonisjs(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n name: `${CONSTANTS.PLUGIN_NAME}/adonisjs`,\n plugins: { [CONSTANTS.PLUGIN_NAME]: plugin },\n settings: { [CONSTANTS.PLUGIN_NAME]: { adonisjs: true } },\n rules: {\n ...categoryRules(\"adonisjs\"),\n [`${CONSTANTS.PLUGIN_NAME}/no-decorative-comment-separators`]: [\"warn\", { allowIn: ROUTE_FILE_GLOBS }],\n },\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { categoryRules } from \"@/configs/helpers\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Builds the `react` flat config: React-specific rules, plus a settings flag so\n * `require-framework-config` knows React is opted into for these files.\n * @param plugin The plugin instance to register the rules against.\n * @returns The flat config object.\n */\nexport function react(plugin: TSESLint.FlatConfig.Plugin): TSESLint.FlatConfig.Config {\n return {\n name: `${CONSTANTS.PLUGIN_NAME}/react`,\n plugins: { [CONSTANTS.PLUGIN_NAME]: plugin },\n settings: { [CONSTANTS.PLUGIN_NAME]: { react: true } },\n rules: categoryRules(\"react\"),\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { all } from \"@/configs/presets/all\"\nimport { recommended } from \"@/configs/presets/recommended\"\nimport { adonisjs } from \"@/configs/rulesets/adonisjs\"\nimport { base } from \"@/configs/rulesets/base\"\nimport { react } from \"@/configs/rulesets/react\"\n\n/**\n * Builds all shared configs bundled with the plugin.\n *\n * Note: Configs are built from a factory rather than declared statically\n * because each one needs a reference to the plugin instance it belongs to.\n * @param plugin The plugin instance to register the rules against.\n * @returns A record of config name to flat config object.\n */\nexport function buildConfigs(plugin: TSESLint.FlatConfig.Plugin): Record<string, TSESLint.FlatConfig.Config> {\n return {\n base: base(plugin),\n recommended: recommended(plugin),\n adonisjs: adonisjs(plugin),\n react: react(plugin),\n all: all(plugin),\n }\n}\n","{\n \"name\": \"@alien_intelligence/eslint-plugin-nitpicker\",\n \"productName\": \"Nitpicker\",\n \"version\": \"0.2.0\",\n \"description\": \"A hyper-pedantic ESLint plugin that flags every stylistic and semantic nit, with AI-friendly fix context.\",\n \"author\": \"Alien <contact@alien.club> (https://www.alien.club/)\",\n \"license\": \"MIT\",\n \"private\": false,\n \"packageManager\": \"npm@11.4.2\",\n \"type\": \"module\",\n \"keywords\": [\n \"alien\",\n \"eslint\",\n \"eslintplugin\",\n \"eslint-plugin\",\n \"nitpicker\",\n \"linting\",\n \"code-style\",\n \"ai\"\n ],\n \"homepage\": \"https://github.com/the-alien-club/eslint-plugin-nitpicker\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/the-alien-club/eslint-plugin-nitpicker.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/the-alien-club/eslint-plugin-nitpicker/issues\"\n },\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org/\",\n \"access\": \"public\",\n \"tag\": \"latest\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"default\": \"./dist/index.js\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"lint\": \"biome check\",\n \"lint:fix\": \"biome check --fix && biome format --write\",\n \"lint:nitpicker\": \"eslint \\\"src/**/*.ts\\\" \\\"tests/**/*.ts\\\"\",\n \"typecheck\": \"tsc --noEmit\",\n \"pretest\": \"node -e \\\"require('node:fs').rmSync('node_modules/.vite', { recursive: true, force: true })\\\"\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"peerDependencies\": {\n \"eslint\": \">=9.0.0\"\n },\n \"dependencies\": {\n \"@typescript-eslint/utils\": \"^8.18.0\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.5.2\",\n \"@types/node\": \"^24.12.2\",\n \"@typescript-eslint/parser\": \"^8.64.0\",\n \"eslint\": \"^9.17.0\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.8.3\",\n \"vitest\": \"^4.1.5\"\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { buildConfigs } from \"@/configs\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { rules } from \"@/rules\"\n\n// Import the version from package.json to include in the plugin metadata\nimport { version } from \"../package.json\"\n\n/**\n * Main declaration of the `@alien_intelligence/eslint-plugin-nitpicker` plugin.\n */\nconst plugin: TSESLint.FlatConfig.Plugin = {\n meta: {\n name: `eslint-plugin-${CONSTANTS.PLUGIN_NAME}`,\n version,\n },\n rules,\n configs: {},\n}\n\n// Configs reference the plugin, so they are attached after it is created\nplugin.configs = buildConfigs(plugin)\n\nexport default plugin\n"]}
package/package.json CHANGED
@@ -1,76 +1,77 @@
1
1
  {
2
- "name": "@alien_intelligence/eslint-plugin-nitpicker",
3
- "productName": "Nitpicker",
4
- "version": "0.1.0",
5
- "description": "A hyper-pedantic ESLint plugin that flags every stylistic and semantic nit, with AI-friendly fix context.",
6
- "author": "Alien <contact@alien.club> (https://www.alien.club/)",
7
- "license": "MIT",
8
- "private": false,
9
- "packageManager": "npm@11.4.2",
10
- "type": "module",
11
- "keywords": [
12
- "alien",
13
- "eslint",
14
- "eslintplugin",
15
- "eslint-plugin",
16
- "nitpicker",
17
- "linting",
18
- "code-style",
19
- "ai"
20
- ],
21
- "homepage": "https://github.com/the-alien-club/eslint-plugin-nitpicker",
22
- "repository": {
23
- "type": "git",
24
- "url": "git+https://github.com/the-alien-club/eslint-plugin-nitpicker.git"
25
- },
26
- "bugs": {
27
- "url": "https://github.com/the-alien-club/eslint-plugin-nitpicker/issues"
28
- },
29
- "publishConfig": {
30
- "registry": "https://registry.npmjs.org/",
31
- "access": "public",
32
- "tag": "latest"
33
- },
34
- "engines": {
35
- "node": ">=20.0.0"
36
- },
37
- "files": [
38
- "dist",
39
- "README.md",
40
- "LICENSE"
41
- ],
42
- "main": "./dist/index.js",
43
- "module": "./dist/index.js",
44
- "types": "./dist/index.d.ts",
45
- "exports": {
46
- ".": {
47
- "types": "./dist/index.d.ts",
48
- "import": "./dist/index.js",
49
- "default": "./dist/index.js"
50
- }
51
- },
52
- "scripts": {
53
- "build": "tsup",
54
- "lint": "biome check",
55
- "lint:fix": "biome check --fix && biome format --write",
56
- "lint:nitpicker": "eslint \"src/**/*.ts\" \"tests/**/*.ts\"",
57
- "typecheck": "tsc --noEmit",
58
- "test": "vitest run",
59
- "test:watch": "vitest"
60
- },
61
- "peerDependencies": {
62
- "eslint": ">=9.0.0"
63
- },
64
- "dependencies": {
65
- "@typescript-eslint/utils": "^8.18.0"
66
- },
67
- "devDependencies": {
68
- "@biomejs/biome": "^2.5.2",
69
- "@types/node": "^24.12.2",
70
- "@typescript-eslint/parser": "^8.64.0",
71
- "eslint": "^9.17.0",
72
- "tsup": "^8.5.1",
73
- "typescript": "^5.8.3",
74
- "vitest": "^4.1.5"
2
+ "name": "@alien_intelligence/eslint-plugin-nitpicker",
3
+ "productName": "Nitpicker",
4
+ "version": "0.2.0",
5
+ "description": "A hyper-pedantic ESLint plugin that flags every stylistic and semantic nit, with AI-friendly fix context.",
6
+ "author": "Alien <contact@alien.club> (https://www.alien.club/)",
7
+ "license": "MIT",
8
+ "private": false,
9
+ "packageManager": "npm@11.4.2",
10
+ "type": "module",
11
+ "keywords": [
12
+ "alien",
13
+ "eslint",
14
+ "eslintplugin",
15
+ "eslint-plugin",
16
+ "nitpicker",
17
+ "linting",
18
+ "code-style",
19
+ "ai"
20
+ ],
21
+ "homepage": "https://github.com/the-alien-club/eslint-plugin-nitpicker",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/the-alien-club/eslint-plugin-nitpicker.git"
25
+ },
26
+ "bugs": {
27
+ "url": "https://github.com/the-alien-club/eslint-plugin-nitpicker/issues"
28
+ },
29
+ "publishConfig": {
30
+ "registry": "https://registry.npmjs.org/",
31
+ "access": "public",
32
+ "tag": "latest"
33
+ },
34
+ "engines": {
35
+ "node": ">=20.0.0"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "main": "./dist/index.js",
43
+ "module": "./dist/index.js",
44
+ "types": "./dist/index.d.ts",
45
+ "exports": {
46
+ ".": {
47
+ "types": "./dist/index.d.ts",
48
+ "import": "./dist/index.js",
49
+ "default": "./dist/index.js"
75
50
  }
51
+ },
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "lint": "biome check",
55
+ "lint:fix": "biome check --fix && biome format --write",
56
+ "lint:nitpicker": "eslint \"src/**/*.ts\" \"tests/**/*.ts\"",
57
+ "typecheck": "tsc --noEmit",
58
+ "pretest": "node -e \"require('node:fs').rmSync('node_modules/.vite', { recursive: true, force: true })\"",
59
+ "test": "vitest run",
60
+ "test:watch": "vitest"
61
+ },
62
+ "peerDependencies": {
63
+ "eslint": ">=9.0.0"
64
+ },
65
+ "dependencies": {
66
+ "@typescript-eslint/utils": "^8.18.0"
67
+ },
68
+ "devDependencies": {
69
+ "@biomejs/biome": "^2.5.2",
70
+ "@types/node": "^24.12.2",
71
+ "@typescript-eslint/parser": "^8.64.0",
72
+ "eslint": "^9.17.0",
73
+ "tsup": "^8.5.1",
74
+ "typescript": "^5.8.3",
75
+ "vitest": "^4.1.5"
76
+ }
76
77
  }