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

@crescware/eslint-plugin-crescware-no-inline-expected

v0.0.3

Published

An [oxlint](https://oxc.rs/docs/guide/usage/linter) JS plugin that forbids passing an inline object or array literal as the expected value to an `expect(...)` matcher. Declare the expected value in a `const` variable first.

Readme

@crescware/eslint-plugin-crescware-no-inline-expected

An oxlint JS plugin that forbids passing an inline object or array literal as the expected value to an expect(...) matcher. Declare the expected value in a const variable first.

Rule: no-inline-expected

When the expected value of an assertion is written inline as an object or array literal (expect(actual).toEqual({ ... }) / expect(actual).toStrictEqual([ ... ])), extract it into a named variable. A named expected separates "what is being compared" from "what the answer should be", keeps the assertion line short, and gives the expected value a name to refer to.

// NG: an inline object literal as the expected value
expect(actual).toEqual({ id: 1, name: "Alice" });

// NG: an inline array literal as the expected value
expect(actual).toEqual([1, 2, 3]);

// NG: an empty literal is still an inline literal
expect(actual).toEqual({});
expect(actual).toEqual([]);

// OK: the expected value is declared first
const expected = { id: 1, name: "Alice" };
expect(actual).toEqual(expected);

// OK: a non-literal argument is out of scope
expect(actual).toEqual(buildExpected());

By default the rule also enforces that, inside a test / it callback, the expected variable is declared first — at the top of the callback. Only declarations of variables that the expected value uses may precede it, and even those may not be part of the value passed to expect(...).

// NG: an unrelated variable is declared above expected
test("...", () => {
  const something = {};
  const expected = {};
  expect(something).toEqual(expected);
});

// NG: expected is aliased from the value under test
test("...", () => {
  const actual = { a: 1 };
  const expected = actual;
  expect(actual).toStrictEqual(expected);
});

// OK: expected is declared first
test("...", () => {
  const expected = {};
  const actual = {};
  expect(actual).toEqual(expected);
});

// OK: a variable used to build expected may precede it, as long as it is not
// the value under test
test("...", () => {
  const id = makeId();
  const expected = { id, name: "alice" };
  const actual = makeUser(id);
  expect(actual).toEqual(expected);
});

Scope

The rule fires when all of the following hold for a call expression:

  • The callee is a member access whose property is one of the configured matchers (default: toEqual, toStrictEqual).
  • The receiver chain is anchored at an expect(...) call. Modifier chains are followed, so expect(x).not.toEqual(...), expect(x).resolves.toEqual(...), expect(x).rejects.toEqual(...), and expect.soft(x).toEqual(...) are all in scope. An unrelated foo.toEqual({ ... }) that is not anchored at expect is not reported.
  • An argument is a plain object literal (ObjectExpression) or array literal (ArrayExpression), optionally wrapped in as / satisfies clauses ({ ... } as Foo, [ ... ] as const, { ... } satisfies T, including multi-step chains such as { ... } as unknown as T). The wrappers are unwrapped to classify the underlying literal.

Notes:

  • Object and array literals are treated the same, including empty {} / [].
  • Every argument is inspected, so multi-argument matchers (e.g. a configured toHaveBeenCalledWith) report each inline literal.
  • The rule applies to JavaScript (.js / .mjs / .cjs / .jsx) as well as TypeScript: it targets a runtime assertion call, not any TypeScript-only syntax.
  • The expected-first check (on by default) only applies inside a test / it callback, and only when the expected value is a plain identifier declared directly in that callback. An expected value that is an inline literal, a call, or declared elsewhere (an outer scope, a parameter, an import) has no callback-top position to enforce and is left alone. Modifier and table forms (it.only, test.each(table)(...)) are recognized.
  • Type-only declarations (type / interface) introduce no runtime value, so they are always allowed above the expected declaration, whether or not the expected value uses them.
  • The rule does not autofix; it reports only.

Options

"crescware-no-inline-expected/no-inline-expected": [
  "error",
  {
    // The matcher names to check. Replaces the default set, not extends it.
    "matchers": ["toEqual", "toStrictEqual"],

    // true (default): inside a `test` / `it` callback the expected variable
    // must be declared first. Set to false to disable this check.
    "requireExpectedFirstInTest": true
  }
]

| Option | Type | Default | Effect | | ---------------------------- | ---------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | matchers | string[] | ["toEqual", "toStrictEqual"] | The matcher names whose inline-literal arguments are reported. Setting this replaces the default set. Add names such as toMatchObject, toContainEqual, or toHaveBeenCalledWith to widen coverage. | | requireExpectedFirstInTest | boolean | true | When true, additionally requires the expected variable to be declared first inside its test / it callback. Only declarations of variables the expected value uses may precede it (and not the value under test). Set to false to disable this check. |

Usage

Register the plugin in your .oxlintrc.json and enable the rule:

{
  "jsPlugins": ["@crescware/eslint-plugin-crescware-no-inline-expected"],
  "rules": {
    "crescware-no-inline-expected/no-inline-expected": "error"
  }
}

Stack

Setup

mise install
corepack enable
pnpm install

Scripts

| Command | Description | | ------------------ | ---------------------------------------- | | pnpm build | Compile src to dist | | pnpm check | Run all checks (types, lint, knip, test) | | pnpm check:types | Type check | | pnpm check:lint | Lint and format check | | pnpm check:knip | Unused files/exports check | | pnpm test | Run fixture integration tests | | pnpm format | Fix lint and format |