npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ttsc/lint

v0.19.3

Published

Reference ttsc plugin: ESLint-style lint rules over the TypeScript-Go Program used by the type-check pass.

Readme

@ttsc/lint

banner of @ttsc/lint

GitHub license NPM Version NPM Downloads Build Status Guide Documents Discord Badge

A linter and formatter. Co-protagonist of the ttsc toolchain, paired with ttsc, it replaces eslint and prettier.

720+ rules across 21 families. Lint violations surface as error TSxxxxx from a single compile pass; the formatter applies via ttsc format.

Demonstration

Given this file:

// src/index.ts
var x: number = 3;
let y: number = 4;
const z: string = 5;

console.log(x + y + z);

Run ttsc with @ttsc/lint enabled (see Setup):

$ pnpm ttsc
src/index.ts:3:7 - error TS2322: Type 'number' is not assignable to type 'string'.

3 const z: string = 5;
        ~

src/index.ts:2:5 - error TS17397: [prefer-const] Use const instead of let.

2 let y: number = 4;
      ~~~~~~~~~~~~~

src/index.ts:1:1 - error TS11966: [no-var] Unexpected var, use let or const instead.

1 var x: number = 3;
  ~~~~~~~~~~~~~~~~~~

Found 3 errors in the same file, starting at: src/index.ts:3

Type errors (TS2322) and lint violations (TS17397, TS11966) come out together. No second tool, no second CI step.

Diagnostic code compatibility

Every built-in rule has a unique positive numeric code in the reserved TS9000 through TS17999 band. These assignments are kept in an append-only ledger: adding a built-in rule does not renumber existing rules, and a removed rule's code is not reused. The LSP surface continues to expose the rule ID, such as no-var, in its diagnostic code field.

The ledger introduction preserved every legacy code that was already unique. For each pre-existing collision group, the alphabetically first rule kept the shared legacy code and every other rule received an available code. Those resolved assignments are now frozen by the same append-only policy.

Rules contributed by another Go package share the same collision-free band. Their codes are deterministic for an unchanged complete set of loaded contributors and do not depend on registration order. Adding or removing a contributor recomputes assignments for that complete contributor set and can change contributor codes, but never changes a built-in assignment.

Setup

npm install -D ttsc @ttsc/lint typescript

Drop a lint.config.ts next to your tsconfig.json:

// lint.config.ts
import type { ITtscLintConfig } from "@ttsc/lint";

export default {
  format: {
    printWidth: 100,
    singleQuote: true,
    trailingComma: "all",
  },
  rules: {
    "no-var": "error",
    "prefer-const": "error",
    "typescript/no-explicit-any": "error",
    "typescript/no-floating-promises": "error",
  },
} satisfies ITtscLintConfig;

Run your normal ttsc or ttsx:

npx ttsc
npx ttsx src/index.ts

Errors fail the command; warnings print without affecting the exit code. Under ttsx, errors stop the program before your entrypoint runs.

ttsc fix applies every autofix the enabled rules offer, lint and format together. Writes results back to disk, then re-runs type-check + lint. ttsc format runs the format rule set through the same dataflow.

npx ttsc fix
npx ttsc format

ttsc fix is a one-shot project pass and rejects --watch, single-file mode, and --emit. Fixes are written to disk before the recheck runs, so source stays modified even when the command exits non-zero on remaining errors. Recommended flow: run ttsc fix locally, commit, then have CI run ttsc --noEmit to gate on zero remaining errors.

Format

Configure the formatter through the format block in lint.config.ts. Keys mirror .prettierrc; the presence of the block, even empty format: {}, enables the always-on format rules at Prettier defaults so ttsc format rewrites your source to match.

// lint.config.ts
import type { ITtscLintConfig } from "@ttsc/lint";

export default {
  format: {
    printWidth: 100,
    singleQuote: true,
    trailingComma: "all",
    sortImports: {
      order: ["<BUILTIN_MODULES>", "", "<THIRD_PARTY_MODULES>", "", "^[./]"],
      unsafeSortRuntimeImports: true, // accepts module evaluation reordering
    },
    jsDoc: true,
  },
  rules: { "no-var": "error" },
} satisfies ITtscLintConfig;

