Setting up lintent for TypeScript/JavaScript projects with ESLint and tsc.

Prerequisites

  • Node.js 18+
  • ESLint and/or TypeScript installed

Quick Setup

# Install lintent
npm install -g lintent

# Install linters (if not already)
npm install -D eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin

# Initialize
lintent init --preset typescript

# Run
lintent run --pretty

Project Structure

my-ts-project/
├── package.json
├── tsconfig.json           # TypeScript config
├── eslint.config.js        # ESLint config (flat config)
├── lintent.yaml             # Semantic rules
└── src/
    └── ...

Configure ESLint (Flat Config)

eslint.config.js:

import eslint from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    rules: {
      "no-unused-vars": "off",
      "@typescript-eslint/no-unused-vars": "error",
      "no-console": "warn",
      "prefer-const": "error",
      "eqeqeq": "error",
      "@typescript-eslint/no-explicit-any": "warn",
    },
  }
);

Configure TypeScript

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "strict": true,
    "noImplicitAny": true,
    "noEmit": true
  },
  "include": ["src/**/*"]
}

Customize Semantic Rules

Edit lintent.yaml:

rules:
  eslint:
    # Preset rules...

    # Project-specific
    "@typescript-eslint/explicit-function-return-type":
      illegal: "Function without explicit return type"
      legal: "function foo(): ReturnType { ... }"
      why: "Explicit returns improve documentation and catch errors"

    "no-restricted-imports":
      illegal: "Importing from restricted module"
      legal: "Use approved alternatives"
      why: "Maintain architecture boundaries"

  typescript:
    TS2571:
      illegal: "Object is of type 'unknown'"
      legal: "Narrow the type with type guards or assertions"
      why: "Unknown requires explicit narrowing for type safety"

Run for Specific Tools

# Only ESLint
lintent run --tool eslint

# Only TypeScript
lintent run --tool typescript

Frontend Framework Support

React

rules:
  eslint:
    "react-hooks/rules-of-hooks":
      illegal: "Hooks called conditionally or in loops"
      legal: "Call hooks at the top level of the component"
      why: "React relies on hook call order between renders"

    "react-hooks/exhaustive-deps":
      illegal: "Missing dependencies in useEffect/useMemo/useCallback"
      legal: "Include all referenced values in dependency array"
      why: "Stale closures cause subtle bugs"

Next.js

rules:
  eslint:
    "@next/next/no-img-element":
      illegal: "Using <img> instead of next/image"
      legal: "Use <Image> from 'next/image'"
      why: "Next Image optimizes loading and layout shift"

CI Integration

GitHub Actions

name: Lint

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm install -g lintent

      - run: lintent run

Common Issues

ESLint Flat Config Not Detected

Ensure you're using eslint.config.js (not .eslintrc.*).

For legacy config, lintent still detects .eslintrc.js, .eslintrc.json, etc.

TypeScript Path Aliases

If you use path aliases in tsconfig.json, TypeScript errors may show aliased paths:

{
  "file": "@/components/Button.tsx",
  "line": 10
}

This is expected - lintent preserves the paths from linter output.

ESLint + TypeScript Integration

For best results, use @typescript-eslint/parser:

// eslint.config.js
import tseslint from "typescript-eslint";

export default tseslint.config(
  // This includes the parser setup
  ...tseslint.configs.recommended,
);