AI Agent Lint Rules SDK - programmatic JSX/TSX linting for AI code generation
Package Exports
laint
laint/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (laint) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
laint
AI Agent Lint Rules SDK - a simple programmatic API for linting JSX/TSX code.
// Exclude mode: run ALL rules except those listedconst results =lintJsxCode(code,{
rules:['no-stylesheet-create'],// rules to skip
exclude:true,});// Run all 31 rulesconst allResults =lintJsxCode(code,{
rules:[],
exclude:true,});// Get list of all available rulesconst ruleNames =getAllRuleNames();// ['no-relative-paths', 'expo-image-import', ...]
Available Rules (31 total)
Expo Router Rules
Rule
Severity
Description
no-relative-paths
error
Use absolute paths in router.navigate/push and Link href
header-shown-false
warning
(tabs) Screen in root layout needs headerShown: false
React Native / Expo Rules
Rule
Severity
Description
no-stylesheet-create
warning
Use inline styles instead of StyleSheet.create()
no-safeareaview
warning
Use useSafeAreaInsets() hook instead of SafeAreaView
expo-image-import
warning
Import Image from expo-image, not react-native
no-tab-bar-height
error
Never set explicit height in tabBarStyle
scrollview-horizontal-flexgrow
warning
Horizontal ScrollView needs flexGrow: 0
expo-font-loaded-check
error
useFonts() must check loaded before rendering
tabs-screen-options-header-shown
warning
Tabs screenOptions should have headerShown: false
native-tabs-bottom-padding
warning
NativeTabs screens need 64px bottom padding
textinput-keyboard-avoiding
warning
TextInput should be inside KeyboardAvoidingView
Liquid Glass Rules (expo-glass-effect)
Rule
Severity
Description
no-border-width-on-glass
error
No borderWidth on GlassView (breaks borderRadius)
glass-needs-fallback
warning
Check isLiquidGlassAvailable() before using GlassView
glass-interactive-prop
warning
GlassView in pressables needs isInteractive={true}
screenStyleInterpolator functions must include "worklet" directive
transition-progress-range
warning
interpolate() should cover full [0, 1, 2] range including exit phase
transition-gesture-scrollview
warning
Use Transition.ScrollView/FlatList instead of regular versions
transition-shared-tag-mismatch
warning
sharedBoundTag on Transition.Pressable must have matching Transition.View
transition-prefer-blank-stack
warning
Use Blank Stack instead of enableTransitions on Native Stack
Tailwind CSS Rules
Rule
Severity
Description
no-tailwind-animation-classes
warning
Avoid animate-* classes, use style jsx global instead
Backend / SQL Rules
Rule
Severity
Description
no-require-statements
error
Use ES imports, not CommonJS require
no-response-json-lowercase
warning
Use Response.json() instead of new Response(JSON.stringify())
sql-no-nested-calls
error
Don't nest sql template tags
General Rules
Rule
Severity
Description
prefer-lucide-icons
warning
Prefer lucide-react/lucide-react-native icons
Rule Details
no-relative-paths
// Bad
router.navigate('./profile');<Linkhref="../settings">
// Good
router.navigate('/(tabs)/profile');
<Linkhref="/settings">
browser-api-in-useeffect
// Bad - breaks SSRfunctionComponent(){const width = window.innerWidth;return<div>{width}</div>;}// GoodfunctionComponent(){const[width, setWidth]=useState(0);useEffect(()=>{setWidth(window.innerWidth);},[]);return<div>{width}</div>;}
fetch-response-ok-check
// Badconst response =awaitfetch('/api/data');const data =await response.json();// Goodconst response =awaitfetch('/api/data');if(!response.ok){thrownewError(`HTTP ${response.status}`);}const data =await response.json();
no-response-json-lowercase
// BadreturnnewResponse(JSON.stringify({ data }));// Goodreturn Response.json({ data });
tabs-screen-options-header-shown
// Bad<TabsscreenOptions={{tabBarStyle:{...}}}>
// Good
<TabsscreenOptions={{headerShown:false,tabBarStyle:{...}}}>
native-tabs-bottom-padding
When using NativeTabs from expo-router/unstable-native-tabs, each screen needs 64px bottom padding to prevent content overlap with the tab bar.
textinput-keyboard-avoiding
// Bad - keyboard will cover input<View><TextInputplaceholder="Enter text"/></View>// Good<KeyboardAvoidingView><TextInputplaceholder="Enter text"/></KeyboardAvoidingView>
glass-no-opacity-animation
// Bad - opacity animation causes visual glitches on GlassView<GlassViewstyle={{opacity: fadeAnim }}/>// Good - use transform animations instead<GlassViewstyle={{transform:[{scale: scaleAnim }]}}/>
no-complex-jsx-expressions
// Bad - IIFE in JSX<div>{(()=>{const x =compute();return x;})()}</div>;// Good - extract to variableconst computedValue =compute();<div>{computedValue}</div>;
no-tailwind-animation-classes
// Bad - CSS animation classes have issues<divclassName="animate-spin"/>// Good - use style jsx global for animations<stylejsxglobal>{`
.spinner { animation: spin 1s linear infinite; }
`}</style><divclassName="spinner"/>
// Bad - only covers [0, 1], missing exit phasescreenStyleInterpolator:(progress)=>{'worklet';const opacity =interpolate(progress,[0,1],[0,1]);return{ opacity };};// Good - covers full [0, 1, 2] rangescreenStyleInterpolator:(progress)=>{'worklet';const opacity =interpolate(progress,[0,1,2],[0,1,0]);return{ opacity };};
transition-gesture-scrollview
// Bad - regular ScrollView conflicts with transition gesturesimport{ Transition }from'react-native-screen-transitions';import{ ScrollView }from'react-native';<ScrollView>...</ScrollView>;// Goodimport{ Transition }from'react-native-screen-transitions';<Transition.ScrollView>...</Transition.ScrollView>;
transition-shared-tag-mismatch
// Bad - Pressable tag has no matching View<Transition.PressablesharedBoundTag="hero"><Imagesource={img}/></Transition.Pressable>// Good - matching tags on both components<Transition.PressablesharedBoundTag="hero"><Imagesource={img}/></Transition.Pressable><Transition.ViewsharedBoundTag="hero"><Imagesource={img}/></Transition.View>
transition-prefer-blank-stack
// Bad - enableTransitions on Native Stack has edge cases<Stack.Screenoptions={{enableTransitions:true}}/>;// Good - use Blank Stack from react-native-screen-transitionsimport{ BlankStack }from'react-native-screen-transitions';
sql-no-nested-calls
// Bad - nested sql causes issues
sql`UPDATE users SET ${sql`name = ${name}`} WHERE id = ${id}`;// Good - build query properly
sql`UPDATE users SET name = ${name} WHERE id = ${id}`;
Adding a New Rule
Create a rule file in src/rules/:
// src/rules/my-rule.tsimport traverse from'@babel/traverse';importtype{ File }from'@babel/types';importtype{ LintResult }from'../types';exportfunctionmyRule(ast: File, code:string): LintResult[]{const results: LintResult[]=[];traverse(ast,{CallExpression(path){// Check for violations...
results.push({
rule:'my-rule',
message:'Description of the issue',
line: path.node.loc?.start.line ??0,
column: path.node.loc?.start.column ??0,
severity:'error',// or 'warning'});},});return results;}