Skip to main content

Rules and Suites

Nova ships two kinds of checks. ESLint rules are individual, per-file checks you enable one at a time in your flat config. Vitest conformance suites are importable test suites that each scan across multiple files at once — frontmatter, links, tables, and type declarations.

Install

If the package is not in your repo yet, go to Setup and Configure and choose Install into project.

warning

Nova must be installed in your project before importing rules and suites. This is because Node.js resolves imports from your project's node_modules folder.

info

If you wish, you can install Nova globally (into the system) and locally (into the project) at the same time. They will not conflict with each other.

Purpose and Scope

ESLint Rules

Custom rules for JavaScript and TypeScript projects. Each rule is targeted, independent, and safe to adopt — enable only what you need. Each rule focuses on a single concern.

Conventions

RuleSynopsis
No Default Export DeclarationDisallow attaching function or class declarations to export default.
No Implicit BooleanRequire explicit comparisons instead of truthy/falsy coercion in conditions.
Require Explicit ReturnRequire an explicit return; at the end of void function bodies.
Require Hash PrivateRequire #hash notation for private class members.
Require Kebab Case FilenameRequire kebab-case file names for TypeScript files.
Require Naming ConventionEnforce context-aware naming conventions for identifiers.
Require Node ProtocolRequire node: protocol when importing Node.js built-in modules.
Require Undefined InitRequire = undefined when declaring uninitialized variables.
Switch Case BlocksRequire block-wrapped switch cases so declarations stay scoped per branch.

Formatting

RuleSynopsis
No Complex Arrow ConciseRequire block body on complex concise arrows.
No Multiline StringsUse [].join() instead of multiline string content.
No Raw Text in CodeBan unwrapped text inside <code> elements to prevent MDX parsing issues.
No Ternary in Template LiteralExtract ternary expressions out of template literal interpolation slots.
Require Import OrderRequire 6-group import ordering with blank line separation.
Require Multiline Condition GroupsRequire expanded formatting for parenthesized groups in mixed-operator logical expressions.
Require Multiline ConditionsRequire multiline format when a logical expression exceeds the inline operand limit.
Require Padding LinesRequire blank lines between specific statement patterns for readability.
Require Ternary ParensRequire parenthesized condition in ternaries.

JSDoc

RuleSynopsis
Require JSDoc BodyRequire a body paragraph in JSDoc blocks that explains why the declaration exists.
Require JSDoc HierarchyRequire summary lines to follow hierarchy chain from file path.
Require JSDoc Param AlignmentRequire vertical alignment of @param types, names, and dashes.
Require JSDoc Param NameRequire @param descriptions to match param name.
Require JSDoc PresenceRequire a leading JSDoc block on every documentable symbol.
Require JSDoc PrivateRequire @private tag for private class members.
Require JSDoc ReturnsRequire every @returns tag to contain only a type in braces.
Require JSDoc SinceRequire a valid @since tag (a released version or UNRELEASED) in every JSDoc block.
Require JSDoc Tag OrderRequire JSDoc tags to follow canonical order with one blank line between groups.

Nova

RuleSynopsis
No Logger.devFlag Logger.dev calls so dev-only logging gets caught before production.

Patterns

RuleSynopsis
No Assign Then ReturnReturn expressions directly instead of assigning to an intermediate variable.
No Await In LoopDisallow await inside loops so sequential calls are parallelized.
No Boolean Var For IfDisallow extracting multi-condition boolean into a variable used once in the next if.
No Bracket AssignmentUse Reflect.set() instead of bracket notation assignment.
No Bracket Method CallUse dot notation to call methods instead of bracket notation with static keys.
No Template Curly in StringCatch ${...} in regular strings so missing backticks are found early.
No Use Before DefineCatch identifiers used before declaration so read order matches definition order.

Regex

RuleSynopsis
No Regex Literal FlagsBan flags on regex literals so callers add flags at the call site.
No Regex LiteralsBan inline regex literals so patterns are centralized in a shared file.

Safety

RuleSynopsis
No Script URLBlock javascript: URLs in string literals.

Syntax

RuleSynopsis
No DestructuringBan destructuring in callbacks, loops, functions, declarations, assignments.
No Numeric LiteralsUse parseInt() with an explicit base instead of binary, octal, or hex literals.
No Optional ChainingBan the ?. operator so null/undefined checks are explicit.
No Rest ParamsBan rest parameters so function signatures list parameters explicitly.

TypeScript

RuleSynopsis
No Catch Unknown AnnotationRemove redundant : unknown annotations from catch clause variables.
No Explicit AnyDisallow the any type in favor of unknown or specific types.
No Inline Type AnnotationRequire named type aliases instead of inline type annotations in code files.
No Shared Type ImportPrevent code files from importing shared type files directly.
Require Bracket Property AccessRequire bracket notation instead of dot notation on project-defined objects.
Require Type NamingRequire type alias names to start with the class name prefix from file path.

Vitest Conformance Suites

Importable test suites that each scan across multiple files to hold your project's docs and types to the same conventions Nova enforces on itself — frontmatter, internal links, table formatting, glossary references, and type declarations.

Unlike ESLint rules, which check one file at a time, each Vitest suite walks an entire directory tree and reports every violation in a single test run.

info

Each suite imports describe and it from Vitest. Your project must already use Vitest as its test runner.

Each test file collapses to a short import-and-invoke. The suite logic lives in the package; your wrapper supplies the configuration.

src/tests/frontmatter.test.ts
ts
import { registerFrontmatterSuite } from '@cbnventures/nova/rules/vitest';
import * as vitest from 'vitest';

registerFrontmatterSuite({
  vitest,
  enable: 'all',
  requiredFields: ['id', 'title', 'description', 'keywords', 'tags'],
});

Enable API

Every register function takes an enable field that selects which checks run. The field is required so a bare call is a compile error, never a silent no-op.

  • enable: 'all' runs every check the suite defines, including checks added in future versions.
  • enable: ['key-one', 'key-two'] runs exactly the listed checks and ignores the rest.
src/tests/link.test.ts
ts
import { registerLinkSuite } from '@cbnventures/nova/rules/vitest';
import * as vitest from 'vitest';

// Run a frozen subset instead of every check.
registerLinkSuite({
  vitest,
  enable: [
    'link-internal-doc-target-exists',
    'link-self-anchor-exists',
  ],
});

Suites

SuiteSynopsis
DotenvEnforce double-quoted values in .env and .env.sample files.
FrontmatterRequire valid frontmatter fields on every Markdown and MDX content file.
LinkVerify internal documentation links and anchors resolve to real targets.
Markdown TableRequire tables to match canonical MarkdownTable output.
TerminologyValidate <Terminology> components against a glossary page.
Type DeclarationsAudit .d.ts mirror files against their sources for structure, order, and naming.

Using Nova presets? See Presets for composable ESLint and TSConfig layers.