ttsc check does not fail on formatting by default. It surfaces format diagnostics only when you opt in with format.severity. ttsc format runs the active format rules across the project and writes results to disk regardless of severity.

Each format key controls one behavior:

| Config key | Effect | | --- | --- | | severity (default "off") | Check-time diagnostic level for formatting. Does not gate ttsc format. | | semi | Insert trailing semicolons on ASI-terminated statements. | | singleQuote | Convert quoted strings to the preferred quote style. | | arrowParens | Add or remove parens around a single arrow parameter. | | bracketSpacing | Spaces inside object and named-import/export braces. | | quoteProps | Quote or unquote object property keys. | | trailingComma | Add trailing commas to multi-line lists. | | printWidth, tabWidth, useTabs, endOfLine | Column-aware line reflow. Object/array literals, call/new arguments, and named import/export clauses break across lines when their flat form overflows the budget. | | sortImports (opt-in) | Sort named specifiers and erased type-only imports. Runtime declaration sorting requires unsafeSortRuntimeImports. | | jsDoc (on by default) | Normalize JSDoc blocks toward prettier-plugin-jsdoc. |

sortImports is opt-in — it takes effect only when you set it. Every other key takes effect as soon as the format block is present (JSDoc normalization included; set jsDoc: false to opt out), which also applies several keyless layout behaviors (statement splitting, indentation, whitespace normalization, clause joining, declaration-header reflow, ternary-nullish parens, leading-semicolon merging, and parameter-property breaking).

The safe default preserves the source order of every runtime-bearing import, including default, namespace, named, and bare imports, because each form can evaluate its dependency module. It still alphabetizes named specifiers within one declaration and can sort or merge a block made entirely of erased import type declarations. Set unsafeSortRuntimeImports: true only when every dependency in the block is order-independent. combineTypeAndValue affects a mixed type/value block only under that unsafe opt-in.

