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
| Rule | Synopsis |
|---|---|
| No Default Export Declaration | Disallow attaching function or class declarations to export default. |
| No Implicit Boolean | Require explicit comparisons instead of truthy/falsy coercion in conditions. |
| Require Explicit Return | Require an explicit return; at the end of void function bodies. |
| Require Hash Private | Require #hash notation for private class members. |
| Require Kebab Case Filename | Require kebab-case file names for TypeScript files. |
| Require Naming Convention | Enforce context-aware naming conventions for identifiers. |
| Require Node Protocol | Require node: protocol when importing Node.js built-in modules. |
| Require Undefined Init | Require = undefined when declaring uninitialized variables. |
| Switch Case Blocks | Require block-wrapped switch cases so declarations stay scoped per branch. |
Formatting
| Rule | Synopsis |
|---|---|
| No Complex Arrow Concise | Require block body on complex concise arrows. |
| No Multiline Strings | Use [].join() instead of multiline string content. |
| No Raw Text in Code | Ban unwrapped text inside <code> elements to prevent MDX parsing issues. |
| No Ternary in Template Literal | Extract ternary expressions out of template literal interpolation slots. |
| Require Import Order | Require 6-group import ordering with blank line separation. |
| Require Multiline Condition Groups | Require expanded formatting for parenthesized groups in mixed-operator logical expressions. |
| Require Multiline Conditions | Require multiline format when a logical expression exceeds the inline operand limit. |
| Require Padding Lines | Require blank lines between specific statement patterns for readability. |
| Require Ternary Parens | Require parenthesized condition in ternaries. |
JSDoc
| Rule | Synopsis |
|---|---|
| Require JSDoc Body | Require a body paragraph in JSDoc blocks that explains why the declaration exists. |
| Require JSDoc Hierarchy | Require summary lines to follow hierarchy chain from file path. |
| Require JSDoc Param Alignment | Require vertical alignment of @param types, names, and dashes. |
| Require JSDoc Param Name | Require @param descriptions to match param name. |
| Require JSDoc Presence | Require a leading JSDoc block on every documentable symbol. |
| Require JSDoc Private | Require @private tag for private class members. |
| Require JSDoc Returns | Require every @returns tag to contain only a type in braces. |
| Require JSDoc Since | Require a valid @since tag (a released version or UNRELEASED) in every JSDoc block. |
| Require JSDoc Tag Order | Require JSDoc tags to follow canonical order with one blank line between groups. |
Nova
| Rule | Synopsis |
|---|---|
| No Logger.dev | Flag Logger.dev calls so dev-only logging gets caught before production. |
Patterns
| Rule | Synopsis |
|---|---|
| No Assign Then Return | Return expressions directly instead of assigning to an intermediate variable. |
| No Await In Loop | Disallow await inside loops so sequential calls are parallelized. |
| No Boolean Var For If | Disallow extracting multi-condition boolean into a variable used once in the next if. |
| No Bracket Assignment | Use Reflect.set() instead of bracket notation assignment. |
| No Bracket Method Call | Use dot notation to call methods instead of bracket notation with static keys. |
| No Template Curly in String | Catch ${...} in regular strings so missing backticks are found early. |
| No Use Before Define | Catch identifiers used before declaration so read order matches definition order. |
Regex
| Rule | Synopsis |
|---|---|
| No Regex Literal Flags | Ban flags on regex literals so callers add flags at the call site. |
| No Regex Literals | Ban inline regex literals so patterns are centralized in a shared file. |
Safety
| Rule | Synopsis |
|---|---|
| No Script URL | Block javascript: URLs in string literals. |
Syntax
| Rule | Synopsis |
|---|---|
| No Destructuring | Ban destructuring in callbacks, loops, functions, declarations, assignments. |
| No Numeric Literals | Use parseInt() with an explicit base instead of binary, octal, or hex literals. |
| No Optional Chaining | Ban the ?. operator so null/undefined checks are explicit. |
| No Rest Params | Ban rest parameters so function signatures list parameters explicitly. |
TypeScript
| Rule | Synopsis |
|---|---|
| No Catch Unknown Annotation | Remove redundant : unknown annotations from catch clause variables. |
| No Explicit Any | Disallow the any type in favor of unknown or specific types. |
| No Inline Type Annotation | Require named type aliases instead of inline type annotations in code files. |
| No Shared Type Import | Prevent code files from importing shared type files directly. |
| Require Bracket Property Access | Require bracket notation instead of dot notation on project-defined objects. |
| Require Type Naming | Require 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.
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.
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
| Suite | Synopsis |
|---|---|
| Dotenv | Enforce double-quoted values in .env and .env.sample files. |
| Frontmatter | Require valid frontmatter fields on every Markdown and MDX content file. |
| Link | Verify internal documentation links and anchors resolve to real targets. |
| Markdown Table | Require tables to match canonical MarkdownTable output. |
| Terminology | Validate <Terminology> components against a glossary page. |
| Type Declarations | Audit .d.ts mirror files against their sources for structure, order, and naming. |
Using Nova presets? See Presets for composable ESLint and TSConfig layers.