wanner.work|rules

@wanner.work/oxlint-rules

Method Rules

All rules regarding reusable methods

Rules that govern how standalone method files (and the methods declared inside component files) are written. Every rule is enabled by the recommended config and applies to .ts / .tsx files inside a /methods/ folder of your project. The two "inside vs. outside components" rules are scoped by the folder the file lives in.

method-name-camel-case

Require top-level method names in /methods/ files to use camelCase.

Do

src/methods/getRandomNumber.ts
export default function getRandomNumber() {
  return 4
}

Don't

src/methods/GetRandomNumber.ts
function GetRandomNumber() {
  return 4
}

export default GetRandomNumber

A name is considered camelCase when it starts with a lowercase letter and only contains alphanumeric characters — no underscores, no leading capital.

method-one-per-file

Require method files to contain only one top-level method.

Do

src/methods/parseValue.ts
export default function parseValue() {
  return 'value'
}

Don't

src/methods/parseValue.ts
function parseValue() {
  return 'value'
}

function formatValue() {
return 'formatted'
}

export default parseValue

If you need a second method, move it to its own file under src/methods/. This keeps each method easy to find, easy to test, and trivial to lazy-load.

method-require-default-export

Require method files to default export their top-level method.

Do

src/methods/loadConfig.ts
export default function loadConfig() {
  return { env: 'dev' }
}

Don't

src/methods/loadConfig.ts
function loadConfig() {
  return { env: 'dev' }
}

export { loadConfig }

A named export would force every caller to know the method's original name. A default export lets the importer rename the method to fit the surrounding context (e.g. loadConfig as config).

method-options-interface

Allow Options interfaces in method files only when they are declared locally or imported from a /types/ folder.

Do

src/methods/buildRequest.ts
interface Options {
  includeMetadata: boolean
}

export default function buildRequest(id: string, options: Options): string {
  return options.includeMetadata ? `${id}:meta` : id
}

Don't

src/methods/saveUser.ts
export interface Options {
  skipValidation: boolean
}

export default function saveUser(userId: string, options: Options): string {
  return options.skipValidation ? userId : `${userId}:validated`
}

Shared option objects should live in /types/, not be re-exported from the method file:

src/methods/sendNotification.ts
// Imported Options types are allowed when the path is under /types/
import type SendNotificationOptions from '../types/SendNotificationOptions'

export default function sendNotification(
  userId: string,
  options: SendNotificationOptions
): string {
  return options.notifyByEmail ? `${userId}:email` : `${userId}:in-app`
}

The rule enforces all of the following at once:

  • An Options interface must not be exported from a method file.
  • An Options type imported from anywhere other than a /types/ folder is rejected.
  • A method that uses an Options parameter must either declare a local Options interface or import it from /types/.

Importing an Options type from a non-/types/ path is treated the same as a locally declared one — both are reported. The intent is to keep option contracts in one obvious place.

method-outside-components-function-declaration

Require methods declared outside components to be function declarations. This applies to any method in /methods/ (and any top-level method that is not the default-exported component of a /components/ file).

Do

src/methods/buildQuery.ts
export default function buildQuery() {
  return 'SELECT 1'
}

Don't

src/methods/buildQuery.ts
const buildQuery = () => {
  return 'SELECT 1'
}

export default buildQuery

Inline default-exported arrow functions are also rejected:

src/methods/formatDate.ts
// No name attached to the default export
export default () => {
  return '2026-01-01'
}

method-inside-components-arrow-function

Require methods declared inside component files to use arrow functions. This applies to nested functions in /components/ files.

Do

src/components/UserActions.tsx
export default function UserActions() {
  const handleClick = () => {
    return 'clicked'
  }

return <button>{handleClick()}</button>
}

Don't

src/components/UserActions.tsx
export default function UserActions() {
  function handleClick() {
    return 'clicked'
  }

  return <button>{handleClick()}</button>
}

Named function expressions are rejected for the same reason — arrow functions are the convention inside components:

src/components/OrderActions.tsx
export default function OrderActions() {
  const handleSubmit = function handleSubmit() {
    return 'submitted'
  }

  return <button>{handleSubmit()}</button>
}

Top-level function declarations in a component file are the component itself (governed by component-default-export-function-declaration). This rule only fires for methods that are nested inside the component function.

On this page