Formatting is configured only through the format block. The rules map is for lint rules; a format/* id placed there is ignored. To turn a format behavior off, set its format key (for example trailingComma: "none"), not a rules entry.

Rules

Lint rules are off until you enable them in lint.config.ts. Severity values: "error" fails the build, "warning" prints without affecting the exit code, "off" disables the rule.

// lint.config.ts
export default {
  rules: {
    "no-var": "error",
    "eqeqeq": "error",
    "prefer-template": "warning",
    "typescript/no-non-null-assertion": "off",
  },
} satisfies ITtscLintConfig;

Rules with options use an ESLint-style tuple such as ["error", { allowElseIf: false }]. A built-in rule whose typed setting is severity-only accepts no payload, even while it is "off"; the engine reports an invalid configuration instead of silently discarding the extra value.

Rule IDs use ESLint-style kebab-case and slash namespaces, no-var, react/jsx-key, testing-library/prefer-screen-queries. The exported ITtscLintRules type is the intersection of family-specific interfaces such as ITtscLintCoreRules, ITtscLintTypeScriptRules, ITtscLintReactRules, and ITtscLintVitestRules, so users can type a whole config or a narrower family-shaped object.

Each rule below links to its TypeScript fixture under tests/test-lint/src/cases/.

ESLint core

Generic ESLint-compatible rules that apply to both JavaScript and TypeScript source. Every rule listed here corresponds 1-to-1 with an ESLint core rule of the same kebab-case id, so projects migrating from ESLint can paste their rule severities into lint.config.ts without renaming anything. TypeScript-only rules and @typescript-eslint extensions live under typescript/* in TypeScript, @ttsc/lint does not accept legacy bare names or @typescript-eslint/* aliases for those.

Source: ESLint core rules.

  • camelcase: reject identifier declarations that aren't camelCase or PascalCase, snake_case bindings are flagged.
  • complexity: reject function bodies whose cyclomatic complexity exceeds twenty (default ESLint threshold).
  • consistent-return: reject functions where some return statements return a value and others fall through without one.
  • curly: require block statements for every if, else, while, for, and do body. Reject the single-statement shorthand.
  • default-case: require switch statements to include a default clause.
  • default-case-last: require the default clause of a switch statement to appear last.
  • default-param-last: keeps parameters with default values at the end of the list.
  • dot-notation: prefers dot property access when a string-literal key is a valid identifier.
  • eqeqeq: requires strict equality operators.
  • for-direction: catches loop counters updated in the wrong direction.
  • getter-return: require a get accessor's body to return a value on every reachable exit.
  • grouped-accessor-pairs: require the get and set accessors of a property to be declared adjacent in the class body.
  • guard-for-in: require a for...in body to be wrapped in an if statement (or to skip iterations with a leading if (...) continue) so inherited keys are guarded, matching ESLint core's structural check.
  • id-length: reject identifier names shorter than two characters.
  • init-declarations: require every var / let declaration to be initialized at its declaration site.
  • max-classes-per-file: reject a source file that declares more than one class.
  • max-depth: reject block-statement nesting deeper than four levels inside a function.
  • max-lines: reject a source file whose total line count exceeds three hundred.
  • max-lines-per-function: reject a function whose body spans more than fifty lines.
  • max-nested-callbacks: reject callback nesting deeper than ten inside a single function.
  • max-params: reject function declarations with more than three parameters.
  • max-statements: reject function bodies whose statement count exceeds ten.
  • no-alert: rejects alert, confirm, and prompt.
  • no-array-constructor: rejects Array constructor calls.
  • no-async-promise-executor: rejects async Promise executors.
  • no-await-in-loop: reject explicit and implicit awaits evaluated in repeated loop positions.
  • no-bitwise: rejects bitwise operators.
  • no-caller: rejects arguments.caller and arguments.callee.
  • no-case-declarations: rejects lexical declarations directly inside case clauses.
  • no-class-assign: rejects reassignment of class declarations.
  • no-compare-neg-zero: rejects comparisons against -0.
  • no-cond-assign: rejects assignments inside conditions.
  • no-console: rejects console calls.
  • no-constant-condition: rejects constant conditions.
  • no-constructor-return: reject return X; (with a value) inside a class constructor.
  • no-continue: rejects continue statements.
  • no-control-regex: rejects control characters in regular expressions.
  • no-debugger: rejects debugger statements.
  • no-delete-var: rejects deleting variables.
  • no-dupe-args: rejects duplicate function parameters.
  • no-dupe-class-members: reject two declarations of the same member on a single class.
  • no-dupe-else-if: rejects duplicate or logically covered else if conditions.
  • no-dupe-keys: rejects duplicate object keys.
  • no-duplicate-case: rejects duplicate switch case labels.
  • no-duplicate-imports: reject a repeated module specifier when the import declarations could be merged into one; allowSeparateTypeImports and includeExports match the ESLint options.
  • no-else-return: reject an else block whose preceding if branch returns on every path.
  • no-empty: rejects uncommented empty blocks and switches; allowEmptyCatch accepts empty catches.
  • no-empty-character-class: rejects empty regex character classes.
  • no-empty-function: rejects uncommented empty functions unless their category is allowed.
  • no-empty-named-blocks: rejects empty named import/export clauses (import {} from "x", export {}).
  • no-empty-pattern: rejects empty destructuring patterns.
  • no-empty-static-block: rejects uncommented empty class static blocks.
  • no-eq-null: rejects loose null comparisons.
  • no-eval: rejects eval.
  • no-ex-assign: rejects reassignment of caught exceptions.
  • no-extend-native: reject assignments to a built-in prototype such as Array.prototype.foo = bar.
  • no-extra-bind: rejects .bind(thisArg) on arrows and regular functions that never read their own this, while preserving partial application.
  • no-extra-boolean-cast: rejects redundant boolean casts.
  • no-fallthrough: rejects switch cases whose end is reachable and that lack an intentional // falls through comment before the next label.
  • no-func-assign: rejects reassignment of function declarations.
  • no-implicit-coercion: reject common implicit-coercion idioms (!!x, +x, "" + x) in favor of the explicit Boolean(x) / Number(x) / String(x) conversions.
  • no-import-assign: resolves imported bindings through the checker and rejects assignments, destructuring and loop writes, plus direct namespace mutations such as ns.x = ... and Object.assign(ns, value).
  • no-inner-declarations: rejects block functions with legacy sloppy semantics; "both" also checks nested var declarations.
  • no-invalid-this: reject this references outside any function-like, class method, or class-static-block context.
  • no-irregular-whitespace: rejects irregular whitespace.
  • no-iterator: rejects __iterator__.
  • no-labels: rejects labels.
  • no-lone-blocks: rejects unnecessary standalone blocks.
  • no-lonely-if: rejects if as the only statement in an else.
  • no-loop-func: reject loop-created closures only when they capture bindings that can change between iterations.
  • no-loss-of-precision: rejects number literals that lose precision.
  • no-magic-numbers: reject inline numeric literals outside const initializer position. 0, 1, -1, array indices, and enum values are exempt.
  • no-misleading-character-class: rejects misleading regex character classes.
  • no-mixed-operators: reject mixing operators of different precedence families in the same expression without explicit parentheses around the inner sub-expression.
  • no-multi-assign: rejects chained assignments.
  • no-multi-str: rejects multiline string escapes.
  • no-negated-condition: rejects negated conditions with an else.
  • no-nested-ternary: rejects nested ternary expressions.
  • no-new: rejects new expressions used only for side effects.
  • no-new-func: rejects Function constructors.
  • no-new-symbol: reject new Symbol(...).
  • no-new-wrappers: rejects primitive wrapper constructors.
  • no-obj-calls: rejects calling global objects as functions.
  • no-object-constructor: rejects new Object().
  • no-octal: rejects legacy octal literals.
  • no-octal-escape: rejects octal escape sequences.
  • no-param-reassign: rejects writes to parameter bindings, with props and property-ignore options matching ESLint.
  • no-plusplus: rejects ++ and --.
  • no-promise-executor-return: rejects values returned by global Promise executors, with an allowVoid option for explicit unary void returns.
  • no-proto: rejects __proto__.
  • no-prototype-builtins: rejects direct Object.prototype method calls.
  • no-redeclare: rejects redeclaring a binding in the same scope.
  • no-regex-spaces: rejects repeated literal spaces in regexes.
  • no-restricted-imports: reject static imports and re-exports selected by user-configured exact paths, gitignore-style groups, or regular expressions.
  • no-restricted-syntax: reject only syntax matching the project's configured TypeScript-Go AST selectors; no selectors means no restrictions.
  • no-return-assign: rejects assignments in return.
  • no-script-url: rejects javascript: URLs.
  • no-self-assign: rejects assignments to the same value.
  • no-self-compare: rejects comparing a value to itself.
  • no-sequences: rejects comma expressions.
  • no-setter-return: rejects returned values from setters.
  • no-shadow: reject a nested-scope binding that shadows a same-name binding from an outer scope.
  • no-shadow-restricted-names: rejects shadowing restricted globals.
  • no-sparse-arrays: rejects sparse arrays.
  • no-template-curly-in-string: rejects ${...} text inside normal strings.
  • no-this-before-super: reject this (or super.x) references that precede the first super() call in a derived constructor.
  • no-throw-literal: rejects throwing literals.
  • no-undef-init: rejects initializing to undefined.
  • no-undefined: rejects the global undefined identifier.
  • no-unneeded-ternary: rejects redundant ternary expressions.
  • no-unreachable: reject statements that follow an unconditional return, throw, break, or continue in the same block, control flow has already left the block, so any later statement is dead code.
  • no-unsafe-finally: rejects control flow from finally.
  • no-unsafe-negation: rejects unsafe negation before relational checks.
  • no-unsafe-optional-chaining: reject member access or call expressions that chain off an optional chain without continuing the chain.
  • no-unused-expressions: rejects expression statements with no effect under ESLint's default semantics, accepting directive prologues (arbitrary text, determined by AST position) and productive expressions such as void promise() while rejecting tagged templates and misplaced strings; the upstream options are supported.
  • no-unused-labels: rejects labels that no break or continue targets.
  • no-useless-assignment: reject an assignment whose value is immediately overwritten by the very next statement without an intervening read of the same identifier.
  • no-useless-call: rejects unnecessary .call() and .apply().
  • no-useless-catch: rejects catch blocks that only rethrow.
  • no-useless-computed-key: rejects unnecessary computed property keys.
  • no-useless-concat: rejects unnecessary string concatenation.
  • no-useless-constructor: rejects empty constructors with no parameters.
  • no-useless-escape: rejects backslash escapes that have no effect inside strings or regexes.
  • no-useless-rename: rejects import/export/destructure renames to the same name.
  • no-useless-return: reject a bare return; whose only effect is to end a function body that would have returned anyway.
  • no-var: rejects var.
  • no-with: rejects with statements.
  • object-shorthand: requires object property shorthand where possible.
  • operator-assignment: prefers compound assignment operators.
  • prefer-arrow-callback: reject function() { ... } expressions passed as callback arguments. Prefer the arrow form.
  • prefer-const: prefers const for lexical let bindings that are never reassigned, including declaration-only and destructured bindings with ESLint-compatible options.
  • prefer-destructuring: reject single-property and single-index variable declarations (const a = obj.a, const x = arr[0]) that destructuring would replace verbatim.
  • prefer-exponentiation-operator: prefers ** over Math.pow.
  • prefer-for-of: prefers for...of for simple array iteration.
  • prefer-named-capture-group: reject regex literals with unnamed capturing groups (...). Prefer named groups (?<name>...).
  • prefer-numeric-literals: prefer ES2015+ numeric literal forms (0b…, 0o…, 0x…) over parseInt(string, 2 | 8 | 16).
  • prefer-object-has-own: prefer Object.hasOwn(obj, key) over Object.prototype.hasOwnProperty.call(obj, key).
  • prefer-object-spread: prefer object-spread { ...a, ...b } over Object.assign({}, a, b).
  • prefer-rest-params: reject reading from arguments in a non-arrow function body. Prefer the ES2015 rest-parameter form (...args).
  • prefer-spread: prefers spread arguments over .apply.
  • prefer-template: prefers template literals over string concatenation.
  • radix: requires a radix argument for parseInt.
  • require-yield: requires generator functions to contain yield.
  • sort-imports: reject import specifiers within a single import declaration that aren't alphabetically sorted.
  • sort-keys: reject object-literal property keys that aren't alphabetically sorted.
  • use-isnan: requires Number.isNaN/isNaN for NaN checks.
  • valid-typeof: restricts typeof comparisons to valid strings.
  • vars-on-top: requires var declarations at the top of their scope.
  • yoda: rejects literal-first comparisons.

TypeScript

TypeScript-only rules and @typescript-eslint plugin equivalents, exposed under the typescript/* namespace. Each rule either requires TypeScript syntax (interface, enum, namespace, as, !, import type, type parameters, declaration merging, parameter properties, triple-slash references) or originates from @typescript-eslint as a TS-aware extension that has no counterpart in plain ESLint.

Source: typescript-eslint.

React

React TSX rules, Hooks correctness, JSX safety, the React Compiler subset, and Fast Refresh export shape. Bundles rules from three upstream plugins under one react/* namespace, matching Oxlint's layout. Performance-only rules live in React performance because they are opt-in toggles rather than correctness checks.

Source: eslint-plugin-react, eslint-plugin-react-hooks, eslint-plugin-react-refresh.

  • react/button-has-type: requires explicit valid type values on JSX button elements.
  • react/component-hook-factories: rejects nested component or Hook factories that call Hooks.
  • react/display-name: require components wrapped in React.memo(...) or React.forwardRef(...) to be named, either by passing a named function, assigning the call to a named binding, or setting an explicit displayName.
  • react/exhaustive-deps: reports high-confidence missing identifier dependencies in useEffect, useLayoutEffect, useInsertionEffect, useMemo, and useCallback.
  • react/iframe-missing-sandbox: requires JSX iframe elements to include a sandbox attribute.
  • react/immutability: rejects local prop mutation inside components and Hooks.
  • react/jsx-key: requires key props for JSX elements produced by arrays or .map().
  • [react/jsx-no-duplicate-props](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/react-jsx-no-duplicate-pr