close

no-restricted-syntax

Added in v0.5.2

Configuration

rslint.config.ts
import { defineConfig, js } from '@rslint/core';

export default defineConfig([
  js.configs.recommended,
  {
    rules: {
      'no-restricted-syntax': 'error',
    },
  },
]);

Rule Details

Disallows specified syntax. The rule accepts a list of esquery selectors; any AST node matching one of the listed selectors triggers a diagnostic with either a default or user-supplied message.

This is the catch-all rule for restricting language constructs (e.g. banning with, banning for-in, requiring named function declarations) without having to write a dedicated rule. The core selector grammar follows ESLint's esquery-based implementation.

Examples of incorrect code for this rule:

{
  "no-restricted-syntax": [
    "error",
    "FunctionExpression",
    "WithStatement"
  ]
}
with (me) {
  dontMess();
}

const doSomething = function () {};

Examples of correct code for the same configuration:

me.dontMess();

function doSomething() {}

foo instanceof bar;

Options

The rule accepts an array of restriction entries. Each entry is either:

  • A bare string — the esquery selector. The diagnostic message is Using '<selector>' is not allowed..
  • An object { "selector": <string>, "message"?: <string> }. When message is provided it replaces the default text verbatim.
{
  "no-restricted-syntax": [
    "error",
    {
      "selector": "CallExpression[callee.name='setTimeout']",
      "message": "Use the timer service instead of raw setTimeout."
    },
    "WithStatement"
  ]
}

Supported selector forms

The implementation follows the esquery 1.7 selector forms used by ESLint 10.10.0, including the complete upstream no-restricted-syntax test suite. Malformed selectors are a deliberate compatibility divergence: rslint drops the malformed entry so one bad selector does not disable the rest of the configuration, while ESLint rejects the whole rule configuration:

  • ESTree node names (e.g. Identifier, FunctionDeclaration, BinaryExpression) and supported TS-ESTree names such as TSEnumDeclaration. ESTree-only wrapper shapes such as ClassBody, JSXEmptyExpression, ChainExpression, and MethodDefinition.value are exposed as virtual facades over the tsgo AST. Bodyless class methods expose TSEmptyBodyFunctionExpression as their value.
  • Wildcard *.
  • Field selectors, including nested fields (e.g. Literal.key and .body.declarations.init).
  • Attribute selectors with presence ([label]), equality ([name="x"], [kind='using']), inequality (!=), numeric comparisons ([params.length>2]), numeric path segments ([arguments.0.type='Literal']), type(...), and regex matching ([regex.flags=/i/]). Attribute paths may inspect ESLint's parent link. BigInt values retain their JavaScript type: Literal[value=type(bigint)] selects them, while a string regex equality selector does not. Class-method function fields are available through selectors such as MethodDefinition[value.body.body.length=0].
  • Combinators > (direct child), descendant whitespace, + (adjacent sibling), ~ (general sibling), including decorator selectors such as Decorator > CallExpression[callee.name='sealed'].
  • The ! subject marker, including its reverse sibling/adjacent matching behavior, and ESLint's :exit event suffix.
  • Pseudo-classes :is(), :matches(), :not(), :has(), :first-child, :last-child, :nth-child(N), :nth-last-child(N), and the semantic classes :statement, :expression, :declaration, :function, and :pattern.

AST representation note

tsgo does not allocate separate nodes for every ESTree wrapper. Direct selectors and structural relationships for those wrappers are modeled, with ESLint-compatible ranges. The bare * selector retains the engine's physical tsgo traversal, which starts at the program's children and does not emit additional diagnostics for virtual wrappers. Other broad selectors evaluate each supported ESTree identity separately. Program and Program:exit can select the program itself.

TS-ESTree coverage is limited to the supported node mappings; the rule does not materialize every TypeScript type annotation or type-parameter wrapper. Broad selectors on type-only syntax can therefore differ from the TypeScript ESLint parser. Runtime receiver attribute paths retain their existing behavior of looking through TypeScript assertions, such as (console as any).log().

Original Documentation