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

@cofferdam/check-sdk

v0.3.6

Published

Author cofferdam plugin checks in TypeScript. defineCheck factory + types.

Readme

@cofferdam/check-sdk

Author cofferdam plugin checks in TypeScript.

cofferdam is a code-quality analyzer for TypeScript with a Rust core. The built-in checks cover the common ground (complexity, dead exports, triple-equals, etc); this SDK lets you express project-specific architectural rules as checks the same engine runs alongside the built-ins.

Install

pnpm add -D @cofferdam/check-sdk     # pnpm
npm install -D @cofferdam/check-sdk  # npm
yarn add -D @cofferdam/check-sdk     # yarn

The SDK ships compiled JS + types; no runtime dependencies. Node 16+.

Hello check

// my-checks/no-examplco.ts
import { Category, defineCheck, Severity } from "@cofferdam/check-sdk";

export default defineCheck({
  id: "BrandCasing",
  category: Category.Warning,
  basePriority: 15,
  defaultSeverity: Severity.High,
  explanation: "Brand must be spelled EXAMPLCO.",
  files: { extensions: ["ts", "tsx"] },
  options: {
    brand: { default: "EXAMPLCO", type: "string" },
  },
  run(file, ctx, opts) {
    for (const line of file.lines()) {
      // Pattern A — line walk. Skip comments and skip non-string content
      // so we don't false-positive on identifiers / JSX text.
      if (line.isComment || line.isJsxText) continue;
      if (!line.isStringLiteral) continue;
      const m = /\bExamplco\b/.exec(line.text);
      if (!m) continue;
      ctx.report({
        message: `Brand must be ${opts.brand}, not ${m[0]}.`,
        span: line.spanFor(m.index, m.index + m[0].length),
      });
    }
  },
});

Wire it into cofferdam.toml:

plugins = ["./my-checks/no-examplco.ts"]

[checks."BrandCasing"]
brand = "EXAMPLCO"

Then cofferdam check src/ runs your plugin alongside every built-in check. Findings flow through the same priority computation, suppression directives, baseline diffing, and output formats.

Three patterns

The SDK supports three check shapes, each suited to a different rule class:

  • Pattern A — line walk. for (const line of file.lines()) { … }. Best for content checks against string literals or comments (brand spelling, banned words, license headers). The fastest path; no AST parse needed.
  • Pattern B — AST findAll. file.ast.findAll("CallExpression"), findAll("ImportDeclaration"). Best when the rule is a tag-and-match against specific node kinds (banned imports, forbidden API calls).
  • Pattern C — stateful walk. file.ast.walk(visitor) with accumulator state, decided per-file. Best when the rule depends on inter-statement context (tenant scoping across queries, accumulator-vs-mutator analysis).

AstView exposes 9 node kinds today: Program, CallExpression, ImportDeclaration, Function, ArrowFunctionExpression, Class, ObjectExpression, MemberExpression, IdentifierReference. The set is additive — new kinds can land in minor releases without breaking existing plugins.

API surface

import {
  defineCheck,           // factory — returns a Check
  Category,              // Consistency | Design | Readability | Refactor | Warning
  Severity,              // Info | Low | Medium | High | Critical
  Walk,                  // visitor return: Continue | Skip
} from "@cofferdam/check-sdk";

import type {
  Check, CheckContext, ReportArgs, Fix,
  SourceFile, LineView, Span, RelatedSpan,
  AstView, AstVisitor, AstNode, NodeKind,
  // Per-kind typed nodes:
  ProgramNode, CallExpressionNode, ImportDeclarationNode,
  FunctionNode, ArrowFunctionExpressionNode, ClassNode,
  ObjectExpressionNode, MemberExpressionNode, IdentifierReferenceNode,
  // Options schema helpers:
  OptionKind, OptionSpec, OptionsSchema, ResolvedOptions,
} from "@cofferdam/check-sdk";

Everything in this list is part of the stability contract; new exports are additive. Removing or renaming an export is a breaking change.

MemberExpression property resolution

MemberExpressionNode exposes two fields: computed: boolean and property: string | undefined.

  • Dot-form (obj.foo, computed=false): property is always the identifier name — e.g. "foo".
  • String-literal-indexed (obj["foo"], computed=true): property resolves to the literal value — e.g. "foo". The resolver only applies when the index is a bare string literal; template literals and concatenation are treated as dynamic.
  • Dynamic-indexed (obj[runtimeVar], computed=true): property is undefined. The index is not statically determinable. Use file.text.slice(node.span.start_byte, node.span.end_byte) if you need the surface form.

In short: property is always set for dot-form, and set for string-literal bracket-form. It is undefined only when the index is truly dynamic.

for (const m of file.ast.findAll("MemberExpression")) {
  if (m.property === "fetch") {
    // Catches both obj.fetch and obj["fetch"]
    ctx.report({ message: "...", span: m.span });
  }
}

ts-morph routing status (0.2.x)

DefineCheckInput exposes a requiresTypes?: boolean field for checks that need full type-aware analysis (resolved types, inferred generics, call signatures). This field is reserved for future use in 0.2.x and is not yet wired. Setting requiresTypes: true today is accepted by the type system and recorded on the Check object, but the engine does not route the check through ts-morph and no type information is available inside run(). The plugin host emits a one-time warning to stderr at load time when it encounters a plugin with requiresTypes: true so authors are not left wondering why type data is absent.

Type-aware routing via ts-morph is on the roadmap. Track cd-l58 / gh #16 for status.

Versioning

The SDK ships in lockstep with the cofferdam binary. @cofferdam/[email protected] is built and tested against @cofferdam/[email protected]; the cofferdam plugin host enforces a major-version compatibility check at load time and refuses to run plugins whose vendored SDK is from a different major.

For 0.x: minor bumps may be breaking. Pin both packages to the same exact version until 1.0:

{
  "devDependencies": {
    "@cofferdam/cofferdam": "0.2.3",
    "@cofferdam/check-sdk": "0.2.3"
  }
}

Documentation

License

MIT.