@alien_intelligence/eslint-plugin-nitpicker 0.3.0 → 0.5.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 +31 -1
- package/dist/index.js +10 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -78,7 +78,8 @@ Every rule is part of `recommended` and enabled as a warning. The Fixable column
|
|
|
78
78
|
| `nitpicker/no-decorative-comment-separators` | | Disallow decorative separators (banners, box-drawing, repeated dashes) inside comments. |
|
|
79
79
|
| `nitpicker/no-em-dash` | | Disallow the em dash character anywhere in the source. |
|
|
80
80
|
| `nitpicker/no-jsdoc-blank-before-tags` | yes | Disallow blank lines before JSDoc tags such as `@param` or `@returns`. |
|
|
81
|
-
| `nitpicker/no-line-comment-
|
|
81
|
+
| `nitpicker/no-line-comment-backticks` | yes | Disallow backticks in `//` line comments, rewriting code references with double quotes. |
|
|
82
|
+
| `nitpicker/no-line-comment-period` | yes | Disallow prose periods in `//` line comments (code dots, quoted spans, ellipses, `e.g.` are OK). |
|
|
82
83
|
| `nitpicker/no-property-access-alias` | | Disallow a `const` whose whole value is a single property access; inline the expression instead. |
|
|
83
84
|
| `nitpicker/no-single-line-jsdoc` | yes | Require JSDoc comments to span multiple lines rather than a single line. |
|
|
84
85
|
| `nitpicker/require-framework-config` | | Warn when a file uses a framework whose Nitpicker config is not enabled. |
|
|
@@ -112,6 +113,35 @@ A few rules accept options. Pass them by overriding the rule with a `["warn", {
|
|
|
112
113
|
"nitpicker/require-framework-config": ["warn", { ignore: ["react"] }],
|
|
113
114
|
```
|
|
114
115
|
|
|
116
|
+
`no-em-dash` takes `{ allow: ("strings" | "templates" | "jsx" | "comments")[] }`, the places an em dash is deliberate rather than AI residue, such as user-facing copy, prompt text, or a glyph standing in for an empty value. It defaults to `[]`, i.e. an em dash is reported anywhere. Scope it to the files that hold copy rather than enabling it globally:
|
|
117
|
+
```js
|
|
118
|
+
{
|
|
119
|
+
files: ["app/legal/**/*.tsx", "app/prompts/**/*.ts"],
|
|
120
|
+
rules: {
|
|
121
|
+
"nitpicker/no-em-dash": ["warn", { allow: ["strings", "templates", "jsx"] }],
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Line comment code references
|
|
127
|
+
A backtick renders as code inside a JSDoc block, but in a `//` comment it is just a literal character, so `no-line-comment-backticks` rewrites those references with double quotes:
|
|
128
|
+
```js
|
|
129
|
+
// Reads `auth.user` from the context -> // Reads "auth.user" from the context
|
|
130
|
+
```
|
|
131
|
+
Backticks are left alone in JSDoc and block comments, in tooling directives, when unpaired, in a run (a ```` ``` ```` fence), and when the span already holds a double quote, since `` `split(".")` `` cannot be requoted without nesting.
|
|
132
|
+
|
|
133
|
+
### Line comment periods
|
|
134
|
+
`no-line-comment-period` only treats a dot as prose when whitespace or the end of the comment follows it, so dots inside code (`foo.bar`, `subagent.*`, `split(".")`), inside a quoted or back-ticked span, in an ellipsis, or closing an abbreviation (`e.g.`, `i.e.`, `etc.`) are left alone.
|
|
135
|
+
|
|
136
|
+
The two prose cases are fixed differently, since removing a period is only safe at the end of a comment:
|
|
137
|
+
```js
|
|
138
|
+
// Reads the token. -> // Reads the token
|
|
139
|
+
// Reads the token. It is cached -> // Reads the token
|
|
140
|
+
// // It is cached
|
|
141
|
+
const a = 1 // Reads the token. Cached -> reported, not fixed
|
|
142
|
+
```
|
|
143
|
+
A mid-comment period is split onto its own line rather than deleted, which would leave a run-on. A trailing comment is reported without a fix, as splitting it would break the line it sits on.
|
|
144
|
+
|
|
115
145
|
## Framework configs
|
|
116
146
|
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
147
|
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {ESLintUtils,ASTUtils}from'@typescript-eslint/utils';var
|
|
2
|
-
- why: ${
|
|
3
|
-
- fix: ${i}`}function
|
|
4
|
-
`)){let r=i.replace(/^\s*\*? ?/,"").trimEnd();if(r.startsWith("@"))break;
|
|
5
|
-
`);for(let
|
|
1
|
+
import {ESLintUtils,ASTUtils}from'@typescript-eslint/utils';var st={PLUGIN_NAME:"nitpicker",REPO_URL:"https://github.com/the-alien-club/eslint-plugin-nitpicker",EM_DASH:"\u2014",EMOJI:new RegExp("\\p{Regional_Indicator}\\p{Regional_Indicator}|\\p{Emoji_Presentation}(?:\\uFE0F|\\p{Emoji_Modifier})?(?:\\u200D\\p{Emoji_Presentation}(?:\\uFE0F|\\p{Emoji_Modifier})?)*|\\p{Extended_Pictographic}\\uFE0F","gu"),COMMENTS:{BOX_DRAWING:/[─-▟]/,PURE_SEPARATOR:/^[-=~*#_+]{3,}$/,WRAPPED_LABEL:/^[-=~*#_+]{2,}\s.*\s[-=~*#_+]{2,}$/,DIRECTIVE:/^\s*(?:eslint\b|eslint-|globals?\b|exported\b|jshint\b|jslint\b|istanbul\b|[cv]8\b|ts-|prettier-ignore|biome-ignore|webpack\b|noinspection\b|@)/,QUOTES:new Set(['"',"`"]),ABBREVIATIONS:["e.g.","i.e.","etc.","vs.","cf.","al.","approx.","resp."]},JSDOC:{TAG:/^\s*\*?\s*@(\w+)/},WORDS:{WORD_CHAR:/[\p{L}\p{N}_$]/u,SUB_WORD:/[A-Z]+(?![a-z])|[A-Z][a-z]+|[a-z]+/g},OBJECTS:{MAX_INLINE_KEYS:2,INDENT_WIDTH:4},FUNCTIONS:{NODE_TYPES:new Set(["FunctionDeclaration","FunctionExpression","ArrowFunctionExpression"])},FRAMEWORKS:{ADONIS_SUBPATH:/^#(models|controllers|services|middleware|validators|policies|config|start|database|providers|lib)\b/,REACT_FILE:/\.[jt]sx$/},REACT:{HOOK:/^use[A-Z]/,CONTEXT_HOOK:/^use[A-Z]\w*Context$/},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"]}},a=st;var ie=ESLintUtils.RuleCreator(e=>`${a.REPO_URL}/blob/main/docs/rules/${e}.md`);var u=class{toRuleModule(){return ie({name:this.name,meta:this.meta,defaultOptions:this.defaultOptions,create:(t,i)=>this.create(t,i)})}};function m({problem:e,why:t,fix:i}){return `${e}
|
|
2
|
+
- why: ${t}
|
|
3
|
+
- fix: ${i}`}function re(e){return e.parent.type==="ExportDefaultDeclaration"&&e.superClass?.type==="Identifier"&&e.superClass.name==="BaseSchema"}function ne(e){if(e.callee.type!=="MemberExpression"||e.callee.property.type!=="Identifier"||e.callee.property.name!=="createTable"||e.callee.object.type!=="MemberExpression"||e.callee.object.property.type!=="Identifier"||e.callee.object.property.name!=="schema")return null;let t=e.arguments.at(-1);return t?.type!=="ArrowFunctionExpression"&&t?.type!=="FunctionExpression"||t.body.type!=="BlockStatement"||t.params[0]?.type!=="Identifier"?null:{body:t.body.body,builderName:t.params[0].name}}function oe(e,t){if(e.type!=="ExpressionStatement")return null;let i=lt(e.expression,t);return i===null?null:a.MIGRATIONS.INDEX_METHODS.has(i.method)?"index":i.method==="timestamps"?"timestamp":a.MIGRATIONS.TIMESTAMP_METHODS.has(i.method)?i.firstArgument!==void 0&&a.MIGRATIONS.AUDIT_TIMESTAMPS.has(i.firstArgument)?"timestamp":null:"column"}function lt(e,t){let i=e;for(;i.type==="CallExpression"&&i.callee.type==="MemberExpression";){if(i.callee.object.type==="Identifier"&&i.callee.object.name===t){if(i.callee.property.type!=="Identifier")return null;let r=i.arguments[0],o=r?.type==="Literal"&&typeof r.value=="string"?r.value:void 0;return {method:i.callee.property.name,firstArgument:o}}i=i.callee.object;}return null}var N=class extends u{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(t){return {CallExpression(i){let r=ne(i);if(r===null)return;let o=0;for(let n of r.body){let s=oe(n,r.builderName);if(s===null)continue;let l=a.MIGRATIONS.CATEGORY_ORDER.indexOf(s);l<o&&t.report({node:n,messageId:"outOfOrder",data:{category:s}}),o=Math.max(o,l);}}}}},se=new N;function ae(e){return e.parent.type==="ExportDefaultDeclaration"&&e.id?.name.endsWith("Controller")===true}function g(e){return e.type==="Block"&&e.value.startsWith("*")}function ct(e){let t=(e.type==="ExportDefaultDeclaration"||e.type==="ExportNamedDeclaration")&&e.declaration!==null?e.declaration:e,r=("decorators"in t?t.decorators:void 0)?.reduce((o,n)=>o===void 0||n.range[0]<o.range[0]?n:o,void 0);return r!==void 0&&r.range[0]<e.range[0]?r:e}function S(e,t){let r=e.getCommentsBefore(ct(t)).at(-1);return r!==void 0&&g(r)}function D(e){return /^\s*\*\s*$/.test(e)}function le(e){return e.match(a.JSDOC.TAG)?.[1]??null}function k(e){return le(e)!==null}function ce(e){let t=[];for(let i of e.value.split(`
|
|
4
|
+
`)){let r=i.replace(/^\s*\*? ?/,"").trimEnd();if(r.startsWith("@"))break;t.push(r);}return t.join(" ").replace(/\s+/g," ").trim()}function pe(e,t){let i=-1;for(let o=t.loc.start.line+1;o<t.loc.end.line;o++){let n=le(e.lines[o-1]??"");if(n==="returns"||n==="return"){i=o;break}}if(i===-1)return null;let r=t.loc.end.line-1;for(let o=i+1;o<t.loc.end.line;o++)if(k(e.lines[o-1]??"")){r=o-1;break}return {from:i,to:r}}var w=class extends u{name="require-controller-jsdoc";defaultOptions=[];meta={type:"suggestion",docs:{description:"Require a JSDoc comment describing an AdonisJS controller.",recommended:true,category:"adonisjs"},schema:[],messages:{missingJSDoc:m({problem:"This controller has no JSDoc describing what it does.",why:"A controller's responsibility should be readable at a glance, before diving into its handler methods",fix:"Add a `/** ... */` JSDoc above the controller class summarizing what it handles"})}};create(t){return {ClassDeclaration(i){ae(i)&&(S(t.sourceCode,i.parent)||t.report({node:i.id??i,messageId:"missingJSDoc"}));}}}},ue=new w;var M=class extends u{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(t){return {ClassDeclaration(i){re(i)&&(S(t.sourceCode,i.parent)||t.report({node:i.id??i,messageId:"missingJSDoc"}));}}}},me=new M;var de=250,A=class extends u{name="max-jsdoc-description-length";defaultOptions=[{max:de}];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(t,i){let r=i[0]?.max??de;return {Program(){for(let o of t.sourceCode.getAllComments()){if(!g(o))continue;let n=ce(o).length;n<=r||t.report({loc:o.loc,messageId:"tooLong",data:{length:n,max:r}});}}}}},fe=new A;function R(e){let t=[],i=e;for(;;){if(i.type==="ChainExpression"||i.type==="TSNonNullExpression"){i=i.expression;continue}if(i.type==="MemberExpression"){if(i.computed||i.property.type!=="Identifier")return null;t.unshift(i.property.name),i=i.object;continue}break}return t.length===0?null:i.type==="ThisExpression"?["this",...t].join("."):i.type==="Identifier"?[i.name,...t].join("."):null}function ge(e){return R(e)!==null}function O(e,t){let i=ASTUtils.findVariable(e,t);if(i===null)return false;let r=new Set(i.defs.map(o=>o.name));return i.references.some(o=>o.isWrite()&&!r.has(o.identifier))}function ye(e,t){for(let i of e)if(t===i||t.startsWith(`${i}.`))return true;return false}function Se(e){return e.properties.length===0?false:e.properties.every(t=>t.type==="Property"&&t.shorthand&&!t.computed&&t.value.type==="Identifier")}var v=class extends u{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(t){return {VariableDeclarator(i){i.parent.type!=="VariableDeclaration"||i.parent.kind!=="const"||i.parent.parent.type!=="ExportNamedDeclaration"&&(i.id.type!=="Identifier"||i.init?.type!=="Identifier"||i.id.typeAnnotation===void 0&&(O(t.sourceCode.getScope(i),i.init.name)||t.report({node:i,messageId:"alias",data:{name:i.id.name,source:i.init.name}})));}}}},he=new v;var Te={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",initialises:"initializes",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 be(e,t,i){let r=Object.create(null);for(let[o,n]of Object.entries(e))r[o.toLowerCase()]=n;for(let[o,n]of Object.entries(t))r[o.toLowerCase()]=n;for(let o of i)delete r[o.toLowerCase()];return r}function F(e){let t=[];for(let i of e.matchAll(a.WORDS.SUB_WORD))i.index!==void 0&&t.push({text:i[0],index:i.index});return t}function j(e,t){return e===e.toUpperCase()?t.toUpperCase():e.charAt(0)===e.charAt(0).toUpperCase()?t.charAt(0).toUpperCase()+t.slice(1):t}function Ee(e){return e!==void 0&&a.WORDS.WORD_CHAR.test(e)}var P=class extends u{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(t,i){let r=be(Te,i[0]?.extra??{},i[0]?.ignore??[]);return {Identifier(o){if(!(o.parent.type==="MemberExpression"&&o.parent.property===o&&!o.parent.computed))for(let n of F(o.name)){let s=r[n.text.toLowerCase()];s!==void 0&&t.report({node:o,messageId:"british",data:{british:n.text,american:j(n.text,s)}});}},Program(){for(let o of t.sourceCode.getAllComments())for(let n of F(o.value)){let s=r[n.text.toLowerCase()];if(s===void 0)continue;let l=j(n.text,s),d=o.range[0]+2+n.index,f=d+n.text.length;t.report({loc:{start:t.sourceCode.getLocFromIndex(d),end:t.sourceCode.getLocFromIndex(f)},messageId:"british",data:{british:n.text,american:l},fix:b=>b.replaceTextRange([d,f],l)});}}}}},xe=new P;function Re(e){let t=e.replace(/^\s*\*?\s*/,"").trimEnd();return t.length===0?false:a.COMMENTS.BOX_DRAWING.test(t)||a.COMMENTS.PURE_SEPARATOR.test(t)||a.COMMENTS.WRAPPED_LABEL.test(t)}function ut(e){let t=e.replace(/\\/g,"/"),i="^";for(let r=0;r<t.length;r++){let o=t[r];if(o===void 0)break;o==="*"?t[r+1]==="*"?(i+=".*",r++,t[r+1]==="/"&&r++):i+="[^/]*":"\\^$.|?+()[]{}".includes(o)?i+=`\\${o}`:i+=o;}return new RegExp(`${i}$`)}function Oe(e,t){let i=e.replace(/\\/g,"/");return t.some(r=>ut(r).test(i))}var _=class extends u{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(t,i){let r=i[0]?.allowIn??[];return r.length>0&&Oe(t.filename,r)?{}:{Program(){for(let o of t.sourceCode.getAllComments()){let n=o.value.split(`
|
|
5
|
+
`);for(let s=0;s<n.length;s++){let l=n[s];if(l===void 0||!Re(l))continue;let d=o.loc.start.line+s,f=t.sourceCode.lines[d-1]??"";t.report({loc:{start:{line:d,column:0},end:{line:d,column:f.length}},messageId:"decorative"});}}}}}},Ce=new _;var mt={strings:"String",templates:"Template",jsx:"JSXText"},J=class extends u{name="no-em-dash";defaultOptions=[{allow:[]}];meta={type:"suggestion",docs:{description:"Disallow the em dash (\u2014) character anywhere in the source.",recommended:true},schema:[{type:"object",properties:{allow:{type:"array",items:{type:"string",enum:["strings","templates","jsx","comments"]}}},additionalProperties:false}],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, or allow it here with the rule's `allow` option if it is deliberate user-facing copy."})}};create(t,i){let r=new Set(i[0]?.allow??[]),o=()=>{let n=[];if(r.size===0)return n;let s=new Set([...r].map(l=>mt[l]).filter(l=>l!==void 0));for(let l of t.sourceCode.ast.tokens??[])s.has(l.type)&&n.push(l.range);if(r.has("comments"))for(let l of t.sourceCode.getAllComments())n.push(l.range);return n};return {Program(){let n=t.sourceCode.getText(),s=o();for(let l=0;l<n.length;l++)n[l]===a.EM_DASH&&(s.some(([d,f])=>l>=d&&l<f)||t.report({loc:{start:t.sourceCode.getLocFromIndex(l),end:t.sourceCode.getLocFromIndex(l+1)},messageId:"emDash"}));}}}},Le=new J;var z=class extends u{name="no-emojis";defaultOptions=[];meta={type:"suggestion",fixable:"code",docs:{description:"Disallow emoji characters anywhere in the source.",recommended:true,category:"base"},schema:[],messages:{emoji:m({problem:"Found an emoji ({{emoji}}).",why:"Emojis are usually introduced by AI-generated text and add noise to code, comments, and identifiers",fix:"Discard the emoji"})}};create(t){let i=t.sourceCode.getText();return {Program(){for(let r of i.matchAll(a.EMOJI)){let o=r[0],n=r.index+o.length;t.report({loc:{start:t.sourceCode.getLocFromIndex(r.index),end:t.sourceCode.getLocFromIndex(n)},messageId:"emoji",data:{emoji:o},fix:s=>s.removeRange([r.index,n])});}}}}},Ie=new z;var B=class extends u{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(t){return {Program(){for(let i of t.sourceCode.getAllComments())if(g(i)&&i.loc.start.line!==i.loc.end.line)for(let r=i.loc.start.line;r<=i.loc.end.line;r++){let o=t.sourceCode.lines[r-1];if(o===void 0||!D(o))continue;let n=r;for(;n<i.loc.end.line&&D(t.sourceCode.lines[n]??"");)n++;let s=t.sourceCode.lines[n];if(s!==void 0&&k(s)){let l=t.sourceCode.getIndexFromLoc({line:r,column:0}),d=t.sourceCode.getIndexFromLoc({line:n+1,column:0});t.report({loc:{start:{line:r,column:0},end:{line:n,column:o.length}},messageId:"blankBeforeTag",fix:f=>f.removeRange([l,d])});}r=n;}}}}},Ne=new B;function E(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 De(e){return e.parent?.type==="Program"}function C(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}function h(e,t,i){if(e.type==="ReturnStatement")return i(e.argument);for(let r of t[e.type]??[]){let o=e[r],n=Array.isArray(o)?o:[o];for(let s of n){let l=s;if(!(!l||typeof l.type!="string")&&!a.FUNCTIONS.NODE_TYPES.has(l.type)&&h(l,t,i))return true}}return false}function dt(e,t){return e.type==="ArrowFunctionExpression"&&e.body.type!=="BlockStatement"?true:h(e.body,t,i=>i!==null)}function ft(e){return e.typeAnnotation.type==="TSVoidKeyword"?true:e.typeAnnotation.type==="TSTypeReference"&&e.typeAnnotation.typeName.type==="Identifier"&&e.typeAnnotation.typeName.name==="Promise"?e.typeAnnotation.typeArguments?.params.length===1&&e.typeAnnotation.typeArguments?.params[0]?.type==="TSVoidKeyword":false}function ke(e,t){return e.returnType?ft(e.returnType):!dt(e,t)}var U=class extends u{name="no-jsdoc-returns-on-void";defaultOptions=[];meta={type:"suggestion",fixable:"code",docs:{description:"Disallow a JSDoc `@returns` tag on a function that returns nothing.",recommended:true,category:"base"},schema:[],messages:{voidReturns:m({problem:"This function returns nothing, but its JSDoc has a `@returns` tag.",why:"A `@returns` on a void function documents a value that never exists and drifts from the code",fix:"Remove the `@returns` tag"})}};create(t){let i=(r,o)=>{let n=t.sourceCode.getCommentsBefore(o).at(-1);if(n===void 0||!g(n))return;let s=pe(t.sourceCode,n);if(s===null||!ke(r,t.sourceCode.visitorKeys))return;let l=t.sourceCode.getIndexFromLoc({line:s.from,column:0}),d=t.sourceCode.getIndexFromLoc({line:s.to+1,column:0});t.report({loc:{start:{line:s.from,column:0},end:{line:s.to,column:(t.sourceCode.lines[s.to-1]??"").length}},messageId:"voidReturns",fix:f=>f.removeRange([l,d])});};return {FunctionDeclaration(r){i(r,E(r));},VariableDeclarator(r){(r.init?.type==="ArrowFunctionExpression"||r.init?.type==="FunctionExpression")&&i(r.init,E(r.init));},MethodDefinition(r){r.value.type==="FunctionExpression"&&i(r.value,r);}}}},we=new U;function L(e){return a.COMMENTS.DIRECTIVE.test(e.value)}function Me(e){let t=e.range[0]+2;if(e.type==="Line"){let r=e.value.match(/\S/u);return r?.index===void 0?null:{index:t+r.index,char:r[0]}}let i=0;for(let r of e.value.split(`
|
|
6
|
+
`)){let o=(r.match(/^\s*\*?\s*/u)?.[0]??"").length,n=r.slice(o).charAt(0);if(n!=="")return {index:t+i+o,char:n};i+=r.length+1;}return null}function Ae(e){let t=[],i=e.range[0]+2,r=null;for(let o=0;o<e.value.length;o++){let n=e.value.charAt(o);if(r!==null){n===r&&(r=null);continue}if(a.COMMENTS.QUOTES.has(n)&&e.value.includes(n,o+1)){r=n;continue}if(n!==".")continue;if(e.value.charAt(o+1)==="."){for(;e.value.charAt(o+1)===".";)o++;continue}let s=e.value.slice(o+1);s!==""&&!/^\s/u.test(s)||gt(e.value.slice(0,o+1))||t.push({index:i+o,terminal:s.trim()===""});}return t}function ve(e){let t=[],i=e.range[0]+2;for(let r=0;r<e.value.length;r++){if(e.value.charAt(r)!=="`")continue;if(e.value.charAt(r+1)==="`"){for(;e.value.charAt(r+1)==="`";)r++;continue}let o=e.value.indexOf("`",r+1);if(o===-1)break;let n=e.value.slice(r+1,o);n.includes('"')||t.push({start:i+r,end:i+o,text:n}),r=o;}return t}function gt(e){let t=e.toLowerCase();return a.COMMENTS.ABBREVIATIONS.some(i=>{if(!t.endsWith(i))return false;let r=t.charAt(t.length-i.length-1);return r===""||!Ee(r)})}var W=class extends u{name="no-line-comment-backticks";defaultOptions=[];meta={type:"suggestion",fixable:"code",docs:{description:"Disallow backticks in `//` line comments, use double quotes for code references.",recommended:true,category:"base"},schema:[],messages:{backticks:m({problem:"This line comment wraps `{{text}}` in backticks.",why:"Backticks only render as code inside a JSDoc block, in a `//` comment they stay literal characters, so double quotes read better",fix:'Wrap it in double quotes instead: "{{text}}"'})}};create(t){return {Program(){for(let i of t.sourceCode.getAllComments())if(!(i.type!=="Line"||L(i)))for(let r of ve(i))t.report({loc:{start:t.sourceCode.getLocFromIndex(r.start),end:t.sourceCode.getLocFromIndex(r.end+1)},messageId:"backticks",data:{text:r.text},fix:o=>[o.replaceTextRange([r.start,r.start+1],'"'),o.replaceTextRange([r.end,r.end+1],'"')]});}}}},Fe=new W;var $=class extends u{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 ends with a period.",why:"Line comments should be short, clear fragments, not full sentences, so a closing period is just noise, dots inside code references like `foo.bar` are allowed.",fix:"Remove the period and keep the comment terse."}),sentence:m({problem:"This line comment runs two sentences together with a period.",why:"Line comments should be short, clear fragments, dropping the period on its own would leave a run-on, so the sentences belong on separate lines",fix:"Split it into one `//` line per fragment, or reword it as a single fragment"})}};create(t){let i=r=>{let o=(t.sourceCode.lines[r.loc.start.line-1]??"").slice(0,r.loc.start.column);return o.trim()===""?o:null};return {Program(){for(let r of t.sourceCode.getAllComments()){if(r.type!=="Line")continue;let o=i(r);for(let n of Ae(r)){let s={start:t.sourceCode.getLocFromIndex(n.index),end:t.sourceCode.getLocFromIndex(n.index+1)};if(n.terminal){t.report({loc:s,messageId:"period",fix:b=>b.removeRange([n.index,n.index+1])});continue}let l=n.index-r.range[0]-2,d=r.value.slice(l+1).match(/^\s*/u)?.[0]??"",f=n.index+1+d.length;t.report({loc:s,messageId:"sentence",fix:o===null?null:b=>b.replaceTextRange([n.index,f],`
|
|
7
|
+
${o}// `)});}}}}}},je=new $;var V=class extends u{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(t){let i=[],r=new Set,o=n=>{if(n.type!=="MemberExpression")return;let s=R(n);s!==null&&r.add(s);};return {AssignmentExpression(n){o(n.left);},UpdateExpression(n){o(n.argument);},VariableDeclarator(n){if(n.parent.type!=="VariableDeclaration"||n.parent.kind!=="const"||n.parent.parent.type==="ExportNamedDeclaration"||n.id.type!=="Identifier"||n.init===null||n.id.typeAnnotation!==void 0)return;let s=R(n.init);if(s===null)return;let l=s.slice(0,s.indexOf("."));l!=="this"&&O(t.sourceCode.getScope(n),l)||i.push({node:n,name:n.id.name,path:s,expression:t.sourceCode.getText(n.init)});},"Program:exit"(){for(let n of i)ye(r,n.path)||t.report({node:n.node,messageId:"propertyAccessAlias",data:{name:n.name,expression:n.expression}});}}}},Pe=new V;var G=class extends u{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(t){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"&&!ge(i.init)||Se(i.id)&&t.report({node:i,messageId:"destructure",data:{source:t.sourceCode.getText(i.init)}}));}}}},_e=new G;var K=class extends u{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(t){return {Program(){for(let i of t.sourceCode.getAllComments()){if(!g(i)||i.loc.start.line!==i.loc.end.line)continue;let r=i.value.replace(/^\*/,"").trim();r.length!==0&&t.report({loc:i.loc,messageId:"singleLine",fix(o){let n=" ".repeat(i.loc.start.column),s=`/**
|
|
6
8
|
${n} * ${r}
|
|
7
|
-
${n} */`;return o.replaceTextRange(i.range,a)}});}}}}},
|
|
8
|
-
${
|
|
9
|
+
${n} */`;return o.replaceTextRange(i.range,s)}});}}}}},Je=new K;var q=class extends u{name="require-capitalized-comments";defaultOptions=[];meta={type:"suggestion",fixable:"code",docs:{description:"Require a comment to start with an uppercase letter.",recommended:true,category:"base"},schema:[],messages:{capitalize:m({problem:"This comment starts with a lowercase letter.",why:"A comment reads as a sentence, and a sentence starts with a capital letter",fix:"Capitalize the first letter of the comment"})}};create(t){let i=r=>{if(r.type!=="Line")return false;let o=t.sourceCode.lines[r.loc.start.line-2];return o!==void 0&&/^\s*\/\//.test(o)};return {Program(){for(let r of t.sourceCode.getAllComments()){if(L(r)||i(r))continue;let o=Me(r);o===null||!new RegExp("\\p{Ll}","u").test(o.char)||/^(?:https?:\/\/|www\.)/u.test(t.sourceCode.getText().slice(o.index))||t.report({loc:{start:t.sourceCode.getLocFromIndex(o.index),end:t.sourceCode.getLocFromIndex(o.index+o.char.length)},messageId:"capitalize",fix:n=>n.replaceTextRange([o.index,o.index+o.char.length],o.char.toUpperCase())});}}}}},ze=new q;var Be={adonisjs:"AdonisJS",react:"React"};function yt(e){let t=[];for(let i of e.ast.body)i.type==="ImportDeclaration"&&t.push(String(i.source.value));return t}function Ue(e,t){let i=new Set,r=yt(e);return r.some(n=>n.startsWith("@adonisjs/")||a.FRAMEWORKS.ADONIS_SUBPATH.test(n))&&i.add("adonisjs"),(r.some(n=>n==="react"||n.startsWith("react/")||n==="react-dom")||a.FRAMEWORKS.REACT_FILE.test(t))&&i.add("react"),i}var H=class extends u{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(t,i){let r=new Set(i[0]?.ignore??[]),o=t.settings[a.PLUGIN_NAME]??{};return {Program(n){let s=Ue(t.sourceCode,t.filename);for(let l of s)r.has(l)||o[l]||t.report({node:n,messageId:"missingConfig",data:{framework:Be[l],config:l}});}}}},We=new H;function $e(e){return /^[A-Z]/.test(e)}function Ve(e){return a.REACT.HOOK.test(e)}function Ge(e){return a.REACT.CONTEXT_HOOK.test(e)}function X(e){return e?e.type==="ArrowFunctionExpression"||e.type==="FunctionExpression"?true:e.type==="CallExpression"&&e.callee.type==="Identifier"&&e.callee.name==="useCallback":false}function y(e){if(!e)return false;switch(e.type){case "JSXElement":case "JSXFragment":return true;case "ConditionalExpression":return y(e.consequent)||y(e.alternate);case "LogicalExpression":return y(e.left)||y(e.right);case "SequenceExpression":return y(e.expressions.at(-1));default:return false}}function Ke(e,t){return e.type==="ArrowFunctionExpression"&&e.body.type!=="BlockStatement"?y(e.body):h(e.body,t,y)}var Y=class extends u{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(t){let i=(r,o)=>{let n=C(r);if(n===void 0)return;let s=E(r);De(s)&&($e(n)&&Ke(r,t.sourceCode.visitorKeys)||S(t.sourceCode,s)||t.report({node:o,messageId:"missingJSDoc",data:{name:n}}));};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));}}}},qe=new Y;function He(e,t,i){let o=(e.lines[t.loc.start.line-1]??"").match(/^\s*/)?.[0]??"",n=o+" ".repeat(i);return `{
|
|
10
|
+
${t.properties.map(l=>`${n}${e.getText(l)}`).join(`,
|
|
9
11
|
`)},
|
|
10
|
-
${o}}`}var
|
|
12
|
+
${o}}`}var Z=class extends u{name="require-multiline-object";defaultOptions=[{maxKeys:a.OBJECTS.MAX_INLINE_KEYS,indent:a.OBJECTS.INDENT_WIDTH}];meta={type:"suggestion",fixable:"whitespace",docs:{description:"Require an object literal with more than a few properties to span multiple lines.",recommended:true,category:"base"},schema:[{type:"object",properties:{maxKeys:{type:"integer",minimum:1},indent:{type:"integer",minimum:1}},additionalProperties:false}],messages:{shouldWrap:m({problem:"This object literal has {{count}} properties packed onto a single line.",why:"An object with more than {{max}} properties is easier to scan, diff, and edit when each property sits on its own line",fix:"Break it across multiple lines, one property per line with a trailing comma"})}};create(t,i){let r=i[0]?.maxKeys??a.OBJECTS.MAX_INLINE_KEYS,o=i[0]?.indent??a.OBJECTS.INDENT_WIDTH;return {ObjectExpression(n){n.properties.length<=r||n.loc.start.line===n.loc.end.line&&t.report({node:n,messageId:"shouldWrap",data:{count:n.properties.length,max:r},fix:s=>s.replaceText(n,He(t.sourceCode,n,o))});}}}},Xe=new Z;var Q=class extends u{name="require-context-hook-destructure";defaultOptions=[];meta={type:"suggestion",docs:{description:"Require the result of a context-consumer hook to be destructured.",recommended:true,category:"react"},schema:[],messages:{destructure:m({problem:"`{{hook}}` is bound whole instead of destructured.",why:"Destructuring at the call site names exactly what the caller uses and reads better than repeated `{{name}}.member` access",fix:"Destructure the members in use, e.g. `const { a, b } = {{hook}}()`"})}};create(t){return {VariableDeclarator(i){i.id.type!=="Identifier"||i.init?.type!=="CallExpression"||i.init.callee.type!=="Identifier"||!Ge(i.init.callee.name)||t.report({node:i,messageId:"destructure",data:{hook:i.init.callee.name,name:i.id.name}});}}}},Ye=new Q;var ee=class extends u{name="require-hook-object-return";defaultOptions=[];meta={type:"suggestion",fixable:"code",docs:{description:"Require a custom hook to return an object rather than a bare function.",recommended:true,category:"react"},schema:[],messages:{wrapInObject:m({problem:"This hook returns a bare function instead of an object.",why:"Returning an object lets the hook expose new members later without changing every call site, a bare function locks its shape",fix:"Return the function inside an object, e.g. `return { handleThing }`"})}};create(t){let i=n=>{if(X(n))return true;if(n.type!=="Identifier")return false;let l=ASTUtils.findVariable(t.sourceCode.getScope(n),n.name)?.defs.at(-1)?.node;return l?.type==="VariableDeclarator"&&X(l.init)},r=n=>{t.report({node:n,messageId:"wrapInObject",fix:n.type==="Identifier"?s=>s.replaceText(n,`{ ${n.name} }`):void 0});},o=n=>{let s=C(n);if(!(s===void 0||!Ve(s))){if(n.type==="ArrowFunctionExpression"&&n.body.type!=="BlockStatement"){i(n.body)&&r(n.body);return}h(n.body,t.sourceCode.visitorKeys,l=>(l!==null&&i(l)&&r(l),false));}};return {FunctionDeclaration(n){o(n);},FunctionExpression(n){o(n);},ArrowFunctionExpression(n){o(n);}}}},Ze=new ee;var ht=[se,ue,me,fe,he,xe,Ce,Le,Ie,Ne,we,Fe,je,Pe,_e,Je,ze,We,qe,Xe,Ye,Ze],x=Object.fromEntries(ht.map(e=>[e.name,e.toRuleModule()]));function T(e){let t={};for(let[i,r]of Object.entries(x))(r.meta.docs?.category??"base")===e&&(t[`${a.PLUGIN_NAME}/${i}`]="warn");return t}function Qe(){let e={};for(let t of Object.keys(x))e[`${a.PLUGIN_NAME}/${t}`]="warn";return e}function et(e){return {name:`${a.PLUGIN_NAME}/all`,plugins:{[a.PLUGIN_NAME]:e},settings:{[a.PLUGIN_NAME]:{adonisjs:true,react:true}},rules:Qe()}}function I(e){return {name:`${a.PLUGIN_NAME}/base`,plugins:{[a.PLUGIN_NAME]:e},rules:T("base")}}function tt(e){return {...I(e),name:`${a.PLUGIN_NAME}/recommended`}}var Tt=["**/start/routes.ts","**/start/routes/**/*.ts"];function it(e){return {name:`${a.PLUGIN_NAME}/adonisjs`,plugins:{[a.PLUGIN_NAME]:e},settings:{[a.PLUGIN_NAME]:{adonisjs:true}},rules:{...T("adonisjs"),[`${a.PLUGIN_NAME}/no-decorative-comment-separators`]:["warn",{allowIn:Tt}]}}}function rt(e){return {name:`${a.PLUGIN_NAME}/react`,plugins:{[a.PLUGIN_NAME]:e},settings:{[a.PLUGIN_NAME]:{react:true}},rules:T("react")}}function nt(e){return {base:I(e),recommended:tt(e),adonisjs:it(e),react:rt(e),all:et(e)}}var ot="0.5.0";var te={meta:{name:`eslint-plugin-${a.PLUGIN_NAME}`,version:ot},rules:x,configs:{}};te.configs=nt(te);var zo=te;export{zo as default};//# sourceMappingURL=index.js.map
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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/controllers.ts","../src/lib/utils/jsdocs.ts","../src/rules/adonisjs/requireControllerJSDoc.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/lib/utils/functions.ts","../src/rules/base/noJSDocReturnsOnVoid.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/react.ts","../src/rules/base/requireFunctionJSDoc.ts","../src/lib/utils/objects.ts","../src/rules/base/requireMultilineObject.ts","../src/rules/react/requireContextHookDestructure.ts","../src/rules/react/requireHookObjectReturn.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","isControllerClass","isJSDocComment","comment","hasLeadingJSDoc","sourceCode","closest","isBlankJSDocLine","line","getJSDocLineTag","isJSDocTagLine","getJSDocDescription","parts","content","findJSDocReturnsRange","tagLine","tag","to","RequireControllerJSDoc","requireControllerJSDoc_default","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","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","getDocumentableNode","fn","isTopLevel","getFunctionName","someReturn","visitorKeys","predicate","children","child","childNode","functionReturnsValue","argument","isVoidReturnType","annotation","isVoidFunction","NoJSDocReturnsOnVoid","check","anchor","jsdoc","range","noJSDocReturnsOnVoid_default","NoLineCommentPeriod","valueStart","at","noLineCommentPeriod_default","isPropertyAccessAlias","sawMemberAccess","isAllShorthand","property","NoPropertyAccessAlias","noPropertyAccessAlias_default","NoPropertyDestructuring","noPropertyDestructuring_default","NoSingleLineJSDoc","indent","expanded","noSingleLineJSDoc_default","FRAMEWORK_LABELS","importSources","sources","detectFrameworks","detected","RequireFrameworkConfig","ignored","enabled","framework","requireFrameworkConfig_default","isReactComponentName","isHookName","isContextHookName","isFunctionValue","isJsxExpression","functionReturnsJsx","RequireFunctionJSDoc","reportNode","documentable","requireFunctionJSDoc_default","expandObjectLiteral","baseIndent","propertyIndent","RequireMultilineObject","maxKeys","requireMultilineObject_default","RequireContextHookDestructure","requireContextHookDestructure_default","RequireHookObjectReturn","returnsFunction","declarator","ASTUtils","report","requireHookObjectReturn_default","ruleInstances","rules","rule","categoryRules","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, 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 inspecting JSDoc structure.\n */\n JSDOC: {\n /**\n * Matches a JSDoc block-tag line, capturing the tag name so callers can\n * find any tag (`param`, `returns`, `throws`, etc.).\n */\n TAG: /^\\s*\\*?\\s*@(\\w+)/,\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 object literals.\n */\n OBJECTS: {\n /**\n * The default maximum number of properties an object literal may keep on\n * a single line before it must be broken across multiple lines.\n */\n MAX_INLINE_KEYS: 2,\n\n /**\n * The default number of spaces per indentation level used when expanding\n * an object literal across multiple lines.\n */\n INDENT_WIDTH: 4,\n },\n\n /**\n * Constants for inspecting functions.\n */\n FUNCTIONS: {\n /**\n * The AST node types that introduce a new function scope.\n */\n NODE_TYPES: new Set([\"FunctionDeclaration\", \"FunctionExpression\", \"ArrowFunctionExpression\"]),\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 React semantics.\n */\n REACT: {\n /**\n * A React hook name: `use` followed by a capitalized word, e.g.\n * `useState` or `useMenuActions`.\n */\n HOOK: /^use[A-Z]/,\n\n /**\n * A context-consumer hook name, i.e. a `use…Context` wrapper such as\n * `useTreeViewContext` (the bare `useContext` is excluded).\n */\n CONTEXT_HOOK: /^use[A-Z]\\w*Context$/,\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({\n node: statement,\n messageId: \"outOfOrder\",\n data: { category },\n })\n }\n\n maxRank = Math.max(maxRank, rank)\n }\n },\n }\n }\n}\n\nexport default new MigrationTableOrder()\n","import type { TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Checks whether a class is an AdonisJS controller, i.e. a default-exported\n * class whose name ends with `Controller`.\n * @param node The class declaration to inspect.\n * @returns True if the class is a controller.\n */\nexport function isControllerClass(node: TSESTree.ClassDeclaration): boolean {\n return node.parent.type === \"ExportDefaultDeclaration\" && node.id?.name.endsWith(\"Controller\") === true\n}\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\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 * Resolves the block-tag name a JSDoc line starts with, e.g. `param` or\n * `returns`, or `null` if the line is not a tag line.\n * @param line The physical source line to inspect.\n * @returns The tag name without its `@`, or `null`.\n */\nexport function getJSDocLineTag(line: string): string | null {\n const match = line.match(CONSTANTS.JSDOC.TAG)\n return match?.[1] ?? null\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 getJSDocLineTag(line) !== null\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\n/**\n * Finds the source-line range of a JSDoc comment's `@returns` (or `@return`)\n * block, spanning the tag line down to the line before the next tag or the\n * closing `*/`.\n * @param sourceCode The source code of the linted file.\n * @param comment The JSDoc comment to inspect.\n * @returns The inclusive `from`/`to` source lines, or `null` if there is none.\n */\nexport function findJSDocReturnsRange(\n sourceCode: Readonly<TSESLint.SourceCode>,\n comment: TSESTree.Comment,\n): { from: number; to: number } | null {\n let tagLine = -1\n for (let line = comment.loc.start.line + 1; line < comment.loc.end.line; line++) {\n const tag = getJSDocLineTag(sourceCode.lines[line - 1] ?? \"\")\n if (tag === \"returns\" || tag === \"return\") {\n tagLine = line\n break\n }\n }\n\n if (tagLine === -1) return null\n\n let to = comment.loc.end.line - 1\n for (let line = tagLine + 1; line < comment.loc.end.line; line++) {\n if (isJSDocTagLine(sourceCode.lines[line - 1] ?? \"\")) {\n to = line - 1\n break\n }\n }\n\n return {\n from: tagLine,\n to,\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isControllerClass } from \"@/lib/utils/controllers\"\nimport { hasLeadingJSDoc } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"missingJSDoc\"\n\n/**\n * Requires a JSDoc comment above an AdonisJS controller (a default-exported\n * class whose name ends with `Controller`) so the responsibility it serves is\n * documented at a glance, before diving into its handler methods.\n */\nclass RequireControllerJSDoc extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-controller-jsdoc\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Require a JSDoc comment describing an AdonisJS controller.\",\n recommended: true,\n category: \"adonisjs\",\n },\n schema: [],\n messages: {\n missingJSDoc: nitpick({\n problem: \"This controller has no JSDoc describing what it does.\",\n why: \"A controller's responsibility should be readable at a glance, before diving into its handler methods\",\n fix: \"Add a `/** ... */` JSDoc above the controller class summarizing what it handles\",\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 (!isControllerClass(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 RequireControllerJSDoc()\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 /**\n * A null-prototype object so lookups like `dictionary[\"constructor\"]` return\n * undefined instead of Object.prototype.constructor, which would otherwise\n * treat identifiers such as `BrowserWindowConstructorOptions` as matches.\n */\n const dictionary: Record<string, string> = Object.create(null)\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 { TSESTree } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Any node that introduces a callable function.\n */\nexport type FunctionNode = TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression\n\n/**\n * A lookup of AST node type to the property keys that hold its child nodes.\n */\nexport type VisitorKeys = Record<string, readonly string[] | undefined>\n\n/**\n * Predicate applied to a `return` statement's argument (which is `null` for a\n * bare `return`).\n */\ntype ReturnPredicate = (argument: TSESTree.Expression | null) => boolean\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\n/**\n * Checks whether any `return` in a subtree satisfies a predicate, without\n * crossing into nested functions (whose returns belong to them, not us).\n * @param node The AST node to search from.\n * @param visitorKeys The AST visitor keys, used to walk the subtree.\n * @param predicate The test applied to each `return` argument.\n * @returns True if a matching `return` is found.\n */\nexport function someReturn(node: TSESTree.Node, visitorKeys: VisitorKeys, predicate: ReturnPredicate): boolean {\n if (node.type === \"ReturnStatement\") {\n return predicate(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 if (CONSTANTS.FUNCTIONS.NODE_TYPES.has(childNode.type)) continue\n if (someReturn(childNode, visitorKeys, predicate)) return true\n }\n }\n\n return false\n}\n\n/**\n * Checks whether a function returns a value, i.e. an arrow with an expression\n * body or a body with a non-empty `return`.\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 a value.\n */\nexport function functionReturnsValue(fn: FunctionNode, visitorKeys: VisitorKeys): boolean {\n if (fn.type === \"ArrowFunctionExpression\" && fn.body.type !== \"BlockStatement\") {\n return true\n }\n\n return someReturn(fn.body, visitorKeys, argument => argument !== null)\n}\n\n/**\n * Checks whether a return-type annotation is `void` or `Promise<void>`.\n * @param annotation The return-type annotation to inspect.\n * @returns True if the annotation is a void type.\n */\nexport function isVoidReturnType(annotation: TSESTree.TSTypeAnnotation): boolean {\n if (annotation.typeAnnotation.type === \"TSVoidKeyword\") return true\n\n if (\n annotation.typeAnnotation.type === \"TSTypeReference\" &&\n annotation.typeAnnotation.typeName.type === \"Identifier\" &&\n annotation.typeAnnotation.typeName.name === \"Promise\"\n ) {\n return (\n annotation.typeAnnotation.typeArguments?.params.length === 1 &&\n annotation.typeAnnotation.typeArguments?.params[0]?.type === \"TSVoidKeyword\"\n )\n }\n\n return false\n}\n\n/**\n * Checks whether a function returns nothing, judged by its return-type\n * annotation when present, otherwise by its body.\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 is void.\n */\nexport function isVoidFunction(fn: FunctionNode, visitorKeys: VisitorKeys): boolean {\n if (fn.returnType) {\n return isVoidReturnType(fn.returnType)\n }\n\n return !functionReturnsValue(fn, visitorKeys)\n}\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { type FunctionNode, getDocumentableNode, isVoidFunction } from \"@/lib/utils/functions\"\nimport { findJSDocReturnsRange, isJSDocComment } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"voidReturns\"\n\n/**\n * Flags a `@returns` tag on a function that returns nothing (a void return type,\n * or a body with no `return` or only a bare `return`), and removes it, since it\n * documents a value that never exists.\n */\nclass NoJSDocReturnsOnVoid extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-jsdoc-returns-on-void\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"code\",\n docs: {\n description: \"Disallow a JSDoc `@returns` tag on a function that returns nothing.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n voidReturns: nitpick({\n problem: \"This function returns nothing, but its JSDoc has a `@returns` tag.\",\n why: \"A `@returns` on a void function documents a value that never exists and drifts from the code\",\n fix: \"Remove the `@returns` tag\",\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, anchor: TSESTree.Node): void => {\n const jsdoc = context.sourceCode.getCommentsBefore(anchor).at(-1)\n if (jsdoc === undefined || !isJSDocComment(jsdoc)) return\n\n const range = findJSDocReturnsRange(context.sourceCode, jsdoc)\n if (range === null) return\n if (!isVoidFunction(fn, context.sourceCode.visitorKeys)) return\n\n const from = context.sourceCode.getIndexFromLoc({ line: range.from, column: 0 })\n const to = context.sourceCode.getIndexFromLoc({ line: range.to + 1, column: 0 })\n\n context.report({\n loc: {\n start: { line: range.from, column: 0 },\n end: { line: range.to, column: (context.sourceCode.lines[range.to - 1] ?? \"\").length },\n },\n messageId: \"voidReturns\",\n fix: fixer => fixer.removeRange([from, to]),\n })\n }\n\n return {\n FunctionDeclaration(node) {\n check(node, getDocumentableNode(node))\n },\n VariableDeclarator(node) {\n if (node.init?.type === \"ArrowFunctionExpression\" || node.init?.type === \"FunctionExpression\") {\n check(node.init, getDocumentableNode(node.init))\n }\n },\n MethodDefinition(node) {\n if (node.value.type === \"FunctionExpression\") {\n check(node.value, node)\n }\n },\n }\n }\n}\n\nexport default new NoJSDocReturnsOnVoid()\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\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, which\n * makes it a pure alias of the object it destructures.\n * @param pattern The object pattern to inspect.\n * @returns True if every property is a pure shorthand grab.\n */\nexport function 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","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 } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isAllShorthand, 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\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\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { type FunctionNode, someReturn, type VisitorKeys } from \"@/lib/utils/functions\"\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 a name is a React hook, i.e. `use` followed by a capitalized\n * word such as `useState` or `useMenuActions`.\n * @param name The function name to test.\n * @returns True if the name is a hook name.\n */\nexport function isHookName(name: string): boolean {\n return CONSTANTS.REACT.HOOK.test(name)\n}\n\n/**\n * Checks whether a name is a context-consumer hook, i.e. a `use…Context` wrapper\n * such as `useTreeViewContext` (the bare `useContext` is excluded).\n * @param name The function name to test.\n * @returns True if the name is a context-hook name.\n */\nexport function isContextHookName(name: string): boolean {\n return CONSTANTS.REACT.CONTEXT_HOOK.test(name)\n}\n\n/**\n * Checks whether an expression is, on its face, a function value: a function or\n * arrow expression, or a `useCallback` call (which always yields a function).\n * @param node The expression to inspect, if any.\n * @returns True if the expression evaluates to a function.\n */\nexport function isFunctionValue(node: TSESTree.Expression | null | undefined): boolean {\n if (!node) return false\n if (node.type === \"ArrowFunctionExpression\" || node.type === \"FunctionExpression\") return true\n\n return node.type === \"CallExpression\" && node.callee.type === \"Identifier\" && node.callee.name === \"useCallback\"\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 * 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(fn: FunctionNode, visitorKeys: VisitorKeys): 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 someReturn(fn.body, visitorKeys, isJsxExpression)\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, TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Rebuilds an object literal across multiple lines, indenting each property one\n * level past the line the object opens on and closing the brace back at that\n * level, so the result matches the surrounding indentation.\n * @param sourceCode The source code of the linted file.\n * @param node The object expression to expand.\n * @param indent The number of spaces in one indentation level.\n * @returns The multiline object literal source text.\n */\nexport function expandObjectLiteral(\n sourceCode: Readonly<TSESLint.SourceCode>,\n node: TSESTree.ObjectExpression,\n indent: number,\n): string {\n const openingLine = sourceCode.lines[node.loc.start.line - 1] ?? \"\"\n const baseIndent = openingLine.match(/^\\s*/)?.[0] ?? \"\"\n const propertyIndent = baseIndent + \" \".repeat(indent)\n\n const body = node.properties.map(property => `${propertyIndent}${sourceCode.getText(property)}`).join(\",\\n\")\n\n return `{\\n${body},\\n${baseIndent}}`\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 { expandObjectLiteral } from \"@/lib/utils/objects\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = [{ maxKeys: number; indent: number }]\ntype MessageIds = \"shouldWrap\"\n\n/**\n * Flags an object literal that packs more than `maxKeys` properties onto a\n * single line, and expands it to one property per line, since a wide inline\n * object is harder to scan, diff, and edit than a stacked one.\n */\nclass RequireMultilineObject extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-multiline-object\"\n readonly defaultOptions: Options = [\n {\n maxKeys: CONSTANTS.OBJECTS.MAX_INLINE_KEYS,\n indent: CONSTANTS.OBJECTS.INDENT_WIDTH,\n },\n ]\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"whitespace\",\n docs: {\n description: \"Require an object literal with more than a few properties to span multiple lines.\",\n recommended: true,\n category: \"base\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxKeys: { type: \"integer\", minimum: 1 },\n indent: { type: \"integer\", minimum: 1 },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n shouldWrap: nitpick({\n problem: \"This object literal has {{count}} properties packed onto a single line.\",\n why: \"An object with more than {{max}} properties is easier to scan, diff, and edit when each property sits on its own line\",\n fix: \"Break it across multiple lines, one property per line with a trailing comma\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const maxKeys = options[0]?.maxKeys ?? CONSTANTS.OBJECTS.MAX_INLINE_KEYS\n const indent = options[0]?.indent ?? CONSTANTS.OBJECTS.INDENT_WIDTH\n\n return {\n ObjectExpression(node) {\n if (node.properties.length <= maxKeys) return\n if (node.loc.start.line !== node.loc.end.line) return\n\n context.report({\n node,\n messageId: \"shouldWrap\",\n data: { count: node.properties.length, max: maxKeys },\n fix: fixer => fixer.replaceText(node, expandObjectLiteral(context.sourceCode, node, indent)),\n })\n },\n }\n }\n}\n\nexport default new RequireMultilineObject()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport { isContextHookName } from \"@/lib/utils/react\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"destructure\"\n\n/**\n * Flags a context-consumer hook (`use…Context`) whose result is bound whole to a\n * variable instead of being destructured, since destructuring names exactly what\n * the caller uses and reads better than repeated `context.member` access.\n */\nclass RequireContextHookDestructure extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-context-hook-destructure\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Require the result of a context-consumer hook to be destructured.\",\n recommended: true,\n category: \"react\",\n },\n schema: [],\n messages: {\n destructure: nitpick({\n problem: \"`{{hook}}` is bound whole instead of destructured.\",\n why: \"Destructuring at the call site names exactly what the caller uses and reads better than repeated `{{name}}.member` access\",\n fix: \"Destructure the members in use, e.g. `const { a, b } = {{hook}}()`\",\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.id.type !== \"Identifier\" || node.init?.type !== \"CallExpression\") return\n if (node.init.callee.type !== \"Identifier\" || !isContextHookName(node.init.callee.name)) return\n\n context.report({\n node,\n messageId: \"destructure\",\n data: { hook: node.init.callee.name, name: node.id.name },\n })\n },\n }\n }\n}\n\nexport default new RequireContextHookDestructure()\n","import { ASTUtils, type TSESLint, type TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { type FunctionNode, getFunctionName, someReturn } from \"@/lib/utils/functions\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport { isFunctionValue, isHookName } from \"@/lib/utils/react\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"wrapInObject\"\n\n/**\n * Flags a custom hook that returns a bare function (directly or through a local\n * `useCallback`), and wraps it in an object, so the hook can grow new members\n * later without breaking every call site.\n */\nclass RequireHookObjectReturn extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-hook-object-return\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"code\",\n docs: {\n description: \"Require a custom hook to return an object rather than a bare function.\",\n recommended: true,\n category: \"react\",\n },\n schema: [],\n messages: {\n wrapInObject: nitpick({\n problem: \"This hook returns a bare function instead of an object.\",\n why: \"Returning an object lets the hook expose new members later without changing every call site, a bare function locks its shape\",\n fix: \"Return the function inside an object, e.g. `return { handleThing }`\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n // Whether a returned expression is a function, resolving a returned\n // identifier through its local declaration such as a `useCallback` const\n const returnsFunction = (argument: TSESTree.Expression): boolean => {\n if (isFunctionValue(argument)) return true\n if (argument.type !== \"Identifier\") return false\n\n const variable = ASTUtils.findVariable(context.sourceCode.getScope(argument), argument.name)\n const declarator = variable?.defs.at(-1)?.node\n return declarator?.type === \"VariableDeclarator\" && isFunctionValue(declarator.init)\n }\n\n const report = (argument: TSESTree.Expression): void => {\n context.report({\n node: argument,\n messageId: \"wrapInObject\",\n fix:\n argument.type === \"Identifier\"\n ? fixer => fixer.replaceText(argument, `{ ${argument.name} }`)\n : undefined,\n })\n }\n\n const check = (fn: FunctionNode): void => {\n const name = getFunctionName(fn)\n if (name === undefined || !isHookName(name)) return\n\n // An arrow with an expression body returns that expression directly\n if (fn.type === \"ArrowFunctionExpression\" && fn.body.type !== \"BlockStatement\") {\n if (returnsFunction(fn.body)) report(fn.body)\n return\n }\n\n someReturn(fn.body, context.sourceCode.visitorKeys, argument => {\n if (argument !== null && returnsFunction(argument)) report(argument)\n return false\n })\n }\n\n return {\n FunctionDeclaration(node) {\n check(node)\n },\n FunctionExpression(node) {\n check(node)\n },\n ArrowFunctionExpression(node) {\n check(node)\n },\n }\n }\n}\n\nexport default new RequireHookObjectReturn()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\nimport migrationTableOrder from \"@/rules/adonisjs/migrationTableOrder\"\nimport requireControllerJSDoc from \"@/rules/adonisjs/requireControllerJSDoc\"\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 noJSDocReturnsOnVoid from \"@/rules/base/noJSDocReturnsOnVoid\"\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\"\nimport requireMultilineObject from \"@/rules/base/requireMultilineObject\"\nimport requireContextHookDestructure from \"@/rules/react/requireContextHookDestructure\"\nimport requireHookObjectReturn from \"@/rules/react/requireHookObjectReturn\"\n\n/**\n * Every rule instance registered by the plugin.\n */\nconst ruleInstances = [\n migrationTableOrder,\n requireControllerJSDoc,\n requireMigrationJSDoc,\n maxJSDocDescriptionLength,\n noAliasVariables,\n noBritishEnglish,\n noDecorativeCommentSeparators,\n noEmDash,\n noJSDocBlankBeforeTags,\n noJSDocReturnsOnVoid,\n noLineCommentPeriod,\n noPropertyAccessAlias,\n noPropertyDestructuring,\n noSingleLineJSDoc,\n requireFrameworkConfig,\n requireFunctionJSDoc,\n requireMultilineObject,\n requireContextHookDestructure,\n requireHookObjectReturn,\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.3.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"]}
|
|
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/controllers.ts","../src/lib/utils/jsdocs.ts","../src/rules/adonisjs/requireControllerJSDoc.ts","../src/rules/adonisjs/requireMigrationJSDoc.ts","../src/rules/base/maxJSDocDescriptionLength.ts","../src/lib/utils/aliases.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/noEmojis.ts","../src/rules/base/noJSDocBlankBeforeTags.ts","../src/lib/utils/functions.ts","../src/rules/base/noJSDocReturnsOnVoid.ts","../src/lib/utils/comments.ts","../src/rules/base/noLineCommentBackticks.ts","../src/rules/base/noLineCommentPeriod.ts","../src/rules/base/noPropertyAccessAlias.ts","../src/rules/base/noPropertyDestructuring.ts","../src/rules/base/noSingleLineJSDoc.ts","../src/rules/base/requireCapitalizedComments.ts","../src/lib/utils/frameworks.ts","../src/rules/base/requireFrameworkConfig.ts","../src/lib/utils/react.ts","../src/rules/base/requireFunctionJSDoc.ts","../src/lib/utils/objects.ts","../src/rules/base/requireMultilineObject.ts","../src/rules/react/requireContextHookDestructure.ts","../src/rules/react/requireHookObjectReturn.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","isControllerClass","isJSDocComment","comment","jsDocAnchor","declaration","earliest","found","decorator","hasLeadingJSDoc","sourceCode","closest","isBlankJSDocLine","line","getJSDocLineTag","isJSDocTagLine","getJSDocDescription","parts","content","findJSDocReturnsRange","tagLine","tag","to","RequireControllerJSDoc","requireControllerJSDoc_default","RequireMigrationJSDoc","requireMigrationJSDoc_default","DEFAULT_MAX","MaxJSDocDescriptionLength","max","length","maxJSDocDescriptionLength_default","propertyAccessPath","properties","isPropertyAccessAlias","isReassigned","scope","variable","ASTUtils","declarations","definition","reference","isPathWritten","written","path","target","isAllShorthand","pattern","property","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","fixer","noBritishEnglish_default","isDecorativeCommentLine","globToRegExp","glob","normalized","index","matchesGlob","filename","patterns","NoDecorativeCommentSeparators","allowIn","lines","reportedLine","noDecorativeCommentSeparators_default","TOKEN_TYPES","NoEmDash","allow","exempt","ranges","tokenTypes","location","type","token","start","end","noEmDash_default","NoEmojis","emoji","noEmojis_default","NoJSDocBlankBeforeTags","runEnd","nextLine","noJSDocBlankBeforeTags_default","getDocumentableNode","fn","isTopLevel","getFunctionName","someReturn","visitorKeys","predicate","children","child","childNode","functionReturnsValue","argument","isVoidReturnType","annotation","isVoidFunction","NoJSDocReturnsOnVoid","check","anchor","jsdoc","range","noJSDocReturnsOnVoid_default","isDirectiveComment","firstCommentContentChar","offset","markerLength","findProsePeriods","periods","quote","rest","endsWithAbbreviation","findBacktickSpans","spans","closing","lowercase","abbreviation","before","NoLineCommentBackticks","span","noLineCommentBackticks_default","NoLineCommentPeriod","ownLineIndent","indent","period","loc","spacing","noLineCommentPeriod_default","NoPropertyAccessAlias","candidates","recordWrite","candidate","noPropertyAccessAlias_default","NoPropertyDestructuring","noPropertyDestructuring_default","NoSingleLineJSDoc","expanded","noSingleLineJSDoc_default","RequireCapitalizedComments","isContinuation","previous","requireCapitalizedComments_default","FRAMEWORK_LABELS","importSources","sources","detectFrameworks","detected","RequireFrameworkConfig","ignored","enabled","framework","requireFrameworkConfig_default","isReactComponentName","isHookName","isContextHookName","isFunctionValue","isJsxExpression","functionReturnsJsx","RequireFunctionJSDoc","reportNode","documentable","requireFunctionJSDoc_default","expandObjectLiteral","baseIndent","propertyIndent","RequireMultilineObject","maxKeys","requireMultilineObject_default","RequireContextHookDestructure","requireContextHookDestructure_default","RequireHookObjectReturn","returnsFunction","declarator","report","requireHookObjectReturn_default","ruleInstances","rules","rule","categoryRules","allRules","all","plugin","recommended","ROUTE_FILE_GLOBS","adonisjs","react","buildConfigs","version","index_default"],"mappings":"4DAGA,IAAMA,EAAAA,CAAY,CAKd,WAAA,CAAa,WAAA,CAKb,SAAU,2DAAA,CAKV,OAAA,CAAS,SAOT,KAAA,CAAO,IAAA,MAAA,CAAC,8MAAiM,IAAE,CAAA,CAK3M,SAAU,CAKN,WAAA,CAAa,QAMb,cAAA,CAAgB,iBAAA,CAKhB,cAAe,oCAAA,CAMf,SAAA,CACI,kJAOJ,MAAA,CAAQ,IAAI,IAAI,CAAC,GAAA,CAAK,GAAG,CAAC,CAAA,CAM1B,cAAe,CAAC,MAAA,CAAQ,OAAQ,MAAA,CAAQ,KAAA,CAAO,MAAO,KAAA,CAAO,SAAA,CAAW,OAAO,CACnF,CAAA,CAKA,MAAO,CAKH,GAAA,CAAK,kBACT,CAAA,CAKA,KAAA,CAAO,CAKH,SAAA,CAAW,iBAAA,CAMX,SAAU,qCACd,CAAA,CAKA,QAAS,CAKL,eAAA,CAAiB,EAMjB,YAAA,CAAc,CAClB,EAKA,SAAA,CAAW,CAIP,WAAY,IAAI,GAAA,CAAI,CAAC,qBAAA,CAAuB,oBAAA,CAAsB,yBAAyB,CAAC,CAChG,EAKA,UAAA,CAAY,CAIR,eACI,sGAAA,CAKJ,UAAA,CAAY,WAChB,CAAA,CAKA,KAAA,CAAO,CAKH,IAAA,CAAM,WAAA,CAMN,aAAc,sBAClB,CAAA,CAKA,WAAY,CAIR,aAAA,CAAe,IAAI,GAAA,CAAI,CAAC,QAAS,QAAA,CAAU,SAAA,CAAW,SAAS,CAAC,CAAA,CAKhE,kBAAmB,IAAI,GAAA,CAAI,CAAC,WAAA,CAAa,UAAA,CAAY,UAAU,CAAC,CAAA,CAMhE,iBAAkB,IAAI,GAAA,CAAI,CAAC,YAAA,CAAc,YAAA,CAAc,YAAY,CAAC,CAAA,CAMpE,eAAgB,CAAC,QAAA,CAAU,YAAa,OAAO,CACnD,CACJ,CAAA,CAEOC,CAAAA,CAAQD,GC1JR,IAAME,GAAaC,WAAAA,CAAY,WAAA,CAClCC,GAAQ,CAAA,EAAGH,CAAAA,CAAU,QAAQ,CAAA,sBAAA,EAAyBG,CAAI,KAC9D,CAAA,CCzBO,IAAeC,EAAf,KAA0G,CAgC7G,cAA4E,CACxE,OAAOH,GAAgC,CACnC,IAAA,CAAM,KAAK,IAAA,CACX,IAAA,CAAM,KAAK,IAAA,CACX,cAAA,CAAgB,KAAK,cAAA,CACrB,MAAA,CAAQ,CAACI,CAAAA,CAASC,CAAAA,GAAY,KAAK,MAAA,CAAOD,CAAAA,CAASC,CAAO,CAC9D,CAAC,CACL,CACJ,CAAA,CCtBO,SAASC,CAAAA,CAAQ,CAAE,QAAAC,CAAAA,CAAS,GAAA,CAAAC,EAAK,GAAA,CAAAC,CAAI,EAAoB,CAC5D,OAAO,GAAGF,CAAO;AAAA,SAAA,EAAcC,CAAG;AAAA,SAAA,EAAcC,CAAG,CAAA,CACvD,CCbO,SAASC,EAAAA,CAAiBC,CAAAA,CAA0C,CACvE,OACIA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,0BAAA,EACrBA,CAAAA,CAAK,UAAA,EAAY,IAAA,GAAS,YAAA,EAC1BA,CAAAA,CAAK,UAAA,CAAW,IAAA,GAAS,YAEjC,CAQO,SAASC,EAAAA,CAAsBD,CAAAA,CAG7B,CAML,GALIA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,oBAAsBA,CAAAA,CAAK,MAAA,CAAO,QAAA,CAAS,IAAA,GAAS,YAAA,EACzEA,CAAAA,CAAK,MAAA,CAAO,QAAA,CAAS,IAAA,GAAS,aAAA,EAG9BA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAA,GAAS,kBAAA,EAAsBA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,QAAA,CAAS,IAAA,GAAS,YAAA,EACvFA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,QAAA,CAAS,IAAA,GAAS,QAAA,CAAU,OAAO,IAAA,CAE1D,IAAME,EAAWF,CAAAA,CAAK,SAAA,CAAU,EAAA,CAAG,EAAE,CAAA,CAErC,OADIE,CAAAA,EAAU,IAAA,GAAS,yBAAA,EAA6BA,CAAAA,EAAU,IAAA,GAAS,oBAAA,EACnEA,CAAAA,CAAS,IAAA,CAAK,IAAA,GAAS,gBAAA,EAAoBA,CAAAA,CAAS,MAAA,CAAO,CAAC,CAAA,EAAG,IAAA,GAAS,YAAA,CAAqB,IAAA,CAE1F,CAAE,IAAA,CAAMA,CAAAA,CAAS,IAAA,CAAK,IAAA,CAAM,WAAA,CAAaA,CAAAA,CAAS,MAAA,CAAO,CAAC,CAAA,CAAE,IAAK,CAC5E,CAUO,SAASC,EAAAA,CAA0BC,CAAAA,CAA+BC,CAAAA,CAA2C,CAChH,GAAID,CAAAA,CAAU,IAAA,GAAS,qBAAA,CAAuB,OAAO,IAAA,CAErD,IAAME,CAAAA,CAAOC,EAAAA,CAAgBH,CAAAA,CAAU,UAAA,CAAYC,CAAW,CAAA,CAC9D,OAAIC,CAAAA,GAAS,IAAA,CAAa,IAAA,CAEtBlB,CAAAA,CAAU,UAAA,CAAW,aAAA,CAAc,GAAA,CAAIkB,EAAK,MAAM,CAAA,CAAU,OAAA,CAC5DA,CAAAA,CAAK,MAAA,GAAW,YAAA,CAAqB,WAAA,CAErClB,CAAAA,CAAU,UAAA,CAAW,iBAAA,CAAkB,GAAA,CAAIkB,CAAAA,CAAK,MAAM,CAAA,CAClDA,CAAAA,CAAK,aAAA,GAAkB,MAAA,EAAalB,CAAAA,CAAU,UAAA,CAAW,gBAAA,CAAiB,GAAA,CAAIkB,CAAAA,CAAK,aAAa,CAAA,CACzF,WAAA,CAKJ,IAAA,CAGJ,QACX,CASA,SAASC,EAAAA,CACLC,EACAH,CAAAA,CAC4D,CAC5D,IAAII,CAAAA,CAAyBD,CAAAA,CAE7B,KAAOC,CAAAA,CAAQ,IAAA,GAAS,gBAAA,EAAoBA,CAAAA,CAAQ,MAAA,CAAO,IAAA,GAAS,kBAAA,EAAoB,CACpF,GAAIA,CAAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,IAAA,GAAS,YAAA,EAAgBA,CAAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,IAAA,GAASJ,CAAAA,CAAa,CAC3F,GAAII,CAAAA,CAAQ,MAAA,CAAO,QAAA,CAAS,OAAS,YAAA,CAAc,OAAO,IAAA,CAE1D,IAAMC,CAAAA,CAAgBD,CAAAA,CAAQ,SAAA,CAAU,CAAC,CAAA,CACnCE,CAAAA,CACFD,CAAAA,EAAe,IAAA,GAAS,SAAA,EAAa,OAAOA,CAAAA,CAAc,KAAA,EAAU,QAAA,CAC9DA,CAAAA,CAAc,KAAA,CACd,MAAA,CAEV,OAAO,CAAE,MAAA,CAAQD,CAAAA,CAAQ,MAAA,CAAO,QAAA,CAAS,IAAA,CAAM,aAAA,CAAeE,CAAQ,CAC1E,CAEAF,CAAAA,CAAUA,CAAAA,CAAQ,MAAA,CAAO,OAC7B,CAEA,OAAO,IACX,CC5FA,IAAMG,CAAAA,CAAN,cAAkCpB,CAAmC,CACxD,IAAA,CAAO,uBAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,6FAAA,CACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,UACd,CAAA,CACA,OAAQ,EAAC,CACT,QAAA,CAAU,CACN,UAAA,CAAYG,CAAAA,CAAQ,CAChB,OAAA,CAAS,4DAAA,CACT,GAAA,CAAK,8HAAA,CACL,GAAA,CAAK,6FACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,cAAA,CAAeO,CAAAA,CAAM,CACjB,IAAMa,CAAAA,CAAUZ,EAAAA,CAAsBD,CAAI,CAAA,CAC1C,GAAIa,CAAAA,GAAY,IAAA,CAAM,OAEtB,IAAIC,CAAAA,CAAU,CAAA,CAEd,IAAA,IAAWV,CAAAA,IAAaS,CAAAA,CAAQ,IAAA,CAAM,CAClC,IAAME,CAAAA,CAAWZ,EAAAA,CAA0BC,CAAAA,CAAWS,CAAAA,CAAQ,WAAW,CAAA,CACzE,GAAIE,CAAAA,GAAa,IAAA,CAAM,SAEvB,IAAMC,CAAAA,CAAO5B,CAAAA,CAAU,UAAA,CAAW,cAAA,CAAe,OAAA,CAAQ2B,CAAQ,CAAA,CAC7DC,EAAOF,CAAAA,EACPrB,CAAAA,CAAQ,MAAA,CAAO,CACX,IAAA,CAAMW,CAAAA,CACN,SAAA,CAAW,YAAA,CACX,IAAA,CAAM,CAAE,QAAA,CAAAW,CAAS,CACrB,CAAC,CAAA,CAGLD,CAAAA,CAAU,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAASE,CAAI,EACpC,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOC,EAAAA,CAAQ,IAAIL,CAAAA,CCzDZ,SAASM,EAAAA,CAAkBlB,CAAAA,CAA0C,CACxE,OAAOA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,0BAAA,EAA8BA,CAAAA,CAAK,EAAA,EAAI,IAAA,CAAK,QAAA,CAAS,YAAY,CAAA,GAAM,IACvG,CCDO,SAASmB,CAAAA,CAAeC,CAAAA,CAAoC,CAC/D,OAAOA,CAAAA,CAAQ,IAAA,GAAS,OAAA,EAAWA,CAAAA,CAAQ,KAAA,CAAM,UAAA,CAAW,GAAG,CACnE,CASO,SAASC,EAAAA,CAAYrB,EAAoC,CAC5D,IAAMsB,CAAAA,CAAAA,CACDtB,CAAAA,CAAK,IAAA,GAAS,0BAAA,EAA8BA,CAAAA,CAAK,IAAA,GAAS,wBAAA,GAC3DA,CAAAA,CAAK,WAAA,GAAgB,IAAA,CACfA,CAAAA,CAAK,WAAA,CACLA,CAAAA,CAMJuB,CAAAA,CAAAA,CAJa,YAAA,GAAgBD,CAAAA,CAAcA,CAAAA,CAAY,UAAA,CAAa,MAAA,GAI7C,MAAA,CACzB,CAACE,CAAAA,CAAOC,CAAAA,GAAeD,CAAAA,GAAU,MAAA,EAAaC,CAAAA,CAAU,KAAA,CAAM,CAAC,CAAA,CAAID,CAAAA,CAAM,KAAA,CAAM,CAAC,CAAA,CAAIC,CAAAA,CAAYD,CAAAA,CAChG,MACJ,CAAA,CAEA,OAAOD,CAAAA,GAAa,MAAA,EAAaA,CAAAA,CAAS,KAAA,CAAM,CAAC,CAAA,CAAIvB,CAAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAIuB,CAAAA,CAAWvB,CACpF,CAQO,SAAS0B,CAAAA,CAAgBC,CAAAA,CAA2C3B,CAAAA,CAA8B,CAErG,IAAM4B,CAAAA,CADiBD,CAAAA,CAAW,iBAAA,CAAkBN,GAAYrB,CAAI,CAAC,CAAA,CACtC,EAAA,CAAG,EAAE,CAAA,CAEpC,OAAO4B,CAAAA,GAAY,MAAA,EAAaT,CAAAA,CAAeS,CAAO,CAC1D,CAQO,SAASC,CAAAA,CAAiBC,CAAAA,CAAuB,CACpD,OAAO,YAAA,CAAa,IAAA,CAAKA,CAAI,CACjC,CAQO,SAASC,EAAAA,CAAgBD,CAAAA,CAA6B,CAEzD,OADcA,CAAAA,CAAK,KAAA,CAAM1C,CAAAA,CAAU,KAAA,CAAM,GAAG,CAAA,GAC7B,CAAC,CAAA,EAAK,IACzB,CAQO,SAAS4C,CAAAA,CAAeF,CAAAA,CAAuB,CAClD,OAAOC,EAAAA,CAAgBD,CAAI,CAAA,GAAM,IACrC,CASO,SAASG,EAAAA,CAAoBb,CAAAA,CAAmC,CACnE,IAAMc,CAAAA,CAAkB,EAAC,CAEzB,IAAA,IAAWJ,CAAAA,IAAQV,CAAAA,CAAQ,KAAA,CAAM,KAAA,CAAM;AAAA,CAAI,EAAG,CAC1C,IAAMe,EAAUL,CAAAA,CAAK,OAAA,CAAQ,YAAa,EAAE,CAAA,CAAE,SAAQ,CACtD,GAAIK,EAAQ,UAAA,CAAW,GAAG,EAAG,MAE7BD,CAAAA,CAAM,KAAKC,CAAO,EACtB,CAEA,OAAOD,EAAM,IAAA,CAAK,GAAG,EAAE,OAAA,CAAQ,MAAA,CAAQ,GAAG,CAAA,CAAE,IAAA,EAChD,CAUO,SAASE,GACZT,CAAAA,CACAP,CAAAA,CACmC,CACnC,IAAIiB,CAAAA,CAAU,GACd,IAAA,IAASP,CAAAA,CAAOV,CAAAA,CAAQ,GAAA,CAAI,MAAM,IAAA,CAAO,CAAA,CAAGU,EAAOV,CAAAA,CAAQ,GAAA,CAAI,IAAI,IAAA,CAAMU,CAAAA,EAAAA,CAAQ,CAC7E,IAAMQ,CAAAA,CAAMP,GAAgBJ,CAAAA,CAAW,KAAA,CAAMG,EAAO,CAAC,CAAA,EAAK,EAAE,CAAA,CAC5D,GAAIQ,CAAAA,GAAQ,SAAA,EAAaA,IAAQ,QAAA,CAAU,CACvCD,EAAUP,CAAAA,CACV,KACJ,CACJ,CAEA,GAAIO,IAAY,EAAA,CAAI,OAAO,KAE3B,IAAIE,CAAAA,CAAKnB,EAAQ,GAAA,CAAI,GAAA,CAAI,KAAO,CAAA,CAChC,IAAA,IAASU,CAAAA,CAAOO,CAAAA,CAAU,EAAGP,CAAAA,CAAOV,CAAAA,CAAQ,IAAI,GAAA,CAAI,IAAA,CAAMU,IACtD,GAAIE,CAAAA,CAAeL,EAAW,KAAA,CAAMG,CAAAA,CAAO,CAAC,CAAA,EAAK,EAAE,EAAG,CAClDS,CAAAA,CAAKT,EAAO,CAAA,CACZ,KACJ,CAGJ,OAAO,CACH,IAAA,CAAMO,CAAAA,CACN,GAAAE,CACJ,CACJ,CC3HA,IAAMC,CAAAA,CAAN,cAAqChD,CAAmC,CAC3D,KAAO,0BAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,YAAa,4DAAA,CACb,WAAA,CAAa,KACb,QAAA,CAAU,UACd,EACA,MAAA,CAAQ,GACR,QAAA,CAAU,CACN,aAAcG,CAAAA,CAAQ,CAClB,QAAS,uDAAA,CACT,GAAA,CAAK,uGACL,GAAA,CAAK,iFACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,EAAqF,CACxF,OAAO,CACH,gBAAA,CAAiBO,CAAAA,CAAM,CACdkB,EAAAA,CAAkBlB,CAAI,IACvB0B,CAAAA,CAAgBjC,CAAAA,CAAQ,WAAYO,CAAAA,CAAK,MAAM,GAEnDP,CAAAA,CAAQ,MAAA,CAAO,CAAE,IAAA,CAAMO,EAAK,EAAA,EAAMA,CAAAA,CAAM,UAAW,cAAe,CAAC,GACvE,CACJ,CACJ,CACJ,CAAA,CAEOyC,EAAAA,CAAQ,IAAID,CAAAA,CClCnB,IAAME,EAAN,cAAoClD,CAAmC,CAC1D,IAAA,CAAO,yBAAA,CAEP,cAAA,CAA0B,GAE1B,IAAA,CAAO,CACZ,KAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,2DAAA,CACb,YAAa,IAAA,CACb,QAAA,CAAU,UACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,YAAA,CAAcG,CAAAA,CAAQ,CAClB,OAAA,CAAS,uDACT,GAAA,CAAK,iHAAA,CACL,IAAK,2EACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,gBAAA,CAAiBO,EAAM,CACdD,EAAAA,CAAiBC,CAAI,CAAA,GACtB0B,CAAAA,CAAgBjC,CAAAA,CAAQ,UAAA,CAAYO,EAAK,MAAM,CAAA,EAEnDP,EAAQ,MAAA,CAAO,CAAE,KAAMO,CAAAA,CAAK,EAAA,EAAMA,EAAM,SAAA,CAAW,cAAe,CAAC,CAAA,EACvE,CACJ,CACJ,CACJ,CAAA,CAEO2C,GAAQ,IAAID,CAAAA,CCxCnB,IAAME,EAAAA,CAAc,IAOdC,CAAAA,CAAN,cAAwCrD,CAAmC,CAC9D,IAAA,CAAO,+BAEP,cAAA,CAA0B,CAAC,CAAE,GAAA,CAAKoD,EAAY,CAAC,CAAA,CAE/C,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,KAAM,CACF,WAAA,CAAa,6DAAA,CACb,WAAA,CAAa,KACb,QAAA,CAAU,MACd,EACA,MAAA,CAAQ,CACJ,CACI,IAAA,CAAM,QAAA,CACN,WAAY,CACR,GAAA,CAAK,CAAE,IAAA,CAAM,SAAA,CAAW,QAAS,CAAE,CACvC,EACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,SAAU,CACN,OAAA,CAASjD,EAAQ,CACb,OAAA,CAAS,qFACT,GAAA,CAAK,2JAAA,CACL,IAAK,qKACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAA8DC,CAAAA,CAAyC,CAC1G,IAAMoD,CAAAA,CAAMpD,EAAQ,CAAC,CAAA,EAAG,KAAOkD,EAAAA,CAE/B,OAAO,CACH,OAAA,EAAU,CACN,QAAWxB,CAAAA,IAAW3B,CAAAA,CAAQ,WAAW,cAAA,EAAe,CAAG,CACvD,GAAI,CAAC0B,EAAeC,CAAO,CAAA,CAAG,SAE9B,IAAM2B,CAAAA,CAASd,EAAAA,CAAoBb,CAAO,EAAE,MAAA,CACxC2B,CAAAA,EAAUD,GAEdrD,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK2B,CAAAA,CAAQ,IACb,SAAA,CAAW,SAAA,CACX,KAAM,CAAE,MAAA,CAAA2B,EAAQ,GAAA,CAAAD,CAAI,CACxB,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOE,GAAQ,IAAIH,CAAAA,CC1DZ,SAASI,CAAAA,CAAmBjD,EAA0C,CACzE,IAAMkD,EAAuB,EAAC,CAC1B1C,EAA4BR,CAAAA,CAEhC,OAAa,CACT,GAAIQ,EAAW,IAAA,GAAS,iBAAA,EAAqBA,EAAW,IAAA,GAAS,qBAAA,CAAuB,CACpFA,CAAAA,CAAaA,CAAAA,CAAW,WACxB,QACJ,CAEA,GAAIA,CAAAA,CAAW,IAAA,GAAS,mBAAoB,CAExC,GADIA,EAAW,QAAA,EACXA,CAAAA,CAAW,QAAA,CAAS,IAAA,GAAS,aAAc,OAAO,IAAA,CAEtD0C,EAAW,OAAA,CAAQ1C,CAAAA,CAAW,SAAS,IAAI,CAAA,CAC3CA,EAAaA,CAAAA,CAAW,MAAA,CACxB,QACJ,CAEA,KACJ,CAEA,OAAI0C,CAAAA,CAAW,SAAW,CAAA,CAAU,IAAA,CAChC1C,CAAAA,CAAW,IAAA,GAAS,iBAAyB,CAAC,MAAA,CAAQ,GAAG0C,CAAU,CAAA,CAAE,KAAK,GAAG,CAAA,CAC7E1C,EAAW,IAAA,GAAS,YAAA,CAAqB,CAACA,CAAAA,CAAW,IAAA,CAAM,GAAG0C,CAAU,CAAA,CAAE,KAAK,GAAG,CAAA,CAE/E,IACX,CASO,SAASC,EAAAA,CAAsBnD,CAAAA,CAAoC,CACtE,OAAOiD,CAAAA,CAAmBjD,CAAI,CAAA,GAAM,IACxC,CASO,SAASoD,CAAAA,CAAaC,EAA6B9D,CAAAA,CAAuB,CAC7E,IAAM+D,CAAAA,CAAWC,QAAAA,CAAS,aAAaF,CAAAA,CAAO9D,CAAI,CAAA,CAGlD,GAAI+D,IAAa,IAAA,CAAM,OAAO,OAE9B,IAAME,CAAAA,CAAe,IAAI,GAAA,CAAmBF,CAAAA,CAAS,KAAK,GAAA,CAAIG,CAAAA,EAAcA,EAAW,IAAI,CAAC,EAE5F,OAAOH,CAAAA,CAAS,WAAW,IAAA,CAAKI,CAAAA,EAAaA,EAAU,OAAA,EAAQ,EAAK,CAACF,CAAAA,CAAa,GAAA,CAAIE,EAAU,UAAU,CAAC,CAC/G,CASO,SAASC,GAAcC,CAAAA,CAA8BC,CAAAA,CAAuB,CAC/E,IAAA,IAAWC,CAAAA,IAAUF,EACjB,GAAIC,CAAAA,GAASC,GAAUD,CAAAA,CAAK,UAAA,CAAW,CAAA,EAAGC,CAAM,GAAG,CAAA,CAAG,OAAO,MAGjE,OAAO,MACX,CASO,SAASC,EAAAA,CAAeC,EAA0C,CACrE,OAAIA,EAAQ,UAAA,CAAW,MAAA,GAAW,EAAU,KAAA,CAErCA,CAAAA,CAAQ,WAAW,KAAA,CACtBC,CAAAA,EACIA,CAAAA,CAAS,IAAA,GAAS,YAClBA,CAAAA,CAAS,SAAA,EACT,CAACA,CAAAA,CAAS,QAAA,EACVA,EAAS,KAAA,CAAM,IAAA,GAAS,YAChC,CACJ,CCrFA,IAAMC,CAAAA,CAAN,cAA+B1E,CAAmC,CACrD,IAAA,CAAO,qBAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,KAAM,CACF,WAAA,CAAa,qFACb,WAAA,CAAa,IAAA,CACb,SAAU,MACd,CAAA,CACA,OAAQ,EAAC,CACT,SAAU,CACN,KAAA,CAAOG,EAAQ,CACX,OAAA,CAAS,uCAAA,CACT,GAAA,CAAK,+FACL,GAAA,CAAK,kGACT,CAAC,CACL,CACJ,EAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,mBAAmBO,CAAAA,CAAM,CACjBA,EAAK,MAAA,CAAO,IAAA,GAAS,uBAAyBA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,OAAA,EAGnEA,EAAK,MAAA,CAAO,MAAA,CAAO,OAAS,wBAAA,GAE5BA,CAAAA,CAAK,GAAG,IAAA,GAAS,YAAA,EAAgBA,EAAK,IAAA,EAAM,IAAA,GAAS,cAIrDA,CAAAA,CAAK,EAAA,CAAG,iBAAmB,MAAA,GAI3BoD,CAAAA,CAAa3D,EAAQ,UAAA,CAAW,QAAA,CAASO,CAAI,CAAA,CAAGA,EAAK,IAAA,CAAK,IAAI,GAElEP,CAAAA,CAAQ,MAAA,CAAO,CACX,IAAA,CAAAO,CAAAA,CACA,UAAW,OAAA,CACX,IAAA,CAAM,CACF,IAAA,CAAMA,CAAAA,CAAK,GAAG,IAAA,CACd,MAAA,CAAQA,EAAK,IAAA,CAAK,IACtB,CACJ,CAAC,IACL,CACJ,CACJ,CACJ,CAAA,CAEOmE,EAAAA,CAAQ,IAAID,CAAAA,CC/DZ,IAAME,GAA8C,CAEvD,MAAA,CAAQ,QACR,OAAA,CAAS,QAAA,CACT,SAAU,SAAA,CACV,SAAA,CAAW,WACX,SAAA,CAAW,UAAA,CACX,WAAY,WAAA,CACZ,SAAA,CAAW,WACX,UAAA,CAAY,WAAA,CACZ,QAAS,QAAA,CACT,QAAA,CAAU,UACV,MAAA,CAAQ,OAAA,CACR,OAAQ,OAAA,CACR,SAAA,CAAW,WAGX,SAAA,CAAW,WAAA,CACX,WAAY,YAAA,CACZ,WAAA,CAAa,cACb,aAAA,CAAe,eAAA,CACf,UAAA,CAAY,YAAA,CACZ,YAAa,aAAA,CACb,WAAA,CAAa,cACb,YAAA,CAAc,cAAA,CACd,eAAgB,gBAAA,CAChB,SAAA,CAAW,YACX,UAAA,CAAY,YAAA,CACZ,YAAa,aAAA,CACb,aAAA,CAAe,gBACf,QAAA,CAAU,UAAA,CACV,UAAW,WAAA,CACX,UAAA,CAAY,YAAA,CACZ,YAAA,CAAc,eACd,QAAA,CAAU,UAAA,CACV,UAAW,WAAA,CACX,UAAA,CAAY,aACZ,YAAA,CAAc,cAAA,CACd,UAAW,WAAA,CACX,UAAA,CAAY,aACZ,WAAA,CAAa,aAAA,CACb,SAAU,UAAA,CACV,SAAA,CAAW,YACX,UAAA,CAAY,YAAA,CACZ,WAAA,CAAa,aAAA,CACb,aAAc,cAAA,CACd,aAAA,CAAe,gBACf,SAAA,CAAW,WAAA,CACX,WAAY,YAAA,CACZ,WAAA,CAAa,cACb,QAAA,CAAU,UAAA,CACV,UAAW,WAAA,CACX,UAAA,CAAY,aACZ,UAAA,CAAY,YAAA,CACZ,YAAa,aAAA,CACb,YAAA,CAAc,cAAA,CACd,UAAA,CAAY,aACZ,WAAA,CAAa,aAAA,CAGb,QAAS,SAAA,CACT,QAAA,CAAU,WACV,SAAA,CAAW,WAAA,CAGX,OAAQ,QAAA,CACR,OAAA,CAAS,WACT,OAAA,CAAS,SAAA,CACT,MAAO,OAAA,CACP,KAAA,CAAO,QAGP,OAAA,CAAS,SAAA,CACT,OAAA,CAAS,SAAA,CACT,QAAS,SAAA,CAGT,SAAA,CAAW,WACX,UAAA,CAAY,WAAA,CACZ,SAAU,SAAA,CACV,SAAA,CAAW,WACX,SAAA,CAAW,UAAA,CACX,UAAW,UAAA,CAGX,IAAA,CAAM,OACN,QAAA,CAAU,QAAA,CACV,UAAW,SACf,CAAA,CCpFO,SAASC,EAAAA,CACZC,EACAC,CAAAA,CACAC,CAAAA,CACsB,CAMtB,IAAMC,CAAAA,CAAqC,OAAO,MAAA,CAAO,IAAI,EAE7D,IAAA,GAAW,CAACC,EAAKC,CAAK,CAAA,GAAK,OAAO,OAAA,CAAQL,CAAI,EAC1CG,CAAAA,CAAWC,CAAAA,CAAI,WAAA,EAAa,EAAIC,CAAAA,CAGpC,IAAA,GAAW,CAACD,CAAAA,CAAKC,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQJ,CAAK,CAAA,CAC3CE,CAAAA,CAAWC,EAAI,WAAA,EAAa,EAAIC,CAAAA,CAGpC,IAAA,IAAWD,KAAOF,CAAAA,CACd,OAAOC,CAAAA,CAAWC,CAAAA,CAAI,aAAa,CAAA,CAGvC,OAAOD,CACX,CCXO,SAASG,CAAAA,CAAaC,CAAAA,CAAsB,CAC/C,IAAMC,CAAAA,CAAgB,EAAC,CAEvB,IAAA,IAAWC,KAASF,CAAAA,CAAK,QAAA,CAASzF,EAAU,KAAA,CAAM,QAAQ,CAAA,CAClD2F,CAAAA,CAAM,QAAU,MAAA,EAChBD,CAAAA,CAAM,KAAK,CAAE,IAAA,CAAMC,EAAM,CAAC,CAAA,CAAG,MAAOA,CAAAA,CAAM,KAAM,CAAC,CAAA,CAIzD,OAAOD,CACX,CAUO,SAASE,EAAUC,CAAAA,CAAgBC,CAAAA,CAA6B,CACnE,OAAID,IAAWA,CAAAA,CAAO,WAAA,GACXC,CAAAA,CAAY,WAAA,GAGnBD,CAAAA,CAAO,MAAA,CAAO,CAAC,CAAA,GAAMA,CAAAA,CAAO,OAAO,CAAC,CAAA,CAAE,aAAY,CAC3CC,CAAAA,CAAY,OAAO,CAAC,CAAA,CAAE,WAAA,EAAY,CAAIA,EAAY,KAAA,CAAM,CAAC,EAG7DA,CACX,CASO,SAASC,EAAAA,CAAWC,CAAAA,CAAmC,CAC1D,OAAOA,CAAAA,GAAS,QAAahG,CAAAA,CAAU,KAAA,CAAM,UAAU,IAAA,CAAKgG,CAAI,CACpE,CChDA,IAAMC,CAAAA,CAAN,cAA+B7F,CAAmC,CACrD,IAAA,CAAO,qBAEP,cAAA,CAA0B,CAAC,CAAE,KAAA,CAAO,GAAI,MAAA,CAAQ,EAAG,CAAC,CAAA,CAEpD,KAAO,CACZ,IAAA,CAAM,aACN,IAAA,CAAM,CACF,WAAA,CAAa,iEAAA,CACb,YAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,OAAA,CAAS,OACT,MAAA,CAAQ,CACJ,CACI,IAAA,CAAM,QAAA,CACN,WAAY,CACR,KAAA,CAAO,CACH,IAAA,CAAM,QAAA,CACN,qBAAsB,CAAE,IAAA,CAAM,QAAS,CAC3C,EACA,MAAA,CAAQ,CACJ,KAAM,OAAA,CACN,KAAA,CAAO,CAAE,IAAA,CAAM,QAAS,CAC5B,CACJ,CAAA,CACA,qBAAsB,KAC1B,CACJ,EACA,QAAA,CAAU,CACN,QAASG,CAAAA,CAAQ,CACb,OAAA,CAAS,sEAAA,CACT,IAAK,8EAAA,CACL,GAAA,CAAK,4BACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,EAA8DC,CAAAA,CAAyC,CAC1G,IAAM+E,CAAAA,CAAaJ,EAAAA,CAAgBD,GAAqB1E,CAAAA,CAAQ,CAAC,GAAG,KAAA,EAAS,GAAIA,CAAAA,CAAQ,CAAC,GAAG,MAAA,EAAU,EAAE,CAAA,CAEzG,OAAO,CACH,UAAA,CAAWM,CAAAA,CAAM,CAGb,GAAI,EAAAA,EAAK,MAAA,CAAO,IAAA,GAAS,oBAAsBA,CAAAA,CAAK,MAAA,CAAO,WAAaA,CAAAA,EAAQ,CAACA,CAAAA,CAAK,MAAA,CAAO,UAI7F,IAAA,IAAWsF,CAAAA,IAAQV,EAAa5E,CAAAA,CAAK,IAAI,EAAG,CACxC,IAAMuF,EAAWd,CAAAA,CAAWa,CAAAA,CAAK,KAAK,WAAA,EAAa,EAC/CC,CAAAA,GAAa,MAAA,EAEjB9F,EAAQ,MAAA,CAAO,CACX,IAAA,CAAAO,CAAAA,CACA,UAAW,SAAA,CACX,IAAA,CAAM,CAAE,OAAA,CAASsF,CAAAA,CAAK,KAAM,QAAA,CAAUN,CAAAA,CAAUM,EAAK,IAAA,CAAMC,CAAQ,CAAE,CACzE,CAAC,EACL,CACJ,CAAA,CACA,SAAU,CACN,IAAA,IAAWnE,CAAAA,IAAW3B,CAAAA,CAAQ,WAAW,cAAA,EAAe,CACpD,QAAW6F,CAAAA,IAAQV,CAAAA,CAAaxD,EAAQ,KAAK,CAAA,CAAG,CAC5C,IAAMmE,CAAAA,CAAWd,EAAWa,CAAAA,CAAK,IAAA,CAAK,aAAa,CAAA,CACnD,GAAIC,CAAAA,GAAa,MAAA,CAAW,SAE5B,IAAMC,EAAQR,CAAAA,CAAUM,CAAAA,CAAK,KAAMC,CAAQ,CAAA,CAGrCE,EAAOrE,CAAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,CAAI,CAAA,CAAIkE,EAAK,KAAA,CACnC/C,CAAAA,CAAKkD,EAAOH,CAAAA,CAAK,IAAA,CAAK,OAE5B7F,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAOA,CAAAA,CAAQ,WAAW,eAAA,CAAgBgG,CAAI,EAC9C,GAAA,CAAKhG,CAAAA,CAAQ,WAAW,eAAA,CAAgB8C,CAAE,CAC9C,CAAA,CACA,SAAA,CAAW,UACX,IAAA,CAAM,CAAE,QAAS+C,CAAAA,CAAK,IAAA,CAAM,QAAA,CAAUE,CAAM,EAC5C,GAAA,CAAKE,CAAAA,EAASA,EAAM,gBAAA,CAAiB,CAACD,EAAMlD,CAAE,CAAA,CAAGiD,CAAK,CAC1D,CAAC,EACL,CAER,CACJ,CACJ,CACJ,CAAA,CAEOG,GAAQ,IAAIN,CAAAA,CChGZ,SAASO,EAAAA,CAAwB9D,EAAuB,CAC3D,IAAMK,EAAUL,CAAAA,CAAK,OAAA,CAAQ,aAAc,EAAE,CAAA,CAAE,SAAQ,CACvD,OAAIK,EAAQ,MAAA,GAAW,CAAA,CAAU,MAG7B/C,CAAAA,CAAU,QAAA,CAAS,YAAY,IAAA,CAAK+C,CAAO,GAC3C/C,CAAAA,CAAU,QAAA,CAAS,eAAe,IAAA,CAAK+C,CAAO,GAC9C/C,CAAAA,CAAU,QAAA,CAAS,cAAc,IAAA,CAAK+C,CAAO,CAErD,CCXA,SAAS0D,GAAaC,CAAAA,CAAsB,CACxC,IAAMC,CAAAA,CAAaD,CAAAA,CAAK,QAAQ,KAAA,CAAO,GAAG,CAAA,CACtC9B,CAAAA,CAAU,IAEd,IAAA,IAASgC,CAAAA,CAAQ,EAAGA,CAAAA,CAAQD,CAAAA,CAAW,OAAQC,CAAAA,EAAAA,CAAS,CACpD,IAAMZ,CAAAA,CAAOW,CAAAA,CAAWC,CAAK,CAAA,CAC7B,GAAIZ,IAAS,MAAA,CAAW,MAEpBA,IAAS,GAAA,CACLW,CAAAA,CAAWC,CAAAA,CAAQ,CAAC,IAAM,GAAA,EAC1BhC,CAAAA,EAAW,KACXgC,CAAAA,EAAAA,CAGID,CAAAA,CAAWC,EAAQ,CAAC,CAAA,GAAM,KAAKA,CAAAA,EAAAA,EAEnChC,CAAAA,EAAW,QAER,gBAAA,CAAiB,QAAA,CAASoB,CAAI,CAAA,CACrCpB,CAAAA,EAAW,KAAKoB,CAAI,CAAA,CAAA,CAEpBpB,CAAAA,EAAWoB,EAEnB,CAEA,OAAO,IAAI,OAAO,CAAA,EAAGpB,CAAO,GAAG,CACnC,CASO,SAASiC,EAAAA,CAAYC,CAAAA,CAAkBC,EAA6B,CACvE,IAAMtC,EAAOqC,CAAAA,CAAS,OAAA,CAAQ,MAAO,GAAG,CAAA,CAExC,OAAOC,CAAAA,CAAS,KAAKnC,CAAAA,EAAW6B,EAAAA,CAAa7B,CAAO,CAAA,CAAE,IAAA,CAAKH,CAAI,CAAC,CACpE,CC9BA,IAAMuC,CAAAA,CAAN,cAA4C5G,CAAmC,CAClE,KAAO,kCAAA,CAEP,cAAA,CAA0B,CAAC,CAAE,OAAA,CAAS,EAAG,CAAC,CAAA,CAE1C,IAAA,CAAO,CACZ,IAAA,CAAM,QAAA,CACN,KAAM,CACF,WAAA,CAAa,0FACb,WAAA,CAAa,IAAA,CACb,SAAU,MACd,CAAA,CACA,OAAQ,CACJ,CACI,KAAM,QAAA,CACN,UAAA,CAAY,CACR,OAAA,CAAS,CACL,IAAA,CAAM,OAAA,CACN,MAAO,CAAE,IAAA,CAAM,QAAS,CAC5B,CACJ,EACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,QAAA,CAAU,CACN,UAAA,CAAYG,CAAAA,CAAQ,CAChB,OAAA,CAAS,2CAAA,CACT,GAAA,CAAK,0GAAA,CACL,IAAK,yFACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAA8DC,CAAAA,CAAyC,CAC1G,IAAM2G,CAAAA,CAAU3G,EAAQ,CAAC,CAAA,EAAG,SAAW,EAAC,CACxC,OAAI2G,CAAAA,CAAQ,MAAA,CAAS,GAAKJ,EAAAA,CAAYxG,CAAAA,CAAQ,SAAU4G,CAAO,CAAA,CACpD,EAAC,CAGL,CACH,SAAU,CACN,IAAA,IAAWjF,KAAW3B,CAAAA,CAAQ,UAAA,CAAW,gBAAe,CAAG,CACvD,IAAM6G,CAAAA,CAAQlF,CAAAA,CAAQ,MAAM,KAAA,CAAM;AAAA,CAAI,CAAA,CAEtC,IAAA,IAAS4E,CAAAA,CAAQ,CAAA,CAAGA,CAAAA,CAAQM,CAAAA,CAAM,MAAA,CAAQN,CAAAA,EAAAA,CAAS,CAC/C,IAAMlE,CAAAA,CAAOwE,CAAAA,CAAMN,CAAK,CAAA,CACxB,GAAIlE,CAAAA,GAAS,MAAA,EAAa,CAAC8D,EAAAA,CAAwB9D,CAAI,CAAA,CAAG,SAE1D,IAAMyE,CAAAA,CAAenF,CAAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAO4E,CAAAA,CACxCf,CAAAA,CAASxF,EAAQ,UAAA,CAAW,KAAA,CAAM8G,CAAAA,CAAe,CAAC,CAAA,EAAK,EAAA,CAE7D9G,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAO,CAAE,IAAA,CAAM8G,CAAAA,CAAc,MAAA,CAAQ,CAAE,CAAA,CACvC,GAAA,CAAK,CAAE,IAAA,CAAMA,CAAAA,CAAc,MAAA,CAAQtB,CAAAA,CAAO,MAAO,CACrD,CAAA,CACA,SAAA,CAAW,YACf,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOuB,EAAAA,CAAQ,IAAIJ,CAAAA,CC7DnB,IAAMK,EAAAA,CAAuD,CACzD,OAAA,CAAS,QAAA,CACT,SAAA,CAAW,UAAA,CACX,GAAA,CAAK,SACT,CAAA,CAMMC,CAAAA,CAAN,cAAuBlH,CAAmC,CAC7C,IAAA,CAAO,YAAA,CAEP,cAAA,CAA0B,CAAC,CAAE,KAAA,CAAO,EAAG,CAAC,CAAA,CAExC,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,iEAAA,CACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,CACJ,CACI,IAAA,CAAM,QAAA,CACN,UAAA,CAAY,CACR,KAAA,CAAO,CACH,IAAA,CAAM,OAAA,CACN,MAAO,CACH,IAAA,CAAM,QAAA,CACN,IAAA,CAAM,CAAC,SAAA,CAAW,WAAA,CAAa,KAAA,CAAO,UAAU,CACpD,CACJ,CACJ,CAAA,CACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,SAAU,CACN,MAAA,CAAQG,CAAAA,CAAQ,CACZ,OAAA,CAAS,sCAAA,CACT,GAAA,CAAK,qGAAA,CACL,GAAA,CAAK,+KACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAA8DC,EAAyC,CAC1G,IAAMiH,CAAAA,CAAQ,IAAI,GAAA,CAAIjH,CAAAA,CAAQ,CAAC,CAAA,EAAG,OAAS,EAAE,CAAA,CAIvCkH,CAAAA,CAAS,IAA0B,CACrC,IAAMC,CAAAA,CAA6B,EAAC,CACpC,GAAIF,CAAAA,CAAM,IAAA,GAAS,CAAA,CAAG,OAAOE,CAAAA,CAE7B,IAAMC,CAAAA,CAAa,IAAI,GAAA,CACnB,CAAC,GAAGH,CAAK,CAAA,CAAE,GAAA,CAAII,GAAYN,EAAAA,CAAYM,CAAQ,CAAC,CAAA,CAAE,MAAA,CAAOC,CAAAA,EAAQA,CAAAA,GAAS,MAAS,CACvF,CAAA,CAEA,IAAA,IAAWC,CAAAA,IAASxH,CAAAA,CAAQ,UAAA,CAAW,GAAA,CAAI,MAAA,EAAU,GAC7CqH,CAAAA,CAAW,GAAA,CAAIG,CAAAA,CAAM,IAAI,CAAA,EAAGJ,CAAAA,CAAO,IAAA,CAAKI,CAAAA,CAAM,KAAK,CAAA,CAG3D,GAAIN,CAAAA,CAAM,GAAA,CAAI,UAAU,CAAA,CACpB,IAAA,IAAWvF,KAAW3B,CAAAA,CAAQ,UAAA,CAAW,cAAA,EAAe,CACpDoH,CAAAA,CAAO,IAAA,CAAKzF,CAAAA,CAAQ,KAAK,EAIjC,OAAOyF,CACX,CAAA,CAEA,OAAO,CACH,OAAA,EAAU,CACN,IAAMhC,EAAOpF,CAAAA,CAAQ,UAAA,CAAW,OAAA,EAAQ,CAClCoH,CAAAA,CAASD,CAAAA,EAAO,CAItB,IAAA,IAASZ,CAAAA,CAAQ,CAAA,CAAGA,CAAAA,CAAQnB,CAAAA,CAAK,MAAA,CAAQmB,CAAAA,EAAAA,CACjCnB,CAAAA,CAAKmB,CAAK,IAAM5G,CAAAA,CAAU,OAAA,GAC1ByH,CAAAA,CAAO,IAAA,CAAK,CAAC,CAACK,CAAAA,CAAOC,CAAG,IAAMnB,CAAAA,EAASkB,CAAAA,EAASlB,CAAAA,CAAQmB,CAAG,CAAA,EAE/D1H,CAAAA,CAAQ,MAAA,CAAO,CACX,IAAK,CACD,KAAA,CAAOA,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgBuG,CAAK,CAAA,CAC/C,GAAA,CAAKvG,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgBuG,CAAAA,CAAQ,CAAC,CACrD,CAAA,CACA,SAAA,CAAW,QACf,CAAC,CAAA,EAET,CACJ,CACJ,CACJ,CAAA,CAEOoB,EAAAA,CAAQ,IAAIV,ECrGnB,IAAMW,CAAAA,CAAN,cAAuB7H,CAAmC,CAC7C,IAAA,CAAO,WAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,OAAA,CAAS,MAAA,CACT,IAAA,CAAM,CACF,WAAA,CAAa,mDAAA,CACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,OAAQ,EAAC,CACT,QAAA,CAAU,CACN,KAAA,CAAOG,CAAAA,CAAQ,CACX,OAAA,CAAS,8BACT,GAAA,CAAK,qGAAA,CACL,GAAA,CAAK,mBACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAAqF,CACxF,IAAMoF,CAAAA,CAAOpF,CAAAA,CAAQ,UAAA,CAAW,OAAA,EAAQ,CAExC,OAAO,CACH,OAAA,EAAU,CAGN,IAAA,IAAWsF,CAAAA,IAASF,CAAAA,CAAK,QAAA,CAASzF,EAAU,KAAK,CAAA,CAAG,CAChD,IAAMkI,CAAAA,CAAQvC,CAAAA,CAAM,CAAC,CAAA,CACfoC,EAAMpC,CAAAA,CAAM,KAAA,CAAQuC,CAAAA,CAAM,MAAA,CAEhC7H,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAOA,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgBsF,CAAAA,CAAM,KAAK,CAAA,CACrD,GAAA,CAAKtF,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB0H,CAAG,CAC/C,CAAA,CACA,SAAA,CAAW,OAAA,CACX,KAAM,CAAE,KAAA,CAAAG,CAAM,CAAA,CACd,GAAA,CAAK5B,CAAAA,EAASA,CAAAA,CAAM,WAAA,CAAY,CAACX,CAAAA,CAAM,KAAA,CAAOoC,CAAG,CAAC,CACtD,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOI,EAAAA,CAAQ,IAAIF,CAAAA,CCjDnB,IAAMG,CAAAA,CAAN,cAAqChI,CAAmC,CAC3D,IAAA,CAAO,4BAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,KAAO,CACZ,IAAA,CAAM,QAAA,CACN,OAAA,CAAS,MAAA,CACT,IAAA,CAAM,CACF,WAAA,CAAa,yEACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,eAAgBG,CAAAA,CAAQ,CACpB,OAAA,CAAS,2CAAA,CACT,GAAA,CAAK,sGAAA,CACL,GAAA,CAAK,uDACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,OAAA,EAAU,CACN,IAAA,IAAW2B,CAAAA,IAAW3B,CAAAA,CAAQ,UAAA,CAAW,cAAA,EAAe,CACpD,GAAK0B,CAAAA,CAAeC,CAAO,CAAA,EAEvBA,CAAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,GAASA,CAAAA,CAAQ,IAAI,GAAA,CAAI,IAAA,CAE/C,IAAA,IAASU,CAAAA,CAAOV,CAAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAMU,CAAAA,EAAQV,CAAAA,CAAQ,GAAA,CAAI,GAAA,CAAI,IAAA,CAAMU,CAAAA,EAAAA,CAAQ,CAC1E,IAAM+C,EAAOpF,CAAAA,CAAQ,UAAA,CAAW,KAAA,CAAMqC,CAAAA,CAAO,CAAC,CAAA,CAC9C,GAAI+C,CAAAA,GAAS,QAAa,CAAChD,CAAAA,CAAiBgD,CAAI,CAAA,CAAG,SAGnD,IAAI4C,CAAAA,CAAS3F,CAAAA,CACb,KACI2F,CAAAA,CAASrG,CAAAA,CAAQ,GAAA,CAAI,GAAA,CAAI,IAAA,EACzBS,CAAAA,CAAiBpC,CAAAA,CAAQ,UAAA,CAAW,KAAA,CAAMgI,CAAM,CAAA,EAAK,EAAE,CAAA,EAEvDA,CAAAA,EAAAA,CAIJ,IAAMC,CAAAA,CAAWjI,EAAQ,UAAA,CAAW,KAAA,CAAMgI,CAAM,CAAA,CAChD,GAAIC,CAAAA,GAAa,MAAA,EAAa1F,CAAAA,CAAe0F,CAAQ,CAAA,CAAG,CACpD,IAAMjC,CAAAA,CAAOhG,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB,CAAE,KAAAqC,CAAAA,CAAM,MAAA,CAAQ,CAAE,CAAC,CAAA,CAC7DS,CAAAA,CAAK9C,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB,CAAE,IAAA,CAAMgI,CAAAA,CAAS,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAC,EAE7EhI,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAO,CAAE,IAAA,CAAAqC,EAAM,MAAA,CAAQ,CAAE,CAAA,CACzB,GAAA,CAAK,CAAE,IAAA,CAAM2F,CAAAA,CAAQ,MAAA,CAAQ5C,EAAK,MAAO,CAC7C,CAAA,CACA,SAAA,CAAW,gBAAA,CACX,GAAA,CAAKa,CAAAA,EAASA,CAAAA,CAAM,WAAA,CAAY,CAACD,CAAAA,CAAMlD,CAAE,CAAC,CAC9C,CAAC,EACL,CAEAT,CAAAA,CAAO2F,EACX,CAER,CACJ,CACJ,CACJ,CAAA,CAEOE,EAAAA,CAAQ,IAAIH,CAAAA,CCtDZ,SAASI,CAAAA,CAAoBC,CAAAA,CAAiC,CACjE,IAAI7H,CAAAA,CAAsB6H,CAAAA,CAE1B,OAAI7H,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,oBAAA,EAAwBA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAA,GAAS,qBAAA,GACzEA,CAAAA,CAAOA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAA,CAAA,CAGnBA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,0BAA4BA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,0BAAA,IACtEA,CAAAA,CAAOA,CAAAA,CAAK,MAAA,CAAA,CAGTA,CACX,CAOO,SAAS8H,EAAAA,CAAW9H,CAAAA,CAA8B,CACrD,OAAOA,CAAAA,CAAK,MAAA,EAAQ,IAAA,GAAS,SACjC,CAQO,SAAS+H,CAAAA,CAAgBF,CAAAA,CAAsC,CAClE,GAAA,CAAKA,CAAAA,CAAG,IAAA,GAAS,qBAAA,EAAyBA,CAAAA,CAAG,IAAA,GAAS,oBAAA,GAAyBA,CAAAA,CAAG,EAAA,CAC9E,OAAOA,CAAAA,CAAG,GAAG,IAAA,CAGjB,GAAIA,CAAAA,CAAG,MAAA,CAAO,IAAA,GAAS,oBAAA,EAAwBA,CAAAA,CAAG,MAAA,CAAO,GAAG,IAAA,GAAS,YAAA,CACjE,OAAOA,CAAAA,CAAG,MAAA,CAAO,EAAA,CAAG,IAI5B,CAUO,SAASG,CAAAA,CAAWhI,CAAAA,CAAqBiI,CAAAA,CAA0BC,CAAAA,CAAqC,CAC3G,GAAIlI,CAAAA,CAAK,IAAA,GAAS,iBAAA,CACd,OAAOkI,CAAAA,CAAUlI,CAAAA,CAAK,QAAQ,CAAA,CAGlC,IAAA,IAAW0E,CAAAA,IAAOuD,EAAYjI,CAAAA,CAAK,IAAI,CAAA,EAAK,EAAC,CAAG,CAC5C,IAAM2E,CAAAA,CAAS3E,EAA4C0E,CAAG,CAAA,CACxDyD,CAAAA,CAAW,KAAA,CAAM,OAAA,CAAQxD,CAAK,CAAA,CAAIA,CAAAA,CAAQ,CAACA,CAAK,CAAA,CAEtD,IAAA,IAAWyD,CAAAA,IAASD,CAAAA,CAAU,CAC1B,IAAME,CAAAA,CAAYD,CAAAA,CAClB,GAAI,EAAA,CAACC,CAAAA,EAAa,OAAOA,CAAAA,CAAU,IAAA,EAAS,QAAA,CAAA,EACxC,CAAAjJ,CAAAA,CAAU,SAAA,CAAU,UAAA,CAAW,GAAA,CAAIiJ,CAAAA,CAAU,IAAI,CAAA,EACjDL,CAAAA,CAAWK,EAAWJ,CAAAA,CAAaC,CAAS,CAAA,CAAG,OAAO,KAC9D,CACJ,CAEA,OAAO,MACX,CASO,SAASI,EAAAA,CAAqBT,CAAAA,CAAkBI,CAAAA,CAAmC,CACtF,OAAIJ,CAAAA,CAAG,IAAA,GAAS,yBAAA,EAA6BA,CAAAA,CAAG,IAAA,CAAK,IAAA,GAAS,gBAAA,CACnD,IAAA,CAGJG,CAAAA,CAAWH,EAAG,IAAA,CAAMI,CAAAA,CAAaM,CAAAA,EAAYA,CAAAA,GAAa,IAAI,CACzE,CAOO,SAASC,GAAiBC,CAAAA,CAAgD,CAC7E,OAAIA,CAAAA,CAAW,cAAA,CAAe,IAAA,GAAS,eAAA,CAAwB,IAAA,CAG3DA,EAAW,cAAA,CAAe,IAAA,GAAS,iBAAA,EACnCA,CAAAA,CAAW,cAAA,CAAe,QAAA,CAAS,IAAA,GAAS,YAAA,EAC5CA,CAAAA,CAAW,cAAA,CAAe,QAAA,CAAS,IAAA,GAAS,SAAA,CAGxCA,CAAAA,CAAW,cAAA,CAAe,aAAA,EAAe,OAAO,MAAA,GAAW,CAAA,EAC3DA,CAAAA,CAAW,cAAA,CAAe,aAAA,EAAe,MAAA,CAAO,CAAC,CAAA,EAAG,OAAS,eAAA,CAI9D,KACX,CASO,SAASC,EAAAA,CAAeb,CAAAA,CAAkBI,CAAAA,CAAmC,CAChF,OAAIJ,CAAAA,CAAG,UAAA,CACIW,EAAAA,CAAiBX,CAAAA,CAAG,UAAU,CAAA,CAGlC,CAACS,EAAAA,CAAqBT,CAAAA,CAAII,CAAW,CAChD,CClIA,IAAMU,CAAAA,CAAN,cAAmCnJ,CAAmC,CACzD,IAAA,CAAO,0BAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,aACN,OAAA,CAAS,MAAA,CACT,IAAA,CAAM,CACF,WAAA,CAAa,qEAAA,CACb,WAAA,CAAa,IAAA,CACb,SAAU,MACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,WAAA,CAAaG,CAAAA,CAAQ,CACjB,OAAA,CAAS,oEAAA,CACT,GAAA,CAAK,8FAAA,CACL,GAAA,CAAK,2BACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,IAAMmJ,CAAAA,CAAQ,CAACf,CAAAA,CAAkBgB,CAAAA,GAAgC,CAC7D,IAAMC,CAAAA,CAAQrJ,CAAAA,CAAQ,UAAA,CAAW,iBAAA,CAAkBoJ,CAAM,CAAA,CAAE,EAAA,CAAG,EAAE,CAAA,CAChE,GAAIC,CAAAA,GAAU,MAAA,EAAa,CAAC3H,CAAAA,CAAe2H,CAAK,CAAA,CAAG,OAEnD,IAAMC,CAAAA,CAAQ3G,EAAAA,CAAsB3C,CAAAA,CAAQ,WAAYqJ,CAAK,CAAA,CAE7D,GADIC,CAAAA,GAAU,IAAA,EACV,CAACL,EAAAA,CAAeb,CAAAA,CAAIpI,EAAQ,UAAA,CAAW,WAAW,CAAA,CAAG,OAEzD,IAAMgG,CAAAA,CAAOhG,CAAAA,CAAQ,UAAA,CAAW,gBAAgB,CAAE,IAAA,CAAMsJ,CAAAA,CAAM,IAAA,CAAM,MAAA,CAAQ,CAAE,CAAC,CAAA,CACzExG,CAAAA,CAAK9C,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB,CAAE,IAAA,CAAMsJ,CAAAA,CAAM,EAAA,CAAK,EAAG,MAAA,CAAQ,CAAE,CAAC,CAAA,CAE/EtJ,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAO,CAAE,IAAA,CAAMsJ,CAAAA,CAAM,IAAA,CAAM,MAAA,CAAQ,CAAE,CAAA,CACrC,IAAK,CAAE,IAAA,CAAMA,CAAAA,CAAM,EAAA,CAAI,MAAA,CAAA,CAAStJ,CAAAA,CAAQ,UAAA,CAAW,KAAA,CAAMsJ,CAAAA,CAAM,EAAA,CAAK,CAAC,CAAA,EAAK,EAAA,EAAI,MAAO,CACzF,CAAA,CACA,UAAW,aAAA,CACX,GAAA,CAAKrD,CAAAA,EAASA,CAAAA,CAAM,WAAA,CAAY,CAACD,CAAAA,CAAMlD,CAAE,CAAC,CAC9C,CAAC,EACL,CAAA,CAEA,OAAO,CACH,mBAAA,CAAoBvC,CAAAA,CAAM,CACtB4I,CAAAA,CAAM5I,CAAAA,CAAM4H,CAAAA,CAAoB5H,CAAI,CAAC,EACzC,CAAA,CACA,kBAAA,CAAmBA,CAAAA,CAAM,CAAA,CACjBA,CAAAA,CAAK,IAAA,EAAM,IAAA,GAAS,yBAAA,EAA6BA,CAAAA,CAAK,IAAA,EAAM,OAAS,oBAAA,GACrE4I,CAAAA,CAAM5I,CAAAA,CAAK,IAAA,CAAM4H,CAAAA,CAAoB5H,CAAAA,CAAK,IAAI,CAAC,EAEvD,CAAA,CACA,gBAAA,CAAiBA,CAAAA,CAAM,CACfA,CAAAA,CAAK,KAAA,CAAM,IAAA,GAAS,oBAAA,EACpB4I,EAAM5I,CAAAA,CAAK,KAAA,CAAOA,CAAI,EAE9B,CACJ,CACJ,CACJ,CAAA,CAEOgJ,EAAAA,CAAQ,IAAIL,CAAAA,CCzBZ,SAASM,CAAAA,CAAmB7H,CAAAA,CAAoC,CACnE,OAAOhC,EAAU,QAAA,CAAS,SAAA,CAAU,IAAA,CAAKgC,CAAAA,CAAQ,KAAK,CAC1D,CAUO,SAAS8H,GAAwB9H,CAAAA,CAAkD,CAEtF,IAAMkD,CAAAA,CAAOlD,CAAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,CAAI,EAEhC,GAAIA,CAAAA,CAAQ,IAAA,GAAS,MAAA,CAAQ,CACzB,IAAM2D,CAAAA,CAAQ3D,CAAAA,CAAQ,KAAA,CAAM,KAAA,CAAM,KAAK,CAAA,CACvC,OAAI2D,CAAAA,EAAO,KAAA,GAAU,MAAA,CAAkB,KAEhC,CACH,KAAA,CAAOT,CAAAA,CAAOS,CAAAA,CAAM,KAAA,CACpB,IAAA,CAAMA,CAAAA,CAAM,CAAC,CACjB,CACJ,CAEA,IAAIoE,CAAAA,CAAS,CAAA,CACb,IAAA,IAAWrH,CAAAA,IAAQV,CAAAA,CAAQ,MAAM,KAAA,CAAM;AAAA,CAAI,EAAG,CAG1C,IAAMgI,CAAAA,CAAAA,CAAgBtH,CAAAA,CAAK,MAAM,aAAa,CAAA,GAAI,CAAC,CAAA,EAAK,IAAI,MAAA,CACtDsD,CAAAA,CAAOtD,CAAAA,CAAK,KAAA,CAAMsH,CAAY,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,CAE9C,GAAIhE,CAAAA,GAAS,EAAA,CACT,OAAO,CACH,MAAOd,CAAAA,CAAO6E,CAAAA,CAASC,CAAAA,CACvB,IAAA,CAAAhE,CACJ,CAAA,CAGJ+D,CAAAA,EAAUrH,CAAAA,CAAK,MAAA,CAAS,EAC5B,CAEA,OAAO,IACX,CASO,SAASuH,EAAAA,CAAiBjI,CAAAA,CAA0C,CACvE,IAAMkI,EAAyB,EAAC,CAG1BhF,CAAAA,CAAOlD,CAAAA,CAAQ,MAAM,CAAC,CAAA,CAAI,CAAA,CAC5BmI,CAAAA,CAAuB,KAE3B,IAAA,IAASvD,CAAAA,CAAQ,CAAA,CAAGA,CAAAA,CAAQ5E,EAAQ,KAAA,CAAM,MAAA,CAAQ4E,CAAAA,EAAAA,CAAS,CACvD,IAAMZ,CAAAA,CAAOhE,CAAAA,CAAQ,KAAA,CAAM,MAAA,CAAO4E,CAAK,CAAA,CAGvC,GAAIuD,IAAU,IAAA,CAAM,CACZnE,IAASmE,CAAAA,GAAOA,CAAAA,CAAQ,IAAA,CAAA,CAC5B,QACJ,CAIA,GAAInK,CAAAA,CAAU,QAAA,CAAS,MAAA,CAAO,IAAIgG,CAAI,CAAA,EAAKhE,CAAAA,CAAQ,KAAA,CAAM,SAASgE,CAAAA,CAAMY,CAAAA,CAAQ,CAAC,CAAA,CAAG,CAChFuD,CAAAA,CAAQnE,CAAAA,CACR,QACJ,CAEA,GAAIA,CAAAA,GAAS,GAAA,CAAK,SAGlB,GAAIhE,EAAQ,KAAA,CAAM,MAAA,CAAO4E,CAAAA,CAAQ,CAAC,IAAM,GAAA,CAAK,CACzC,KAAO5E,CAAAA,CAAQ,MAAM,MAAA,CAAO4E,CAAAA,CAAQ,CAAC,CAAA,GAAM,KAAKA,CAAAA,EAAAA,CAChD,QACJ,CAEA,IAAMwD,EAAOpI,CAAAA,CAAQ,KAAA,CAAM,KAAA,CAAM4E,CAAAA,CAAQ,CAAC,CAAA,CAItCwD,CAAAA,GAAS,EAAA,EAAM,CAAC,OAAO,IAAA,CAAKA,CAAI,CAAA,EAEhCC,EAAAA,CAAqBrI,EAAQ,KAAA,CAAM,KAAA,CAAM,CAAA,CAAG4E,CAAAA,CAAQ,CAAC,CAAC,CAAA,EAE1DsD,CAAAA,CAAQ,IAAA,CAAK,CACT,KAAA,CAAOhF,CAAAA,CAAO0B,EACd,QAAA,CAAUwD,CAAAA,CAAK,MAAK,GAAM,EAC9B,CAAC,EACL,CAEA,OAAOF,CACX,CASO,SAASI,GAAkBtI,CAAAA,CAA2C,CACzE,IAAMuI,CAAAA,CAAwB,EAAC,CAGzBrF,CAAAA,CAAOlD,CAAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,CAAI,CAAA,CAEhC,IAAA,IAAS4E,CAAAA,CAAQ,EAAGA,CAAAA,CAAQ5E,CAAAA,CAAQ,KAAA,CAAM,MAAA,CAAQ4E,IAAS,CACvD,GAAI5E,CAAAA,CAAQ,KAAA,CAAM,OAAO4E,CAAK,CAAA,GAAM,GAAA,CAAK,SAGzC,GAAI5E,CAAAA,CAAQ,KAAA,CAAM,MAAA,CAAO4E,CAAAA,CAAQ,CAAC,CAAA,GAAM,GAAA,CAAK,CACzC,KAAO5E,EAAQ,KAAA,CAAM,MAAA,CAAO4E,CAAAA,CAAQ,CAAC,IAAM,GAAA,EAAKA,CAAAA,EAAAA,CAChD,QACJ,CAEA,IAAM4D,CAAAA,CAAUxI,CAAAA,CAAQ,KAAA,CAAM,OAAA,CAAQ,IAAK4E,CAAAA,CAAQ,CAAC,CAAA,CACpD,GAAI4D,IAAY,EAAA,CAAI,MAEpB,IAAM/E,CAAAA,CAAOzD,EAAQ,KAAA,CAAM,KAAA,CAAM4E,EAAQ,CAAA,CAAG4D,CAAO,EAG9C/E,CAAAA,CAAK,QAAA,CAAS,GAAG,CAAA,EAClB8E,EAAM,IAAA,CAAK,CACP,KAAA,CAAOrF,CAAAA,CAAO0B,EACd,GAAA,CAAK1B,CAAAA,CAAOsF,CAAAA,CACZ,IAAA,CAAA/E,CACJ,CAAC,CAAA,CAGLmB,CAAAA,CAAQ4D,EACZ,CAEA,OAAOD,CACX,CAQA,SAASF,GAAqB5E,CAAAA,CAAuB,CACjD,IAAMgF,CAAAA,CAAYhF,EAAK,WAAA,EAAY,CAEnC,OAAOzF,CAAAA,CAAU,SAAS,aAAA,CAAc,IAAA,CAAK0K,CAAAA,EAAgB,CACzD,GAAI,CAACD,CAAAA,CAAU,QAAA,CAASC,CAAY,EAAG,OAAO,MAAA,CAG9C,IAAMC,CAAAA,CAASF,EAAU,MAAA,CAAOA,CAAAA,CAAU,MAAA,CAASC,CAAAA,CAAa,OAAS,CAAC,CAAA,CAC1E,OAAOC,CAAAA,GAAW,IAAM,CAAC5E,EAAAA,CAAW4E,CAAM,CAC9C,CAAC,CACL,CCtMA,IAAMC,CAAAA,CAAN,cAAqCxK,CAAmC,CAC3D,IAAA,CAAO,2BAAA,CAEP,eAA0B,EAAC,CAE3B,KAAO,CACZ,IAAA,CAAM,aACN,OAAA,CAAS,MAAA,CACT,IAAA,CAAM,CACF,YAAa,kFAAA,CACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,SAAU,CACN,SAAA,CAAWG,CAAAA,CAAQ,CACf,QAAS,kDAAA,CACT,GAAA,CAAK,kIAAA,CACL,GAAA,CAAK,8CACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,SAAU,CACN,IAAA,IAAW2B,CAAAA,IAAW3B,CAAAA,CAAQ,WAAW,cAAA,EAAe,CAGpD,GAAI,EAAA2B,EAAQ,IAAA,GAAS,MAAA,EAAU6H,CAAAA,CAAmB7H,CAAO,GAEzD,IAAA,IAAW6I,CAAAA,IAAQP,EAAAA,CAAkBtI,CAAO,EACxC3B,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAOA,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgBwK,EAAK,KAAK,CAAA,CACpD,GAAA,CAAKxK,CAAAA,CAAQ,WAAW,eAAA,CAAgBwK,CAAAA,CAAK,GAAA,CAAM,CAAC,CACxD,CAAA,CACA,SAAA,CAAW,YACX,IAAA,CAAM,CAAE,KAAMA,CAAAA,CAAK,IAAK,CAAA,CACxB,GAAA,CAAKvE,GAAS,CACVA,CAAAA,CAAM,gBAAA,CAAiB,CAACuE,EAAK,KAAA,CAAOA,CAAAA,CAAK,KAAA,CAAQ,CAAC,EAAG,GAAG,CAAA,CACxDvE,CAAAA,CAAM,gBAAA,CAAiB,CAACuE,CAAAA,CAAK,GAAA,CAAKA,CAAAA,CAAK,GAAA,CAAM,CAAC,CAAA,CAAG,GAAG,CACxD,CACJ,CAAC,EAGb,CACJ,CACJ,CACJ,EAEOC,EAAAA,CAAQ,IAAIF,CAAAA,CCnDnB,IAAMG,EAAN,cAAkC3K,CAAmC,CACxD,IAAA,CAAO,yBAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,QAAA,CACN,OAAA,CAAS,MAAA,CACT,KAAM,CACF,WAAA,CAAa,8FAAA,CACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,SAAU,CACN,MAAA,CAAQG,CAAAA,CAAQ,CACZ,QAAS,uCAAA,CACT,GAAA,CAAK,gKAAA,CACL,GAAA,CAAK,+CACT,CAAC,CAAA,CACD,SAAUA,CAAAA,CAAQ,CACd,QAAS,8DAAA,CACT,GAAA,CAAK,gJAAA,CACL,GAAA,CAAK,6EACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAAqF,CAGxF,IAAM2K,CAAAA,CAAiBhJ,GAA6C,CAChE,IAAM2I,CAAAA,CAAAA,CAAUtK,CAAAA,CAAQ,WAAW,KAAA,CAAM2B,CAAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,KAAO,CAAC,CAAA,EAAK,EAAA,EAAI,KAAA,CACxE,EACAA,CAAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,MACtB,EAEA,OAAO2I,CAAAA,CAAO,IAAA,EAAK,GAAM,GAAKA,CAAAA,CAAS,IAC3C,CAAA,CAEA,OAAO,CACH,OAAA,EAAU,CACN,IAAA,IAAW3I,CAAAA,IAAW3B,EAAQ,UAAA,CAAW,cAAA,EAAe,CAAG,CACvD,GAAI2B,CAAAA,CAAQ,IAAA,GAAS,MAAA,CAAQ,SAE7B,IAAMiJ,CAAAA,CAASD,CAAAA,CAAchJ,CAAO,CAAA,CAEpC,QAAWkJ,CAAAA,IAAUjB,EAAAA,CAAiBjI,CAAO,CAAA,CAAG,CAC5C,IAAMmJ,CAAAA,CAAM,CACR,KAAA,CAAO9K,EAAQ,UAAA,CAAW,eAAA,CAAgB6K,EAAO,KAAK,CAAA,CACtD,IAAK7K,CAAAA,CAAQ,UAAA,CAAW,eAAA,CAAgB6K,CAAAA,CAAO,MAAQ,CAAC,CAC5D,CAAA,CAIA,GAAIA,EAAO,QAAA,CAAU,CACjB7K,CAAAA,CAAQ,MAAA,CAAO,CACX,GAAA,CAAA8K,CAAAA,CACA,SAAA,CAAW,QAAA,CACX,IAAK7E,CAAAA,EAASA,CAAAA,CAAM,WAAA,CAAY,CAAC4E,EAAO,KAAA,CAAOA,CAAAA,CAAO,KAAA,CAAQ,CAAC,CAAC,CACpE,CAAC,CAAA,CAED,QACJ,CAKA,IAAMnB,CAAAA,CAASmB,CAAAA,CAAO,KAAA,CAAQlJ,EAAQ,KAAA,CAAM,CAAC,CAAA,CAAI,CAAA,CAC3CoJ,EAAUpJ,CAAAA,CAAQ,KAAA,CAAM,KAAA,CAAM+H,CAAAA,CAAS,CAAC,CAAA,CAAE,KAAA,CAAM,OAAO,CAAA,GAAI,CAAC,CAAA,EAAK,EAAA,CACjEhC,CAAAA,CAAMmD,CAAAA,CAAO,MAAQ,CAAA,CAAIE,CAAAA,CAAQ,MAAA,CAEvC/K,CAAAA,CAAQ,OAAO,CACX,GAAA,CAAA8K,CAAAA,CACA,SAAA,CAAW,WACX,GAAA,CACIF,CAAAA,GAAW,IAAA,CACL,IAAA,CACA3E,GAASA,CAAAA,CAAM,gBAAA,CAAiB,CAAC4E,CAAAA,CAAO,KAAA,CAAOnD,CAAG,CAAA,CAAG;AAAA,EAAKkD,CAAM,KAAK,CACnF,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOI,GAAQ,IAAIN,CAAAA,CC3DnB,IAAMO,CAAAA,CAAN,cAAoClL,CAAmC,CAC1D,IAAA,CAAO,0BAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,KAAM,CACF,WAAA,CACI,mGACJ,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,mBAAA,CAAqBG,CAAAA,CAAQ,CACzB,QAAS,+DAAA,CACT,GAAA,CAAK,iGAAA,CACL,GAAA,CAAK,mFACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAAqF,CACxF,IAAMkL,CAAAA,CAA0B,EAAC,CAC3B/G,CAAAA,CAAU,IAAI,GAAA,CAIdgH,EAAe9G,CAAAA,EAAgC,CACjD,GAAIA,CAAAA,CAAO,IAAA,GAAS,kBAAA,CAAoB,OAExC,IAAMD,CAAAA,CAAOZ,CAAAA,CAAmBa,CAAM,CAAA,CAClCD,CAAAA,GAAS,MAAMD,CAAAA,CAAQ,GAAA,CAAIC,CAAI,EACvC,CAAA,CAEA,OAAO,CACH,oBAAA,CAAqB7D,CAAAA,CAAM,CACvB4K,CAAAA,CAAY5K,CAAAA,CAAK,IAAI,EACzB,CAAA,CAEA,gBAAA,CAAiBA,CAAAA,CAAM,CACnB4K,CAAAA,CAAY5K,EAAK,QAAQ,EAC7B,CAAA,CAEA,kBAAA,CAAmBA,CAAAA,CAAM,CAUrB,GATIA,CAAAA,CAAK,MAAA,CAAO,OAAS,qBAAA,EAAyBA,CAAAA,CAAK,OAAO,IAAA,GAAS,OAAA,EAGnEA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAA,GAAS,0BAE5BA,CAAAA,CAAK,EAAA,CAAG,IAAA,GAAS,YAAA,EAAgBA,CAAAA,CAAK,IAAA,GAAS,MAI/CA,CAAAA,CAAK,EAAA,CAAG,cAAA,GAAmB,MAAA,CAAW,OAE1C,IAAM6D,EAAOZ,CAAAA,CAAmBjD,CAAAA,CAAK,IAAI,CAAA,CACzC,GAAI6D,IAAS,IAAA,CAAM,OAInB,IAAMvD,CAAAA,CAAOuD,CAAAA,CAAK,KAAA,CAAM,EAAGA,CAAAA,CAAK,OAAA,CAAQ,GAAG,CAAC,CAAA,CACxCvD,CAAAA,GAAS,QAAU8C,CAAAA,CAAa3D,CAAAA,CAAQ,UAAA,CAAW,QAAA,CAASO,CAAI,CAAA,CAAGM,CAAI,CAAA,EAE3EqK,CAAAA,CAAW,KAAK,CACZ,IAAA,CAAA3K,EACA,IAAA,CAAMA,CAAAA,CAAK,EAAA,CAAG,IAAA,CACd,IAAA,CAAA6D,CAAAA,CACA,WAAYpE,CAAAA,CAAQ,UAAA,CAAW,OAAA,CAAQO,CAAAA,CAAK,IAAI,CACpD,CAAC,EACL,CAAA,CAEA,cAAA,EAAiB,CACb,IAAA,IAAW6K,CAAAA,IAAaF,EAChBhH,EAAAA,CAAcC,CAAAA,CAASiH,EAAU,IAAI,CAAA,EAEzCpL,EAAQ,MAAA,CAAO,CACX,IAAA,CAAMoL,CAAAA,CAAU,IAAA,CAChB,SAAA,CAAW,sBACX,IAAA,CAAM,CACF,IAAA,CAAMA,CAAAA,CAAU,IAAA,CAChB,UAAA,CAAYA,EAAU,UAC1B,CACJ,CAAC,EAET,CACJ,CACJ,CACJ,CAAA,CAEOC,EAAAA,CAAQ,IAAIJ,CAAAA,CCtHnB,IAAMK,EAAN,cAAsCvL,CAAmC,CAC5D,IAAA,CAAO,2BAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,8FAAA,CACb,WAAA,CAAa,IAAA,CACb,QAAA,CAAU,MACd,EACA,MAAA,CAAQ,GACR,QAAA,CAAU,CACN,YAAaG,CAAAA,CAAQ,CACjB,OAAA,CAAS,mEAAA,CACT,GAAA,CAAK,4KAAA,CACL,IAAK,yEACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,EAAqF,CACxF,OAAO,CACH,kBAAA,CAAmBO,CAAAA,CAAM,CACjBA,EAAK,MAAA,CAAO,IAAA,GAAS,uBAAyBA,CAAAA,CAAK,MAAA,CAAO,OAAS,OAAA,EACnEA,CAAAA,CAAK,MAAA,CAAO,MAAA,CAAO,IAAA,GAAS,wBAAA,GAC5BA,EAAK,EAAA,CAAG,IAAA,GAAS,eAAA,EAAmBA,CAAAA,CAAK,IAAA,GAAS,IAAA,EAIlDA,EAAK,IAAA,CAAK,IAAA,GAAS,YAAA,EAAgB,CAACmD,EAAAA,CAAsBnD,CAAAA,CAAK,IAAI,CAAA,EAIlE+D,EAAAA,CAAe/D,EAAK,EAAE,CAAA,EAE3BP,EAAQ,MAAA,CAAO,CACX,IAAA,CAAAO,CAAAA,CACA,SAAA,CAAW,aAAA,CACX,KAAM,CAAE,MAAA,CAAQP,CAAAA,CAAQ,UAAA,CAAW,OAAA,CAAQO,CAAAA,CAAK,IAAI,CAAE,CAC1D,CAAC,CAAA,EACL,CACJ,CACJ,CACJ,CAAA,CAEOgL,EAAAA,CAAQ,IAAID,CAAAA,CC3CnB,IAAME,EAAN,cAAgCzL,CAAmC,CACtD,IAAA,CAAO,sBAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,QAAA,CACN,OAAA,CAAS,OACT,IAAA,CAAM,CACF,WAAA,CAAa,iFAAA,CACb,WAAA,CAAa,IACjB,EACA,MAAA,CAAQ,GACR,QAAA,CAAU,CACN,WAAYG,CAAAA,CAAQ,CAChB,OAAA,CAAS,iDAAA,CACT,GAAA,CAAK,oGAAA,CACL,IAAK,wFACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,EAAqF,CACxF,OAAO,CACH,OAAA,EAAU,CACN,IAAA,IAAW2B,KAAW3B,CAAAA,CAAQ,UAAA,CAAW,gBAAe,CAAG,CAGvD,GADI,CAAC0B,CAAAA,CAAeC,CAAO,CAAA,EACvBA,CAAAA,CAAQ,GAAA,CAAI,MAAM,IAAA,GAASA,CAAAA,CAAQ,GAAA,CAAI,GAAA,CAAI,IAAA,CAAM,SAGrD,IAAMe,CAAAA,CAAUf,CAAAA,CAAQ,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAO,EAAE,EAAE,IAAA,EAAK,CAIlDe,CAAAA,CAAQ,MAAA,GAAW,CAAA,EAEvB1C,CAAAA,CAAQ,OAAO,CACX,GAAA,CAAK2B,CAAAA,CAAQ,GAAA,CACb,SAAA,CAAW,YAAA,CACX,IAAIsE,CAAAA,CAAO,CACP,IAAM2E,CAAAA,CAAS,GAAA,CAAI,MAAA,CAAOjJ,EAAQ,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA,CAC5C8J,CAAAA,CAAW,CAAA;AAAA,EAAQb,CAAM,MAAMlI,CAAO;AAAA,EAAKkI,CAAM,CAAA,GAAA,CAAA,CACvD,OAAO3E,EAAM,gBAAA,CAAiBtE,CAAAA,CAAQ,MAAO8J,CAAQ,CACzD,CACJ,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOC,GAAQ,IAAIF,CAAAA,CCvDnB,IAAMG,CAAAA,CAAN,cAAyC5L,CAAmC,CAC/D,KAAO,8BAAA,CAEP,cAAA,CAA0B,EAAC,CAE3B,IAAA,CAAO,CACZ,IAAA,CAAM,YAAA,CACN,QAAS,MAAA,CACT,IAAA,CAAM,CACF,WAAA,CAAa,sDAAA,CACb,YAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,OAAQ,EAAC,CACT,SAAU,CACN,UAAA,CAAYG,EAAQ,CAChB,OAAA,CAAS,+CACT,GAAA,CAAK,4EAAA,CACL,IAAK,4CACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAAqF,CAGxF,IAAM4L,CAAAA,CAAkBjK,GAAuC,CAC3D,GAAIA,EAAQ,IAAA,GAAS,MAAA,CAAQ,OAAO,MAAA,CAEpC,IAAMkK,EAAW7L,CAAAA,CAAQ,UAAA,CAAW,MAAM2B,CAAAA,CAAQ,GAAA,CAAI,MAAM,IAAA,CAAO,CAAC,EACpE,OAAOkK,CAAAA,GAAa,MAAA,EAAa,UAAA,CAAW,KAAKA,CAAQ,CAC7D,EAEA,OAAO,CACH,SAAU,CACN,IAAA,IAAWlK,CAAAA,IAAW3B,CAAAA,CAAQ,WAAW,cAAA,EAAe,CAAG,CACvD,GAAIwJ,CAAAA,CAAmB7H,CAAO,CAAA,EAAKiK,CAAAA,CAAejK,CAAO,CAAA,CAAG,SAE5D,IAAMe,CAAAA,CAAU+G,GAAwB9H,CAAO,CAAA,CAC3Ce,IAAY,IAAA,EAAQ,CAAC,WAAC,SAAA,CAAO,GAAC,EAAC,IAAA,CAAKA,CAAAA,CAAQ,IAAI,CAAA,EAIhD,yBAAA,CAA0B,KAAK1C,CAAAA,CAAQ,UAAA,CAAW,OAAA,EAAQ,CAAE,MAAM0C,CAAAA,CAAQ,KAAK,CAAC,CAAA,EAEpF1C,CAAAA,CAAQ,OAAO,CACX,GAAA,CAAK,CACD,KAAA,CAAOA,CAAAA,CAAQ,WAAW,eAAA,CAAgB0C,CAAAA,CAAQ,KAAK,CAAA,CACvD,GAAA,CAAK1C,EAAQ,UAAA,CAAW,eAAA,CAAgB0C,CAAAA,CAAQ,KAAA,CAAQA,EAAQ,IAAA,CAAK,MAAM,CAC/E,CAAA,CACA,SAAA,CAAW,aACX,GAAA,CAAKuD,CAAAA,EACDA,EAAM,gBAAA,CACF,CAACvD,EAAQ,KAAA,CAAOA,CAAAA,CAAQ,MAAQA,CAAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,CACnDA,CAAAA,CAAQ,IAAA,CAAK,WAAA,EACjB,CACR,CAAC,EACL,CACJ,CACJ,CACJ,CACJ,CAAA,CAEOoJ,EAAAA,CAAQ,IAAIH,ECnEZ,IAAMI,EAAAA,CAA8C,CACvD,QAAA,CAAU,UAAA,CACV,MAAO,OACX,CAAA,CAOA,SAASC,EAAAA,CAAc9J,EAAqD,CACxE,IAAM+J,EAAoB,EAAC,CAE3B,QAAWtL,CAAAA,IAAauB,CAAAA,CAAW,IAAI,IAAA,CAC/BvB,CAAAA,CAAU,OAAS,mBAAA,EACnBsL,CAAAA,CAAQ,KAAK,MAAA,CAAOtL,CAAAA,CAAU,OAAO,KAAK,CAAC,CAAA,CAInD,OAAOsL,CACX,CASO,SAASC,GAAiBhK,CAAAA,CAA2CuE,CAAAA,CAAkC,CAC1G,IAAM0F,CAAAA,CAAW,IAAI,GAAA,CACfF,CAAAA,CAAUD,GAAc9J,CAAU,CAAA,CAExC,OAAI+J,CAAAA,CAAQ,IAAA,CAAKzG,GAAUA,CAAAA,CAAO,UAAA,CAAW,YAAY,CAAA,EAAK7F,EAAU,UAAA,CAAW,cAAA,CAAe,KAAK6F,CAAM,CAAC,GAC1G2G,CAAAA,CAAS,GAAA,CAAI,UAAU,CAAA,CAAA,CAGNF,CAAAA,CAAQ,KACzBzG,CAAAA,EAAUA,CAAAA,GAAW,SAAWA,CAAAA,CAAO,UAAA,CAAW,QAAQ,CAAA,EAAKA,CAAAA,GAAW,WAC9E,CAAA,EACoB7F,EAAU,UAAA,CAAW,UAAA,CAAW,KAAK8G,CAAQ,CAAA,GAC7D0F,EAAS,GAAA,CAAI,OAAO,EAGjBA,CACX,CCzCA,IAAMC,CAAAA,CAAN,cAAqCrM,CAAmC,CAC3D,IAAA,CAAO,2BAEP,cAAA,CAA0B,CAAC,CAAE,MAAA,CAAQ,EAAG,CAAC,EAEzC,IAAA,CAAO,CACZ,KAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,0EAAA,CACb,YAAa,IAAA,CACb,QAAA,CAAU,MACd,CAAA,CACA,MAAA,CAAQ,CACJ,CACI,IAAA,CAAM,QAAA,CACN,UAAA,CAAY,CACR,MAAA,CAAQ,CACJ,KAAM,OAAA,CACN,KAAA,CAAO,CACH,IAAA,CAAM,QAAA,CACN,KAAM,CAAC,UAAA,CAAY,OAAO,CAC9B,CACJ,CACJ,CAAA,CACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,QAAA,CAAU,CACN,cAAeG,CAAAA,CAAQ,CACnB,QAAS,qFAAA,CACT,GAAA,CAAK,sGACL,GAAA,CAAK,oIACT,CAAC,CACL,CACJ,EAEA,MAAA,CAAOF,CAAAA,CAA8DC,EAAyC,CAC1G,IAAMoM,EAAU,IAAI,GAAA,CAAIpM,CAAAA,CAAQ,CAAC,GAAG,MAAA,EAAU,EAAE,CAAA,CAG1CqM,CAAAA,CAAWtM,EAAQ,QAAA,CAASL,CAAAA,CAAU,WAAW,CAAA,EAAK,EAAC,CAE7D,OAAO,CACH,OAAA,CAAQY,CAAAA,CAAM,CACV,IAAM4L,CAAAA,CAAWD,EAAAA,CAAiBlM,CAAAA,CAAQ,WAAYA,CAAAA,CAAQ,QAAQ,EAEtE,IAAA,IAAWuM,CAAAA,IAAaJ,EAChBE,CAAAA,CAAQ,GAAA,CAAIE,CAAS,CAAA,EAAKD,CAAAA,CAAQC,CAAS,CAAA,EAE/CvM,CAAAA,CAAQ,OAAO,CACX,IAAA,CAAAO,EACA,SAAA,CAAW,eAAA,CACX,IAAA,CAAM,CAAE,UAAWwL,EAAAA,CAAiBQ,CAAS,EAAG,MAAA,CAAQA,CAAU,CACtE,CAAC,EAET,CACJ,CACJ,CACJ,EAEOC,EAAAA,CAAQ,IAAIJ,ECjEZ,SAASK,EAAAA,CAAqB3M,EAAuB,CACxD,OAAO,QAAA,CAAS,IAAA,CAAKA,CAAI,CAC7B,CAQO,SAAS4M,EAAAA,CAAW5M,CAAAA,CAAuB,CAC9C,OAAOH,CAAAA,CAAU,MAAM,IAAA,CAAK,IAAA,CAAKG,CAAI,CACzC,CAQO,SAAS6M,EAAAA,CAAkB7M,CAAAA,CAAuB,CACrD,OAAOH,CAAAA,CAAU,KAAA,CAAM,YAAA,CAAa,KAAKG,CAAI,CACjD,CAQO,SAAS8M,CAAAA,CAAgBrM,EAAuD,CACnF,OAAKA,EACDA,CAAAA,CAAK,IAAA,GAAS,2BAA6BA,CAAAA,CAAK,IAAA,GAAS,qBAA6B,IAAA,CAEnFA,CAAAA,CAAK,OAAS,gBAAA,EAAoBA,CAAAA,CAAK,MAAA,CAAO,IAAA,GAAS,cAAgBA,CAAAA,CAAK,MAAA,CAAO,OAAS,aAAA,CAHjF,KAItB,CAQO,SAASsM,CAAAA,CAAgBtM,EAAuD,CACnF,GAAI,CAACA,CAAAA,CAAM,OAAO,OAElB,OAAQA,CAAAA,CAAK,MACT,KAAK,YAAA,CACL,KAAK,cACD,OAAO,KAAA,CACX,KAAK,uBAAA,CACD,OAAOsM,EAAgBtM,CAAAA,CAAK,UAAU,GAAKsM,CAAAA,CAAgBtM,CAAAA,CAAK,SAAS,CAAA,CAC7E,KAAK,oBACD,OAAOsM,CAAAA,CAAgBtM,EAAK,IAAI,CAAA,EAAKsM,CAAAA,CAAgBtM,CAAAA,CAAK,KAAK,CAAA,CACnE,KAAK,qBACD,OAAOsM,CAAAA,CAAgBtM,EAAK,WAAA,CAAY,EAAA,CAAG,EAAE,CAAC,CAAA,CAClD,QACI,OAAO,MACf,CACJ,CASO,SAASuM,GAAmB1E,CAAAA,CAAkBI,CAAAA,CAAmC,CAEpF,OAAIJ,EAAG,IAAA,GAAS,yBAAA,EAA6BA,EAAG,IAAA,CAAK,IAAA,GAAS,iBACnDyE,CAAAA,CAAgBzE,CAAAA,CAAG,IAAI,CAAA,CAG3BG,EAAWH,CAAAA,CAAG,IAAA,CAAMI,EAAaqE,CAAe,CAC3D,CCtEA,IAAME,CAAAA,CAAN,cAAmChN,CAAmC,CACzD,IAAA,CAAO,wBAAA,CAEP,eAA0B,EAAC,CAE3B,KAAO,CACZ,IAAA,CAAM,aACN,IAAA,CAAM,CACF,YAAa,mFAAA,CACb,WAAA,CAAa,IACjB,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,YAAA,CAAcG,EAAQ,CAClB,OAAA,CAAS,gDACT,GAAA,CAAK,kIAAA,CACL,IAAK,wFACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAAqF,CACxF,IAAMmJ,CAAAA,CAAQ,CAACf,EAAkB4E,CAAAA,GAAoC,CACjE,IAAMlN,CAAAA,CAAOwI,EAAgBF,CAAE,CAAA,CAE/B,GAAItI,CAAAA,GAAS,MAAA,CAAW,OAExB,IAAMmN,CAAAA,CAAe9E,EAAoBC,CAAE,CAAA,CACtCC,GAAW4E,CAAY,CAAA,GAGxBR,GAAqB3M,CAAI,CAAA,EAAKgN,GAAmB1E,CAAAA,CAAIpI,CAAAA,CAAQ,UAAA,CAAW,WAAW,GAEnFiC,CAAAA,CAAgBjC,CAAAA,CAAQ,WAAYiN,CAAY,CAAA,EAEpDjN,EAAQ,MAAA,CAAO,CACX,KAAMgN,CAAAA,CACN,SAAA,CAAW,eACX,IAAA,CAAM,CAAE,KAAAlN,CAAK,CACjB,CAAC,CAAA,EACL,CAAA,CAEA,OAAO,CACH,oBAAoBS,CAAAA,CAAM,CACtB4I,EAAM5I,CAAAA,CAAMA,CAAAA,CAAK,IAAMA,CAAI,EAC/B,EACA,kBAAA,CAAmBA,CAAAA,CAAM,CAChBA,CAAAA,CAAK,IAAA,GACNA,EAAK,IAAA,CAAK,IAAA,GAAS,2BAA6BA,CAAAA,CAAK,IAAA,CAAK,IAAA,GAAS,oBAAA,EAEvE4I,EAAM5I,CAAAA,CAAK,IAAA,CAAMA,EAAK,EAAE,CAAA,EAC5B,CACJ,CACJ,CACJ,EAEO2M,EAAAA,CAAQ,IAAIH,EC5DZ,SAASI,EAAAA,CACZjL,EACA3B,CAAAA,CACAqK,CAAAA,CACM,CAEN,IAAMwC,CAAAA,CAAAA,CADclL,CAAAA,CAAW,KAAA,CAAM3B,EAAK,GAAA,CAAI,KAAA,CAAM,KAAO,CAAC,CAAA,EAAK,IAClC,KAAA,CAAM,MAAM,IAAI,CAAC,CAAA,EAAK,GAC/C8M,CAAAA,CAAiBD,CAAAA,CAAa,IAAI,MAAA,CAAOxC,CAAM,EAIrD,OAAO,CAAA;AAAA,EAFMrK,CAAAA,CAAK,UAAA,CAAW,GAAA,CAAIiE,CAAAA,EAAY,CAAA,EAAG6I,CAAc,CAAA,EAAGnL,CAAAA,CAAW,OAAA,CAAQsC,CAAQ,CAAC,CAAA,CAAE,EAAE,IAAA,CAAK,CAAA;AAAA,CAAK,CAE1F,CAAA;AAAA,EAAM4I,CAAU,GACrC,CCRA,IAAME,EAAN,cAAqCvN,CAAmC,CAC3D,IAAA,CAAO,0BAAA,CACP,eAA0B,CAC/B,CACI,QAASJ,CAAAA,CAAU,OAAA,CAAQ,gBAC3B,MAAA,CAAQA,CAAAA,CAAU,QAAQ,YAC9B,CACJ,EAES,IAAA,CAAO,CACZ,KAAM,YAAA,CACN,OAAA,CAAS,aACT,IAAA,CAAM,CACF,YAAa,mFAAA,CACb,WAAA,CAAa,KACb,QAAA,CAAU,MACd,EACA,MAAA,CAAQ,CACJ,CACI,IAAA,CAAM,QAAA,CACN,UAAA,CAAY,CACR,OAAA,CAAS,CAAE,KAAM,SAAA,CAAW,OAAA,CAAS,CAAE,CAAA,CACvC,MAAA,CAAQ,CAAE,IAAA,CAAM,SAAA,CAAW,QAAS,CAAE,CAC1C,EACA,oBAAA,CAAsB,KAC1B,CACJ,CAAA,CACA,QAAA,CAAU,CACN,UAAA,CAAYO,CAAAA,CAAQ,CAChB,OAAA,CAAS,yEAAA,CACT,IAAK,uHAAA,CACL,GAAA,CAAK,6EACT,CAAC,CACL,CACJ,CAAA,CAEA,MAAA,CAAOF,EAA8DC,CAAAA,CAAyC,CAC1G,IAAMsN,CAAAA,CAAUtN,CAAAA,CAAQ,CAAC,CAAA,EAAG,OAAA,EAAWN,EAAU,OAAA,CAAQ,eAAA,CACnDiL,CAAAA,CAAS3K,CAAAA,CAAQ,CAAC,CAAA,EAAG,QAAUN,CAAAA,CAAU,OAAA,CAAQ,aAEvD,OAAO,CACH,iBAAiBY,CAAAA,CAAM,CACfA,EAAK,UAAA,CAAW,MAAA,EAAUgN,GAC1BhN,CAAAA,CAAK,GAAA,CAAI,MAAM,IAAA,GAASA,CAAAA,CAAK,IAAI,GAAA,CAAI,IAAA,EAEzCP,EAAQ,MAAA,CAAO,CACX,KAAAO,CAAAA,CACA,SAAA,CAAW,aACX,IAAA,CAAM,CAAE,MAAOA,CAAAA,CAAK,UAAA,CAAW,OAAQ,GAAA,CAAKgN,CAAQ,EACpD,GAAA,CAAKtH,CAAAA,EAASA,EAAM,WAAA,CAAY1F,CAAAA,CAAM4M,GAAoBnN,CAAAA,CAAQ,UAAA,CAAYO,CAAAA,CAAMqK,CAAM,CAAC,CAC/F,CAAC,EACL,CACJ,CACJ,CACJ,CAAA,CAEO4C,GAAQ,IAAIF,CAAAA,CCzDnB,IAAMG,CAAAA,CAAN,cAA4C1N,CAAmC,CAClE,IAAA,CAAO,mCAEP,cAAA,CAA0B,GAE1B,IAAA,CAAO,CACZ,KAAM,YAAA,CACN,IAAA,CAAM,CACF,WAAA,CAAa,mEAAA,CACb,YAAa,IAAA,CACb,QAAA,CAAU,OACd,CAAA,CACA,MAAA,CAAQ,EAAC,CACT,QAAA,CAAU,CACN,WAAA,CAAaG,CAAAA,CAAQ,CACjB,OAAA,CAAS,oDAAA,CACT,IAAK,2HAAA,CACL,GAAA,CAAK,oEACT,CAAC,CACL,CACJ,EAEA,MAAA,CAAOF,CAAAA,CAAqF,CACxF,OAAO,CACH,mBAAmBO,CAAAA,CAAM,CACjBA,EAAK,EAAA,CAAG,IAAA,GAAS,cAAgBA,CAAAA,CAAK,IAAA,EAAM,OAAS,gBAAA,EACrDA,CAAAA,CAAK,KAAK,MAAA,CAAO,IAAA,GAAS,cAAgB,CAACoM,EAAAA,CAAkBpM,EAAK,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,EAEtFP,CAAAA,CAAQ,OAAO,CACX,IAAA,CAAAO,EACA,SAAA,CAAW,aAAA,CACX,KAAM,CAAE,IAAA,CAAMA,EAAK,IAAA,CAAK,MAAA,CAAO,KAAM,IAAA,CAAMA,CAAAA,CAAK,EAAA,CAAG,IAAK,CAC5D,CAAC,EACL,CACJ,CACJ,CACJ,CAAA,CAEOmN,EAAAA,CAAQ,IAAID,CAAAA,CCrCnB,IAAME,EAAAA,CAAN,cAAsC5N,CAAmC,CAC5D,IAAA,CAAO,6BAEP,cAAA,CAA0B,GAE1B,IAAA,CAAO,CACZ,KAAM,YAAA,CACN,OAAA,CAAS,OACT,IAAA,CAAM,CACF,YAAa,wEAAA,CACb,WAAA,CAAa,KACb,QAAA,CAAU,OACd,EACA,MAAA,CAAQ,GACR,QAAA,CAAU,CACN,aAAcG,CAAAA,CAAQ,CAClB,OAAA,CAAS,yDAAA,CACT,GAAA,CAAK,8HAAA,CACL,IAAK,qEACT,CAAC,CACL,CACJ,CAAA,CAEA,OAAOF,CAAAA,CAAqF,CAGxF,IAAM4N,CAAAA,CAAmB9E,CAAAA,EAA2C,CAChE,GAAI8D,CAAAA,CAAgB9D,CAAQ,CAAA,CAAG,OAAO,MACtC,GAAIA,CAAAA,CAAS,OAAS,YAAA,CAAc,OAAO,OAG3C,IAAM+E,CAAAA,CADW/J,SAAS,YAAA,CAAa9D,CAAAA,CAAQ,WAAW,QAAA,CAAS8I,CAAQ,EAAGA,CAAAA,CAAS,IAAI,GAC9D,IAAA,CAAK,EAAA,CAAG,EAAE,CAAA,EAAG,IAAA,CAC1C,OAAO+E,CAAAA,EAAY,IAAA,GAAS,oBAAA,EAAwBjB,CAAAA,CAAgBiB,CAAAA,CAAW,IAAI,CACvF,CAAA,CAEMC,CAAAA,CAAUhF,GAAwC,CACpD9I,CAAAA,CAAQ,OAAO,CACX,IAAA,CAAM8I,EACN,SAAA,CAAW,cAAA,CACX,IACIA,CAAAA,CAAS,IAAA,GAAS,aACZ7C,CAAAA,EAASA,CAAAA,CAAM,YAAY6C,CAAAA,CAAU,CAAA,EAAA,EAAKA,CAAAA,CAAS,IAAI,CAAA,EAAA,CAAI,CAAA,CAC3D,MACd,CAAC,EACL,EAEMK,CAAAA,CAASf,CAAAA,EAA2B,CACtC,IAAMtI,CAAAA,CAAOwI,EAAgBF,CAAE,CAAA,CAC/B,GAAI,EAAAtI,CAAAA,GAAS,QAAa,CAAC4M,EAAAA,CAAW5M,CAAI,CAAA,CAAA,CAG1C,CAAA,GAAIsI,CAAAA,CAAG,IAAA,GAAS,yBAAA,EAA6BA,CAAAA,CAAG,KAAK,IAAA,GAAS,gBAAA,CAAkB,CACxEwF,CAAAA,CAAgBxF,CAAAA,CAAG,IAAI,CAAA,EAAG0F,CAAAA,CAAO1F,EAAG,IAAI,CAAA,CAC5C,MACJ,CAEAG,CAAAA,CAAWH,EAAG,IAAA,CAAMpI,CAAAA,CAAQ,WAAW,WAAA,CAAa8I,CAAAA,GAC5CA,IAAa,IAAA,EAAQ8E,CAAAA,CAAgB9E,CAAQ,CAAA,EAAGgF,CAAAA,CAAOhF,CAAQ,CAAA,CAC5D,KAAA,CACV,GACL,CAAA,CAEA,OAAO,CACH,mBAAA,CAAoBvI,CAAAA,CAAM,CACtB4I,CAAAA,CAAM5I,CAAI,EACd,CAAA,CACA,kBAAA,CAAmBA,EAAM,CACrB4I,CAAAA,CAAM5I,CAAI,EACd,CAAA,CACA,uBAAA,CAAwBA,EAAM,CAC1B4I,CAAAA,CAAM5I,CAAI,EACd,CACJ,CACJ,CACJ,CAAA,CAEOwN,GAAQ,IAAIJ,EAAAA,CC9DnB,IAAMK,EAAAA,CAAgB,CAClBxM,GACAwB,EAAAA,CACAE,EAAAA,CACAK,GACAmB,EAAAA,CACAwB,EAAAA,CACAa,GACAY,EAAAA,CACAG,EAAAA,CACAI,GACAqB,EAAAA,CACAkB,EAAAA,CACAO,GACAK,EAAAA,CACAE,EAAAA,CACAG,GACAI,EAAAA,CACAU,EAAAA,CACAU,GACAM,EAAAA,CACAE,EAAAA,CACAK,EACJ,CAAA,CAKaE,CAAAA,CAAQ,OAAO,WAAA,CAAYD,EAAAA,CAAc,IAAIE,CAAAA,EAAQ,CAACA,CAAAA,CAAK,IAAA,CAAMA,CAAAA,CAAK,YAAA,EAAc,CAAC,CAAC,EC9C5F,SAASC,CAAAA,CAAc7M,EAAmD,CAC7E,IAAMgL,EAAqC,EAAC,CAE5C,OAAW,CAACxM,CAAAA,CAAMoO,CAAI,CAAA,GAAK,MAAA,CAAO,QAAQD,CAAK,CAAA,CAAA,CACtCC,EAAK,IAAA,CAAK,IAAA,EAAM,UAAY,MAAA,IAAY5M,CAAAA,GACzCgL,EAAQ,CAAA,EAAG3M,CAAAA,CAAU,WAAW,CAAA,CAAA,EAAIG,CAAI,EAAE,CAAA,CAAI,MAAA,CAAA,CAItD,OAAOwM,CACX,CAMO,SAAS8B,EAAAA,EAAsC,CAClD,IAAM9B,CAAAA,CAAqC,EAAC,CAE5C,IAAA,IAAWxM,CAAAA,IAAQ,MAAA,CAAO,KAAKmO,CAAK,CAAA,CAChC3B,EAAQ,CAAA,EAAG3M,CAAAA,CAAU,WAAW,CAAA,CAAA,EAAIG,CAAI,EAAE,CAAA,CAAI,MAAA,CAGlD,OAAOwM,CACX,CCxBO,SAAS+B,EAAAA,CAAIC,CAAAA,CAAgE,CAChF,OAAO,CACH,KAAM,CAAA,EAAG3O,CAAAA,CAAU,WAAW,CAAA,IAAA,CAAA,CAC9B,OAAA,CAAS,CAAE,CAACA,CAAAA,CAAU,WAAW,EAAG2O,CAAO,EAC3C,QAAA,CAAU,CAAE,CAAC3O,CAAAA,CAAU,WAAW,EAAG,CAAE,QAAA,CAAU,KAAM,KAAA,CAAO,IAAK,CAAE,CAAA,CACrE,KAAA,CAAOyO,EAAAA,EACX,CACJ,CCRO,SAASvJ,CAAAA,CAAKyJ,CAAAA,CAAgE,CACjF,OAAO,CACH,KAAM,CAAA,EAAG3O,CAAAA,CAAU,WAAW,CAAA,KAAA,CAAA,CAC9B,OAAA,CAAS,CAAE,CAACA,CAAAA,CAAU,WAAW,EAAG2O,CAAO,EAC3C,KAAA,CAAOH,CAAAA,CAAc,MAAM,CAC/B,CACJ,CCNO,SAASI,EAAAA,CAAYD,EAAgE,CACxF,OAAO,CACH,GAAGzJ,CAAAA,CAAKyJ,CAAM,CAAA,CACd,IAAA,CAAM,GAAG3O,CAAAA,CAAU,WAAW,cAClC,CACJ,CCVA,IAAM6O,EAAAA,CAAmB,CAAC,oBAAA,CAAsB,yBAAyB,CAAA,CASlE,SAASC,GAASH,CAAAA,CAAgE,CACrF,OAAO,CACH,IAAA,CAAM,GAAG3O,CAAAA,CAAU,WAAW,YAC9B,OAAA,CAAS,CAAE,CAACA,CAAAA,CAAU,WAAW,EAAG2O,CAAO,CAAA,CAC3C,SAAU,CAAE,CAAC3O,EAAU,WAAW,EAAG,CAAE,QAAA,CAAU,IAAK,CAAE,CAAA,CACxD,KAAA,CAAO,CACH,GAAGwO,CAAAA,CAAc,UAAU,CAAA,CAC3B,CAAC,GAAGxO,CAAAA,CAAU,WAAW,mCAAmC,EAAG,CAAC,MAAA,CAAQ,CAAE,OAAA,CAAS6O,EAAiB,CAAC,CACzG,CACJ,CACJ,CCdO,SAASE,GAAMJ,CAAAA,CAAgE,CAClF,OAAO,CACH,IAAA,CAAM,GAAG3O,CAAAA,CAAU,WAAW,SAC9B,OAAA,CAAS,CAAE,CAACA,CAAAA,CAAU,WAAW,EAAG2O,CAAO,CAAA,CAC3C,SAAU,CAAE,CAAC3O,EAAU,WAAW,EAAG,CAAE,KAAA,CAAO,IAAK,CAAE,CAAA,CACrD,KAAA,CAAOwO,EAAc,OAAO,CAChC,CACJ,CCFO,SAASQ,GAAaL,CAAAA,CAAgF,CACzG,OAAO,CACH,IAAA,CAAMzJ,CAAAA,CAAKyJ,CAAM,CAAA,CACjB,WAAA,CAAaC,GAAYD,CAAM,CAAA,CAC/B,SAAUG,EAAAA,CAASH,CAAM,EACzB,KAAA,CAAOI,EAAAA,CAAMJ,CAAM,CAAA,CACnB,GAAA,CAAKD,GAAIC,CAAM,CACnB,CACJ,CCpBE,IAAAM,EAAAA,CAAW,OAAA,CCQb,IAAMN,EAAAA,CAAqC,CACvC,IAAA,CAAM,CACF,KAAM,CAAA,cAAA,EAAiB3O,CAAAA,CAAU,WAAW,CAAA,CAAA,CAC5C,OAAA,CAAAiP,EACJ,CAAA,CACA,KAAA,CAAAX,EACA,OAAA,CAAS,EACb,CAAA,CAGAK,EAAAA,CAAO,QAAUK,EAAAA,CAAaL,EAAM,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 * Matches a single emoji as one unit: flag pairs, skin-tone and\n * variation-selector modifiers, and ZWJ sequences. Text-default pictographs\n * like © match only when emoji-styled with a variation selector.\n */\n EMOJI: /\\p{Regional_Indicator}\\p{Regional_Indicator}|\\p{Emoji_Presentation}(?:\\uFE0F|\\p{Emoji_Modifier})?(?:\\u200D\\p{Emoji_Presentation}(?:\\uFE0F|\\p{Emoji_Modifier})?)*|\\p{Extended_Pictographic}\\uFE0F/gu,\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 * A tooling directive comment (eslint, ts-, biome-ignore, etc.) rather\n * than prose, matched against the comment text.\n */\n DIRECTIVE:\n /^\\s*(?:eslint\\b|eslint-|globals?\\b|exported\\b|jshint\\b|jslint\\b|istanbul\\b|[cv]8\\b|ts-|prettier-ignore|biome-ignore|webpack\\b|noinspection\\b|@)/,\n\n /**\n * Quote characters that fence a verbatim span inside a comment, whose\n * dots belong to the quoted text rather than the surrounding prose. The\n * apostrophe is absent, as it appears unpaired in words like \"don't\".\n */\n QUOTES: new Set(['\"', \"`\"]),\n\n /**\n * Abbreviations whose trailing dot is part of the word itself, so it must\n * survive even though it looks like the end of a sentence.\n */\n ABBREVIATIONS: [\"e.g.\", \"i.e.\", \"etc.\", \"vs.\", \"cf.\", \"al.\", \"approx.\", \"resp.\"],\n },\n\n /**\n * Constants for inspecting JSDoc structure.\n */\n JSDOC: {\n /**\n * Matches a JSDoc block-tag line, capturing the tag name so callers can\n * find any tag (`param`, `returns`, `throws`, etc.).\n */\n TAG: /^\\s*\\*?\\s*@(\\w+)/,\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 object literals.\n */\n OBJECTS: {\n /**\n * The default maximum number of properties an object literal may keep on\n * a single line before it must be broken across multiple lines.\n */\n MAX_INLINE_KEYS: 2,\n\n /**\n * The default number of spaces per indentation level used when expanding\n * an object literal across multiple lines.\n */\n INDENT_WIDTH: 4,\n },\n\n /**\n * Constants for inspecting functions.\n */\n FUNCTIONS: {\n /**\n * The AST node types that introduce a new function scope.\n */\n NODE_TYPES: new Set([\"FunctionDeclaration\", \"FunctionExpression\", \"ArrowFunctionExpression\"]),\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 React semantics.\n */\n REACT: {\n /**\n * A React hook name: `use` followed by a capitalized word, e.g.\n * `useState` or `useMenuActions`.\n */\n HOOK: /^use[A-Z]/,\n\n /**\n * A context-consumer hook name, i.e. a `use…Context` wrapper such as\n * `useTreeViewContext` (the bare `useContext` is excluded).\n */\n CONTEXT_HOOK: /^use[A-Z]\\w*Context$/,\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` when the statement is not ordered: either it\n * is not a builder call, or it is a domain timestamp such as `expires_at`, which\n * reads fine among the columns or beside the audit timestamps.\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\n if (CONSTANTS.MIGRATIONS.TIMESTAMP_METHODS.has(root.method)) {\n if (root.firstArgument !== undefined && CONSTANTS.MIGRATIONS.AUDIT_TIMESTAMPS.has(root.firstArgument)) {\n return \"timestamp\"\n }\n\n // A domain timestamp carries meaning of its own rather than tracking a\n // row's lifecycle, so it is not forced into either group\n return null\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({\n node: statement,\n messageId: \"outOfOrder\",\n data: { category },\n })\n }\n\n maxRank = Math.max(maxRank, rank)\n }\n },\n }\n }\n}\n\nexport default new MigrationTableOrder()\n","import type { TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Checks whether a class is an AdonisJS controller, i.e. a default-exported\n * class whose name ends with `Controller`.\n * @param node The class declaration to inspect.\n * @returns True if the class is a controller.\n */\nexport function isControllerClass(node: TSESTree.ClassDeclaration): boolean {\n return node.parent.type === \"ExportDefaultDeclaration\" && node.id?.name.endsWith(\"Controller\") === true\n}\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\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 * Resolves the node a JSDoc comment sits above, which for a decorated\n * declaration is its earliest decorator, since decorators are written between the\n * JSDoc and the declaration they belong to.\n * @param node The node to anchor the JSDoc lookup on.\n * @returns The node whose leading comments hold the JSDoc.\n */\nexport function jsDocAnchor(node: TSESTree.Node): TSESTree.Node {\n const declaration =\n (node.type === \"ExportDefaultDeclaration\" || node.type === \"ExportNamedDeclaration\") &&\n node.declaration !== null\n ? node.declaration\n : node\n\n const decorators = \"decorators\" in declaration ? declaration.decorators : undefined\n\n // Only a decorator written before the declaration shifts the anchor, the\n // \"export default @dec class\" form leaves the JSDoc above the export\n const earliest = decorators?.reduce<TSESTree.Decorator | undefined>(\n (found, decorator) => (found === undefined || decorator.range[0] < found.range[0] ? decorator : found),\n undefined,\n )\n\n return earliest !== undefined && earliest.range[0] < node.range[0] ? earliest : node\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(jsDocAnchor(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 * Resolves the block-tag name a JSDoc line starts with, e.g. `param` or\n * `returns`, or `null` if the line is not a tag line.\n * @param line The physical source line to inspect.\n * @returns The tag name without its `@`, or `null`.\n */\nexport function getJSDocLineTag(line: string): string | null {\n const match = line.match(CONSTANTS.JSDOC.TAG)\n return match?.[1] ?? null\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 getJSDocLineTag(line) !== null\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\n/**\n * Finds the source-line range of a JSDoc comment's `@returns` (or `@return`)\n * block, spanning the tag line down to the line before the next tag or the\n * closing `*/`.\n * @param sourceCode The source code of the linted file.\n * @param comment The JSDoc comment to inspect.\n * @returns The inclusive `from`/`to` source lines, or `null` if there is none.\n */\nexport function findJSDocReturnsRange(\n sourceCode: Readonly<TSESLint.SourceCode>,\n comment: TSESTree.Comment,\n): { from: number; to: number } | null {\n let tagLine = -1\n for (let line = comment.loc.start.line + 1; line < comment.loc.end.line; line++) {\n const tag = getJSDocLineTag(sourceCode.lines[line - 1] ?? \"\")\n if (tag === \"returns\" || tag === \"return\") {\n tagLine = line\n break\n }\n }\n\n if (tagLine === -1) return null\n\n let to = comment.loc.end.line - 1\n for (let line = tagLine + 1; line < comment.loc.end.line; line++) {\n if (isJSDocTagLine(sourceCode.lines[line - 1] ?? \"\")) {\n to = line - 1\n break\n }\n }\n\n return {\n from: tagLine,\n to,\n }\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isControllerClass } from \"@/lib/utils/controllers\"\nimport { hasLeadingJSDoc } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"missingJSDoc\"\n\n/**\n * Requires a JSDoc comment above an AdonisJS controller (a default-exported\n * class whose name ends with `Controller`) so the responsibility it serves is\n * documented at a glance, before diving into its handler methods.\n */\nclass RequireControllerJSDoc extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-controller-jsdoc\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Require a JSDoc comment describing an AdonisJS controller.\",\n recommended: true,\n category: \"adonisjs\",\n },\n schema: [],\n messages: {\n missingJSDoc: nitpick({\n problem: \"This controller has no JSDoc describing what it does.\",\n why: \"A controller's responsibility should be readable at a glance, before diving into its handler methods\",\n fix: \"Add a `/** ... */` JSDoc above the controller class summarizing what it handles\",\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 (!isControllerClass(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 RequireControllerJSDoc()\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 { ASTUtils, type TSESLint, type TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Builds the dotted path of a pure property access chain, i.e. one made only of\n * non-computed member accesses (with any `?.` or `!`) bottoming out at an\n * identifier or `this`, such as `auth.user!` or `menu.node.path`.\n * @param node The expression to inspect.\n * @returns The dotted path, e.g. `auth.user`, or `null` if the expression is not\n * a plain property access.\n */\nexport function propertyAccessPath(node: TSESTree.Expression): string | null {\n const properties: string[] = []\n let expression: TSESTree.Node = node\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 null\n if (expression.property.type !== \"Identifier\") return null\n\n properties.unshift(expression.property.name)\n expression = expression.object\n continue\n }\n\n break\n }\n\n if (properties.length === 0) return null\n if (expression.type === \"ThisExpression\") return [\"this\", ...properties].join(\".\")\n if (expression.type === \"Identifier\") return [expression.name, ...properties].join(\".\")\n\n return null\n}\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 return propertyAccessPath(node) !== null\n}\n\n/**\n * Checks whether a binding is written to after its declaration, which makes an\n * alias of it a snapshot of the value at that point rather than a rename.\n * @param scope The scope the alias is declared in.\n * @param name The name of the source binding.\n * @returns True if the binding is reassigned somewhere.\n */\nexport function isReassigned(scope: TSESLint.Scope.Scope, name: string): boolean {\n const variable = ASTUtils.findVariable(scope, name)\n\n // An unresolved name is a global or an ambient declaration, so it is stable\n if (variable === null) return false\n\n const declarations = new Set<TSESTree.Node>(variable.defs.map(definition => definition.name))\n\n return variable.references.some(reference => reference.isWrite() && !declarations.has(reference.identifier))\n}\n\n/**\n * Checks whether a property path, or a prefix of it, is written to, which makes\n * an alias of that path a snapshot rather than a rename.\n * @param written The property paths written to in the file.\n * @param path The property path the alias reads.\n * @returns True if the path or one of its prefixes is written to.\n */\nexport function isPathWritten(written: ReadonlySet<string>, path: string): boolean {\n for (const target of written) {\n if (path === target || path.startsWith(`${target}.`)) return true\n }\n\n return false\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, which\n * makes it a pure alias of the object it destructures.\n * @param pattern The object pattern to inspect.\n * @returns True if every property is a pure shorthand grab.\n */\nexport function 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","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isReassigned } from \"@/lib/utils/aliases\"\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. `let`,\n * exported bindings, annotated declarations, and snapshots of a reassigned source\n * 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 // A type annotation is a reason of its own to keep the binding, as\n // inlining it would drop the narrowing it applies\n if (node.id.typeAnnotation !== undefined) return\n\n // A reassigned source makes this a snapshot of its value here, not\n // a rename, so inlining it would change what the code does\n if (isReassigned(context.sourceCode.getScope(node), node.init.name)) 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 initialises: \"initializes\",\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 /**\n * A null-prototype object so lookups like `dictionary[\"constructor\"]` return\n * undefined instead of Object.prototype.constructor, which would otherwise\n * treat identifiers such as `BrowserWindowConstructorOptions` as matches.\n */\n const dictionary: Record<string, string> = Object.create(null)\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\n/**\n * A place an em dash may be tolerated, so user-facing copy, prompt text, and\n * glyphs can keep it while code and comments stay clean.\n */\ntype EmDashLocation = \"strings\" | \"templates\" | \"jsx\" | \"comments\"\n\ntype Options = [{ allow?: EmDashLocation[] }]\ntype MessageIds = \"emDash\"\n\n/**\n * The token type each allowed location maps to, `comments` aside, as comments are\n * not tokens.\n */\nconst TOKEN_TYPES: Partial<Record<EmDashLocation, string>> = {\n strings: \"String\",\n templates: \"Template\",\n jsx: \"JSXText\",\n}\n\n/**\n * Flags every em dash (—) character found anywhere in the source, except in the\n * locations the `allow` option exempts.\n */\nclass NoEmDash extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-em-dash\"\n\n readonly defaultOptions: Options = [{ allow: [] }]\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 {\n type: \"object\",\n properties: {\n allow: {\n type: \"array\",\n items: {\n type: \"string\",\n enum: [\"strings\", \"templates\", \"jsx\", \"comments\"],\n },\n },\n },\n additionalProperties: false,\n },\n ],\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, or allow it here with the rule's `allow` option if it is deliberate user-facing copy.\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const allow = new Set(options[0]?.allow ?? [])\n\n // The source spans an em dash may sit in without being reported, left empty\n // when nothing is allowed so the default scan stays exhaustive\n const exempt = (): [number, number][] => {\n const ranges: [number, number][] = []\n if (allow.size === 0) return ranges\n\n const tokenTypes = new Set(\n [...allow].map(location => TOKEN_TYPES[location]).filter(type => type !== undefined),\n )\n\n for (const token of context.sourceCode.ast.tokens ?? []) {\n if (tokenTypes.has(token.type)) ranges.push(token.range)\n }\n\n if (allow.has(\"comments\")) {\n for (const comment of context.sourceCode.getAllComments()) {\n ranges.push(comment.range)\n }\n }\n\n return ranges\n }\n\n return {\n Program() {\n const text = context.sourceCode.getText()\n const ranges = exempt()\n\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 if (ranges.some(([start, end]) => index >= start && index < end)) 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 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 = \"emoji\"\n\n/**\n * Flags every emoji found anywhere in the source and removes it, since emojis\n * are noise in code, comments, and identifiers.\n */\nclass NoEmojis extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-emojis\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"code\",\n docs: {\n description: \"Disallow emoji characters anywhere in the source.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n emoji: nitpick({\n problem: \"Found an emoji ({{emoji}}).\",\n why: \"Emojis are usually introduced by AI-generated text and add noise to code, comments, and identifiers\",\n fix: \"Discard the emoji\",\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 emoji is caught, whether it\n // appears in code, strings, or comments\n for (const match of text.matchAll(CONSTANTS.EMOJI)) {\n const emoji = match[0]\n const end = match.index + emoji.length\n\n context.report({\n loc: {\n start: context.sourceCode.getLocFromIndex(match.index),\n end: context.sourceCode.getLocFromIndex(end),\n },\n messageId: \"emoji\",\n data: { emoji },\n fix: fixer => fixer.removeRange([match.index, end]),\n })\n }\n },\n }\n }\n}\n\nexport default new NoEmojis()\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 { TSESTree } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\n\n/**\n * Any node that introduces a callable function.\n */\nexport type FunctionNode = TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression\n\n/**\n * A lookup of AST node type to the property keys that hold its child nodes.\n */\nexport type VisitorKeys = Record<string, readonly string[] | undefined>\n\n/**\n * Predicate applied to a `return` statement's argument (which is `null` for a\n * bare `return`).\n */\ntype ReturnPredicate = (argument: TSESTree.Expression | null) => boolean\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\n/**\n * Checks whether any `return` in a subtree satisfies a predicate, without\n * crossing into nested functions (whose returns belong to them, not us).\n * @param node The AST node to search from.\n * @param visitorKeys The AST visitor keys, used to walk the subtree.\n * @param predicate The test applied to each `return` argument.\n * @returns True if a matching `return` is found.\n */\nexport function someReturn(node: TSESTree.Node, visitorKeys: VisitorKeys, predicate: ReturnPredicate): boolean {\n if (node.type === \"ReturnStatement\") {\n return predicate(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 if (CONSTANTS.FUNCTIONS.NODE_TYPES.has(childNode.type)) continue\n if (someReturn(childNode, visitorKeys, predicate)) return true\n }\n }\n\n return false\n}\n\n/**\n * Checks whether a function returns a value, i.e. an arrow with an expression\n * body or a body with a non-empty `return`.\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 a value.\n */\nexport function functionReturnsValue(fn: FunctionNode, visitorKeys: VisitorKeys): boolean {\n if (fn.type === \"ArrowFunctionExpression\" && fn.body.type !== \"BlockStatement\") {\n return true\n }\n\n return someReturn(fn.body, visitorKeys, argument => argument !== null)\n}\n\n/**\n * Checks whether a return-type annotation is `void` or `Promise<void>`.\n * @param annotation The return-type annotation to inspect.\n * @returns True if the annotation is a void type.\n */\nexport function isVoidReturnType(annotation: TSESTree.TSTypeAnnotation): boolean {\n if (annotation.typeAnnotation.type === \"TSVoidKeyword\") return true\n\n if (\n annotation.typeAnnotation.type === \"TSTypeReference\" &&\n annotation.typeAnnotation.typeName.type === \"Identifier\" &&\n annotation.typeAnnotation.typeName.name === \"Promise\"\n ) {\n return (\n annotation.typeAnnotation.typeArguments?.params.length === 1 &&\n annotation.typeAnnotation.typeArguments?.params[0]?.type === \"TSVoidKeyword\"\n )\n }\n\n return false\n}\n\n/**\n * Checks whether a function returns nothing, judged by its return-type\n * annotation when present, otherwise by its body.\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 is void.\n */\nexport function isVoidFunction(fn: FunctionNode, visitorKeys: VisitorKeys): boolean {\n if (fn.returnType) {\n return isVoidReturnType(fn.returnType)\n }\n\n return !functionReturnsValue(fn, visitorKeys)\n}\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { type FunctionNode, getDocumentableNode, isVoidFunction } from \"@/lib/utils/functions\"\nimport { findJSDocReturnsRange, isJSDocComment } from \"@/lib/utils/jsdocs\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"voidReturns\"\n\n/**\n * Flags a `@returns` tag on a function that returns nothing (a void return type,\n * or a body with no `return` or only a bare `return`), and removes it, since it\n * documents a value that never exists.\n */\nclass NoJSDocReturnsOnVoid extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-jsdoc-returns-on-void\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"code\",\n docs: {\n description: \"Disallow a JSDoc `@returns` tag on a function that returns nothing.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n voidReturns: nitpick({\n problem: \"This function returns nothing, but its JSDoc has a `@returns` tag.\",\n why: \"A `@returns` on a void function documents a value that never exists and drifts from the code\",\n fix: \"Remove the `@returns` tag\",\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, anchor: TSESTree.Node): void => {\n const jsdoc = context.sourceCode.getCommentsBefore(anchor).at(-1)\n if (jsdoc === undefined || !isJSDocComment(jsdoc)) return\n\n const range = findJSDocReturnsRange(context.sourceCode, jsdoc)\n if (range === null) return\n if (!isVoidFunction(fn, context.sourceCode.visitorKeys)) return\n\n const from = context.sourceCode.getIndexFromLoc({ line: range.from, column: 0 })\n const to = context.sourceCode.getIndexFromLoc({ line: range.to + 1, column: 0 })\n\n context.report({\n loc: {\n start: { line: range.from, column: 0 },\n end: { line: range.to, column: (context.sourceCode.lines[range.to - 1] ?? \"\").length },\n },\n messageId: \"voidReturns\",\n fix: fixer => fixer.removeRange([from, to]),\n })\n }\n\n return {\n FunctionDeclaration(node) {\n check(node, getDocumentableNode(node))\n },\n VariableDeclarator(node) {\n if (node.init?.type === \"ArrowFunctionExpression\" || node.init?.type === \"FunctionExpression\") {\n check(node.init, getDocumentableNode(node.init))\n }\n },\n MethodDefinition(node) {\n if (node.value.type === \"FunctionExpression\") {\n check(node.value, node)\n }\n },\n }\n }\n}\n\nexport default new NoJSDocReturnsOnVoid()\n","import type { TSESTree } from \"@typescript-eslint/utils\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { isWordChar } from \"@/lib/utils/words\"\n\n/**\n * The first prose character of a comment, with its absolute source index.\n */\ntype CommentContent = { index: number; char: string }\n\n/**\n * A period inside a comment that punctuates prose rather than belonging to a\n * code token, with its absolute source index.\n */\nexport type ProsePeriod = {\n /**\n * The absolute source index of the period character.\n */\n index: number\n\n /**\n * Whether the period closes the comment, i.e. only whitespace follows it, so\n * removing it cannot run two sentences together.\n */\n terminal: boolean\n}\n\n/**\n * A backtick-fenced span inside a comment, with the absolute source indices of\n * its two backticks and the text they wrap.\n */\nexport type BacktickSpan = {\n /**\n * The absolute source index of the opening backtick.\n */\n start: number\n\n /**\n * The absolute source index of the closing backtick.\n */\n end: number\n\n /**\n * The text between the two backticks.\n */\n text: string\n}\n\n/**\n * Checks whether a comment is a tooling directive (eslint, `ts-`, biome-ignore,\n * etc.) rather than prose, which should not be treated as an English sentence.\n * @param comment The comment to test.\n * @returns True if the comment is a directive.\n */\nexport function isDirectiveComment(comment: TSESTree.Comment): boolean {\n return CONSTANTS.COMMENTS.DIRECTIVE.test(comment.value)\n}\n\n/**\n * Finds the first prose character of a comment, skipping the `//` or `/*`\n * delimiters and, for a block comment, the per-line ` * ` markers, so callers\n * can inspect where the comment's text actually begins.\n * @param comment The comment to inspect.\n * @returns The first content character and its source index, or `null` if the\n * comment has no textual content.\n */\nexport function firstCommentContentChar(comment: TSESTree.Comment): CommentContent | null {\n // Skip past the opening \"//\" or \"/*\" delimiter\n const base = comment.range[0] + 2\n\n if (comment.type === \"Line\") {\n const match = comment.value.match(/\\S/u)\n if (match?.index === undefined) return null\n\n return {\n index: base + match.index,\n char: match[0],\n }\n }\n\n let offset = 0\n for (const line of comment.value.split(\"\\n\")) {\n // Strip leading whitespace and a single \" * \" marker; whatever remains is\n // the line's content, so a marker-only line is skipped\n const markerLength = (line.match(/^\\s*\\*?\\s*/u)?.[0] ?? \"\").length\n const char = line.slice(markerLength).charAt(0)\n\n if (char !== \"\") {\n return {\n index: base + offset + markerLength,\n char,\n }\n }\n\n offset += line.length + 1\n }\n\n return null\n}\n\n/**\n * Finds the periods inside a `//` comment that punctuate prose, skipping the ones\n * that belong to a code token (`foo.bar`, `subagent.*`), sit inside a quoted\n * span, form an ellipsis, or close an abbreviation such as `e.g.`.\n * @param comment The line comment to scan.\n * @returns The prose periods found, in source order.\n */\nexport function findProsePeriods(comment: TSESTree.Comment): ProsePeriod[] {\n const periods: ProsePeriod[] = []\n\n // The comment value starts right after the leading \"//\"\n const base = comment.range[0] + 2\n let quote: string | null = null\n\n for (let index = 0; index < comment.value.length; index++) {\n const char = comment.value.charAt(index)\n\n // Inside a quoted span everything is verbatim until it closes\n if (quote !== null) {\n if (char === quote) quote = null\n continue\n }\n\n // Only open a span when it actually closes, so an unpaired quote does not\n // swallow the rest of the comment\n if (CONSTANTS.COMMENTS.QUOTES.has(char) && comment.value.includes(char, index + 1)) {\n quote = char\n continue\n }\n\n if (char !== \".\") continue\n\n // A run of consecutive dots is an ellipsis, leave it alone\n if (comment.value.charAt(index + 1) === \".\") {\n while (comment.value.charAt(index + 1) === \".\") index++\n continue\n }\n\n const rest = comment.value.slice(index + 1)\n\n // A dot is prose punctuation only when whitespace or the end of the\n // comment follows it, anything else makes it part of a token\n if (rest !== \"\" && !/^\\s/u.test(rest)) continue\n\n if (endsWithAbbreviation(comment.value.slice(0, index + 1))) continue\n\n periods.push({\n index: base + index,\n terminal: rest.trim() === \"\",\n })\n }\n\n return periods\n}\n\n/**\n * Finds the backtick-fenced spans inside a comment, skipping runs of backticks\n * (a code fence), an unpaired backtick, and any span already holding a double\n * quote, none of which survive being rewritten as a quoted span.\n * @param comment The comment to scan.\n * @returns The spans found, in source order.\n */\nexport function findBacktickSpans(comment: TSESTree.Comment): BacktickSpan[] {\n const spans: BacktickSpan[] = []\n\n // The comment value starts right after the leading \"//\"\n const base = comment.range[0] + 2\n\n for (let index = 0; index < comment.value.length; index++) {\n if (comment.value.charAt(index) !== \"`\") continue\n\n // A run of backticks fences a code block, which quotes cannot stand in for\n if (comment.value.charAt(index + 1) === \"`\") {\n while (comment.value.charAt(index + 1) === \"`\") index++\n continue\n }\n\n const closing = comment.value.indexOf(\"`\", index + 1)\n if (closing === -1) break\n\n const text = comment.value.slice(index + 1, closing)\n\n // Rewriting a span that already holds a double quote would nest quotes\n if (!text.includes('\"')) {\n spans.push({\n start: base + index,\n end: base + closing,\n text,\n })\n }\n\n index = closing\n }\n\n return spans\n}\n\n/**\n * Checks whether a piece of comment text ends with an abbreviation whose\n * trailing dot is part of the word, e.g. `e.g.` or `etc.`.\n * @param text The comment text up to and including the dot.\n * @returns True if the dot closes an abbreviation.\n */\nfunction endsWithAbbreviation(text: string): boolean {\n const lowercase = text.toLowerCase()\n\n return CONSTANTS.COMMENTS.ABBREVIATIONS.some(abbreviation => {\n if (!lowercase.endsWith(abbreviation)) return false\n\n // Require a boundary before the abbreviation so \"foo.al\" is not one\n const before = lowercase.charAt(lowercase.length - abbreviation.length - 1)\n return before === \"\" || !isWordChar(before)\n })\n}\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { findBacktickSpans, isDirectiveComment } from \"@/lib/utils/comments\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"backticks\"\n\n/**\n * Flags a backtick-fenced code reference inside a `//` line comment and rewrites\n * it with double quotes, since backticks only render as code in a JSDoc block.\n * Code fences, unpaired backticks, and directives are left alone.\n */\nclass NoLineCommentBackticks extends NitpickerRule<MessageIds, Options> {\n readonly name = \"no-line-comment-backticks\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"code\",\n docs: {\n description: \"Disallow backticks in `//` line comments, use double quotes for code references.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n backticks: nitpick({\n problem: \"This line comment wraps `{{text}}` in backticks.\",\n why: \"Backticks only render as code inside a JSDoc block, in a `//` comment they stay literal characters, so double quotes read better\",\n fix: 'Wrap it in double quotes instead: \"{{text}}\"',\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 // A JSDoc block is where backticks do render, so only \"//\"\n // comments are rewritten, and never a tooling directive\n if (comment.type !== \"Line\" || isDirectiveComment(comment)) continue\n\n for (const span of findBacktickSpans(comment)) {\n context.report({\n loc: {\n start: context.sourceCode.getLocFromIndex(span.start),\n end: context.sourceCode.getLocFromIndex(span.end + 1),\n },\n messageId: \"backticks\",\n data: { text: span.text },\n fix: fixer => [\n fixer.replaceTextRange([span.start, span.start + 1], '\"'),\n fixer.replaceTextRange([span.end, span.end + 1], '\"'),\n ],\n })\n }\n }\n },\n }\n }\n}\n\nexport default new NoLineCommentBackticks()\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { findProsePeriods } from \"@/lib/utils/comments\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"period\" | \"sentence\"\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`, `subagent.*`), dots inside a\n * quoted span, ellipses, and abbreviations like `e.g.` 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 ends with a period.\",\n why: \"Line comments should be short, clear fragments, not full sentences, so a closing period is just noise, dots inside code references like `foo.bar` are allowed.\",\n fix: \"Remove the period and keep the comment terse.\",\n }),\n sentence: nitpick({\n problem: \"This line comment runs two sentences together with a period.\",\n why: \"Line comments should be short, clear fragments, dropping the period on its own would leave a run-on, so the sentences belong on separate lines\",\n fix: \"Split it into one `//` line per fragment, or reword it as a single fragment\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n // The indentation of a comment that sits alone on its line, or \"null\" when\n // code precedes it, as splitting a trailing comment would break that line\n const ownLineIndent = (comment: TSESTree.Comment): string | null => {\n const before = (context.sourceCode.lines[comment.loc.start.line - 1] ?? \"\").slice(\n 0,\n comment.loc.start.column,\n )\n\n return before.trim() === \"\" ? before : null\n }\n\n return {\n Program() {\n for (const comment of context.sourceCode.getAllComments()) {\n if (comment.type !== \"Line\") continue\n\n const indent = ownLineIndent(comment)\n\n for (const period of findProsePeriods(comment)) {\n const loc = {\n start: context.sourceCode.getLocFromIndex(period.index),\n end: context.sourceCode.getLocFromIndex(period.index + 1),\n }\n\n // A period that closes the comment can simply go, nothing\n // follows it to run together\n if (period.terminal) {\n context.report({\n loc,\n messageId: \"period\",\n fix: fixer => fixer.removeRange([period.index, period.index + 1]),\n })\n\n continue\n }\n\n // Mid-comment, the period separates two fragments, so the\n // fix moves the second one onto its own comment line,\n // swallowing the spacing that followed the period\n const offset = period.index - comment.range[0] - 2\n const spacing = comment.value.slice(offset + 1).match(/^\\s*/u)?.[0] ?? \"\"\n const end = period.index + 1 + spacing.length\n\n context.report({\n loc,\n messageId: \"sentence\",\n fix:\n indent === null\n ? null\n : fixer => fixer.replaceTextRange([period.index, end], `\\n${indent}// `),\n })\n }\n }\n },\n }\n }\n}\n\nexport default new NoLineCommentPeriod()\n","import type { TSESLint, TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { isPathWritten, isReassigned, propertyAccessPath } 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 * A `const` that reads like a property alias, held back until the whole file has\n * been walked so writes to the same property can exempt it.\n */\ntype Candidate = {\n /**\n * The declarator to report.\n */\n node: TSESTree.VariableDeclarator\n\n /**\n * The name the property is aliased under.\n */\n name: string\n\n /**\n * The dotted path the alias reads, e.g. `auth.user`.\n */\n path: string\n\n /**\n * The source text of the aliased expression.\n */\n expression: string\n}\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. `let`, exported\n * bindings, annotated declarations, and snapshots of a value written to later are\n * exempt.\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 candidates: Candidate[] = []\n const written = new Set<string>()\n\n // Track the properties the file writes to, so an alias taken before one of\n // those writes is understood as a snapshot\n const recordWrite = (target: TSESTree.Node): void => {\n if (target.type !== \"MemberExpression\") return\n\n const path = propertyAccessPath(target)\n if (path !== null) written.add(path)\n }\n\n return {\n AssignmentExpression(node) {\n recordWrite(node.left)\n },\n\n UpdateExpression(node) {\n recordWrite(node.argument)\n },\n\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\n // A type annotation is a reason of its own to keep the binding, as\n // inlining it would drop the narrowing it applies\n if (node.id.typeAnnotation !== undefined) return\n\n const path = propertyAccessPath(node.init)\n if (path === null) return\n\n // A reassigned root object makes this a snapshot of what it held\n // here, so inlining it would change what the code does\n const root = path.slice(0, path.indexOf(\".\"))\n if (root !== \"this\" && isReassigned(context.sourceCode.getScope(node), root)) return\n\n candidates.push({\n node,\n name: node.id.name,\n path,\n expression: context.sourceCode.getText(node.init),\n })\n },\n\n \"Program:exit\"() {\n for (const candidate of candidates) {\n if (isPathWritten(written, candidate.path)) continue\n\n context.report({\n node: candidate.node,\n messageId: \"propertyAccessAlias\",\n data: {\n name: candidate.name,\n expression: candidate.expression,\n },\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 { isAllShorthand, 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\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, TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { firstCommentContentChar, isDirectiveComment } from \"@/lib/utils/comments\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"capitalize\"\n\n/**\n * Flags a comment whose first prose letter is lowercase and capitalizes it, so\n * comments read as sentences. Continuation lines of a wrapped `//` comment,\n * tooling directives, and comments that open with code, a symbol, or a URL are\n * left alone.\n */\nclass RequireCapitalizedComments extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-capitalized-comments\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"code\",\n docs: {\n description: \"Require a comment to start with an uppercase letter.\",\n recommended: true,\n category: \"base\",\n },\n schema: [],\n messages: {\n capitalize: nitpick({\n problem: \"This comment starts with a lowercase letter.\",\n why: \"A comment reads as a sentence, and a sentence starts with a capital letter\",\n fix: \"Capitalize the first letter of the comment\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n // Whether a \"//\" comment continues a wrapped one, i.e the previous\n // physical line is itself a line comment\n const isContinuation = (comment: TSESTree.Comment): boolean => {\n if (comment.type !== \"Line\") return false\n\n const previous = context.sourceCode.lines[comment.loc.start.line - 2]\n return previous !== undefined && /^\\s*\\/\\//.test(previous)\n }\n\n return {\n Program() {\n for (const comment of context.sourceCode.getAllComments()) {\n if (isDirectiveComment(comment) || isContinuation(comment)) continue\n\n const content = firstCommentContentChar(comment)\n if (content === null || !/\\p{Ll}/u.test(content.char)) continue\n\n // Leave a comment that opens with a URL alone, capitalizing it\n // would break the link\n if (/^(?:https?:\\/\\/|www\\.)/u.test(context.sourceCode.getText().slice(content.index))) continue\n\n context.report({\n loc: {\n start: context.sourceCode.getLocFromIndex(content.index),\n end: context.sourceCode.getLocFromIndex(content.index + content.char.length),\n },\n messageId: \"capitalize\",\n fix: fixer =>\n fixer.replaceTextRange(\n [content.index, content.index + content.char.length],\n content.char.toUpperCase(),\n ),\n })\n }\n },\n }\n }\n}\n\nexport default new RequireCapitalizedComments()\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\"\nimport CONSTANTS from \"@/lib/constants\"\nimport { type FunctionNode, someReturn, type VisitorKeys } from \"@/lib/utils/functions\"\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 a name is a React hook, i.e. `use` followed by a capitalized\n * word such as `useState` or `useMenuActions`.\n * @param name The function name to test.\n * @returns True if the name is a hook name.\n */\nexport function isHookName(name: string): boolean {\n return CONSTANTS.REACT.HOOK.test(name)\n}\n\n/**\n * Checks whether a name is a context-consumer hook, i.e. a `use…Context` wrapper\n * such as `useTreeViewContext` (the bare `useContext` is excluded).\n * @param name The function name to test.\n * @returns True if the name is a context-hook name.\n */\nexport function isContextHookName(name: string): boolean {\n return CONSTANTS.REACT.CONTEXT_HOOK.test(name)\n}\n\n/**\n * Checks whether an expression is, on its face, a function value: a function or\n * arrow expression, or a `useCallback` call (which always yields a function).\n * @param node The expression to inspect, if any.\n * @returns True if the expression evaluates to a function.\n */\nexport function isFunctionValue(node: TSESTree.Expression | null | undefined): boolean {\n if (!node) return false\n if (node.type === \"ArrowFunctionExpression\" || node.type === \"FunctionExpression\") return true\n\n return node.type === \"CallExpression\" && node.callee.type === \"Identifier\" && node.callee.name === \"useCallback\"\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 * 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(fn: FunctionNode, visitorKeys: VisitorKeys): 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 someReturn(fn.body, visitorKeys, isJsxExpression)\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, TSESTree } from \"@typescript-eslint/utils\"\n\n/**\n * Rebuilds an object literal across multiple lines, indenting each property one\n * level past the line the object opens on and closing the brace back at that\n * level, so the result matches the surrounding indentation.\n * @param sourceCode The source code of the linted file.\n * @param node The object expression to expand.\n * @param indent The number of spaces in one indentation level.\n * @returns The multiline object literal source text.\n */\nexport function expandObjectLiteral(\n sourceCode: Readonly<TSESLint.SourceCode>,\n node: TSESTree.ObjectExpression,\n indent: number,\n): string {\n const openingLine = sourceCode.lines[node.loc.start.line - 1] ?? \"\"\n const baseIndent = openingLine.match(/^\\s*/)?.[0] ?? \"\"\n const propertyIndent = baseIndent + \" \".repeat(indent)\n\n const body = node.properties.map(property => `${propertyIndent}${sourceCode.getText(property)}`).join(\",\\n\")\n\n return `{\\n${body},\\n${baseIndent}}`\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 { expandObjectLiteral } from \"@/lib/utils/objects\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = [{ maxKeys: number; indent: number }]\ntype MessageIds = \"shouldWrap\"\n\n/**\n * Flags an object literal that packs more than `maxKeys` properties onto a\n * single line, and expands it to one property per line, since a wide inline\n * object is harder to scan, diff, and edit than a stacked one.\n */\nclass RequireMultilineObject extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-multiline-object\"\n readonly defaultOptions: Options = [\n {\n maxKeys: CONSTANTS.OBJECTS.MAX_INLINE_KEYS,\n indent: CONSTANTS.OBJECTS.INDENT_WIDTH,\n },\n ]\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"whitespace\",\n docs: {\n description: \"Require an object literal with more than a few properties to span multiple lines.\",\n recommended: true,\n category: \"base\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxKeys: { type: \"integer\", minimum: 1 },\n indent: { type: \"integer\", minimum: 1 },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n shouldWrap: nitpick({\n problem: \"This object literal has {{count}} properties packed onto a single line.\",\n why: \"An object with more than {{max}} properties is easier to scan, diff, and edit when each property sits on its own line\",\n fix: \"Break it across multiple lines, one property per line with a trailing comma\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>, options: Options): TSESLint.RuleListener {\n const maxKeys = options[0]?.maxKeys ?? CONSTANTS.OBJECTS.MAX_INLINE_KEYS\n const indent = options[0]?.indent ?? CONSTANTS.OBJECTS.INDENT_WIDTH\n\n return {\n ObjectExpression(node) {\n if (node.properties.length <= maxKeys) return\n if (node.loc.start.line !== node.loc.end.line) return\n\n context.report({\n node,\n messageId: \"shouldWrap\",\n data: { count: node.properties.length, max: maxKeys },\n fix: fixer => fixer.replaceText(node, expandObjectLiteral(context.sourceCode, node, indent)),\n })\n },\n }\n }\n}\n\nexport default new RequireMultilineObject()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport { isContextHookName } from \"@/lib/utils/react\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"destructure\"\n\n/**\n * Flags a context-consumer hook (`use…Context`) whose result is bound whole to a\n * variable instead of being destructured, since destructuring names exactly what\n * the caller uses and reads better than repeated `context.member` access.\n */\nclass RequireContextHookDestructure extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-context-hook-destructure\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n docs: {\n description: \"Require the result of a context-consumer hook to be destructured.\",\n recommended: true,\n category: \"react\",\n },\n schema: [],\n messages: {\n destructure: nitpick({\n problem: \"`{{hook}}` is bound whole instead of destructured.\",\n why: \"Destructuring at the call site names exactly what the caller uses and reads better than repeated `{{name}}.member` access\",\n fix: \"Destructure the members in use, e.g. `const { a, b } = {{hook}}()`\",\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.id.type !== \"Identifier\" || node.init?.type !== \"CallExpression\") return\n if (node.init.callee.type !== \"Identifier\" || !isContextHookName(node.init.callee.name)) return\n\n context.report({\n node,\n messageId: \"destructure\",\n data: { hook: node.init.callee.name, name: node.id.name },\n })\n },\n }\n }\n}\n\nexport default new RequireContextHookDestructure()\n","import { ASTUtils, type TSESLint, type TSESTree } from \"@typescript-eslint/utils\"\nimport { NitpickerRule } from \"@/lib/rule\"\nimport { type FunctionNode, getFunctionName, someReturn } from \"@/lib/utils/functions\"\nimport { nitpick } from \"@/lib/utils/messages\"\nimport { isFunctionValue, isHookName } from \"@/lib/utils/react\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\ntype Options = []\ntype MessageIds = \"wrapInObject\"\n\n/**\n * Flags a custom hook that returns a bare function (directly or through a local\n * `useCallback`), and wraps it in an object, so the hook can grow new members\n * later without breaking every call site.\n */\nclass RequireHookObjectReturn extends NitpickerRule<MessageIds, Options> {\n readonly name = \"require-hook-object-return\"\n\n readonly defaultOptions: Options = []\n\n readonly meta = {\n type: \"suggestion\",\n fixable: \"code\",\n docs: {\n description: \"Require a custom hook to return an object rather than a bare function.\",\n recommended: true,\n category: \"react\",\n },\n schema: [],\n messages: {\n wrapInObject: nitpick({\n problem: \"This hook returns a bare function instead of an object.\",\n why: \"Returning an object lets the hook expose new members later without changing every call site, a bare function locks its shape\",\n fix: \"Return the function inside an object, e.g. `return { handleThing }`\",\n }),\n },\n } satisfies TSESLint.RuleMetaData<MessageIds, NitpickerRuleDocs, Options>\n\n create(context: Readonly<TSESLint.RuleContext<MessageIds, Options>>): TSESLint.RuleListener {\n // Whether a returned expression is a function, resolving a returned\n // identifier through its local declaration such as a \"useCallback\" const\n const returnsFunction = (argument: TSESTree.Expression): boolean => {\n if (isFunctionValue(argument)) return true\n if (argument.type !== \"Identifier\") return false\n\n const variable = ASTUtils.findVariable(context.sourceCode.getScope(argument), argument.name)\n const declarator = variable?.defs.at(-1)?.node\n return declarator?.type === \"VariableDeclarator\" && isFunctionValue(declarator.init)\n }\n\n const report = (argument: TSESTree.Expression): void => {\n context.report({\n node: argument,\n messageId: \"wrapInObject\",\n fix:\n argument.type === \"Identifier\"\n ? fixer => fixer.replaceText(argument, `{ ${argument.name} }`)\n : undefined,\n })\n }\n\n const check = (fn: FunctionNode): void => {\n const name = getFunctionName(fn)\n if (name === undefined || !isHookName(name)) return\n\n // An arrow with an expression body returns that expression directly\n if (fn.type === \"ArrowFunctionExpression\" && fn.body.type !== \"BlockStatement\") {\n if (returnsFunction(fn.body)) report(fn.body)\n return\n }\n\n someReturn(fn.body, context.sourceCode.visitorKeys, argument => {\n if (argument !== null && returnsFunction(argument)) report(argument)\n return false\n })\n }\n\n return {\n FunctionDeclaration(node) {\n check(node)\n },\n FunctionExpression(node) {\n check(node)\n },\n ArrowFunctionExpression(node) {\n check(node)\n },\n }\n }\n}\n\nexport default new RequireHookObjectReturn()\n","import type { TSESLint } from \"@typescript-eslint/utils\"\nimport type { NitpickerRuleDocs } from \"@/lib/utils/rules\"\n\nimport migrationTableOrder from \"@/rules/adonisjs/migrationTableOrder\"\nimport requireControllerJSDoc from \"@/rules/adonisjs/requireControllerJSDoc\"\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 noEmojis from \"@/rules/base/noEmojis\"\nimport noJSDocBlankBeforeTags from \"@/rules/base/noJSDocBlankBeforeTags\"\nimport noJSDocReturnsOnVoid from \"@/rules/base/noJSDocReturnsOnVoid\"\nimport noLineCommentBackticks from \"@/rules/base/noLineCommentBackticks\"\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 requireCapitalizedComments from \"@/rules/base/requireCapitalizedComments\"\nimport requireFrameworkConfig from \"@/rules/base/requireFrameworkConfig\"\nimport requireFunctionJSDoc from \"@/rules/base/requireFunctionJSDoc\"\nimport requireMultilineObject from \"@/rules/base/requireMultilineObject\"\nimport requireContextHookDestructure from \"@/rules/react/requireContextHookDestructure\"\nimport requireHookObjectReturn from \"@/rules/react/requireHookObjectReturn\"\n\n/**\n * Every rule instance registered by the plugin.\n */\nconst ruleInstances = [\n migrationTableOrder,\n requireControllerJSDoc,\n requireMigrationJSDoc,\n maxJSDocDescriptionLength,\n noAliasVariables,\n noBritishEnglish,\n noDecorativeCommentSeparators,\n noEmDash,\n noEmojis,\n noJSDocBlankBeforeTags,\n noJSDocReturnsOnVoid,\n noLineCommentBackticks,\n noLineCommentPeriod,\n noPropertyAccessAlias,\n noPropertyDestructuring,\n noSingleLineJSDoc,\n requireCapitalizedComments,\n requireFrameworkConfig,\n requireFunctionJSDoc,\n requireMultilineObject,\n requireContextHookDestructure,\n requireHookObjectReturn,\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.5.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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alien_intelligence/eslint-plugin-nitpicker",
|
|
3
3
|
"productName": "Nitpicker",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"description": "A hyper-pedantic ESLint plugin that flags every stylistic and semantic nit, with AI-friendly fix context.",
|
|
6
6
|
"author": "Alien <contact@alien.club> (https://www.alien.club/)",
|
|
7
7
|
"license": "MIT",
|