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

@futdevpro/dynamo-eslint

v1.20.83

Published

Shared ESLint configs, Dynamo-powered plugin and validators for FutDevPro stacks

Readme

@futdevpro/dynamo-eslint

Shared ESLint presets, custom Dynamo rules, and validation tools for FutDevPro TypeScript projects. This package provides standardized linting configurations optimized for lint-on-save functionality across different project types.

🚀 Quick Start

Installation

npm install --save-dev @futdevpro/dynamo-eslint

Required Peer Dependencies

npm install --save-dev \
  eslint@~9.39.5 \
  [email protected] \
  typescript-eslint@~8.67.0

For Angular projects, also install:

npm install --save-dev \
  angular-eslint@~20.7.0

angular-eslint is an optional peer for Node-only consumers and is required when loading the ngx or ngx-package preset.

📋 Available Presets

Test files are exempt (every preset, BFR-FLEET-014). In *.spec.ts, *.test.ts (and .tsx, *.e2e-spec.ts) every type and code rule is off; the ONE rule tests keep is the name prefix — describe('| …'), it('| …') (@futdevpro/dynamo/require-test-description-prefix). The exemption is the last entry of every preset and is computed from the preset's own rules, so a rule added later is exempted in tests too. If you append your own entry for **/*.ts after a preset, wrap the result again: require('@futdevpro/dynamo-eslint/test-file-exemption').withTestFileExemption([ ...preset, yourEntry ]).

1. base - Core TypeScript Rules

Generic TypeScript projects with browser environment.

const baseConfig = require('@futdevpro/dynamo-eslint/base');

module.exports = baseConfig;

Features:

  • Browser environment
  • 1000 line limit
  • All Dynamo custom rules enabled
  • Explicit return types required
  • A dropped promise is reported (@typescript-eslint/no-floating-promises, type-aware, in every preset): an async call without await, return, .catch or void. Mark intended fire-and-forget with void; Router.navigate / navigateByUrl are known safe (the router emits a NavigationError itself)

2. nts - Node TypeScript Projects

Node.js TypeScript applications and services.

const ntsConfig = require('@futdevpro/dynamo-eslint/nts');

module.exports = ntsConfig;

Features:

  • Node environment
  • 1500 line limit (extended for server code)
  • Module source type
  • All base rules + Node-specific optimizations

3. ngx - Angular Projects

Angular applications with component and template linting.

const ngxConfig = require('@futdevpro/dynamo-eslint/ngx');

module.exports = ngxConfig;

Features:

  • Angular ESLint integration
  • Browser environment
  • Component and template linting
  • Angular-specific rules

4. fsm - Full Stack Module

Full-stack TypeScript modules (same as base).

const fsmConfig = require('@futdevpro/dynamo-eslint/fsm');

module.exports = fsmConfig;

5. nts-package - Node TypeScript Packages

NPM packages and libraries built with TypeScript.

const ntsPackageConfig = require('@futdevpro/dynamo-eslint/nts-package');

module.exports = ntsPackageConfig;

Features:

  • Relaxed @typescript-eslint/ban-types and no-explicit-any rules
  • Optimized for package development
  • Extended line limits for library code

6. ngx-package - Angular Packages

Angular libraries and packages.

const ngxPackageConfig = require('@futdevpro/dynamo-eslint/ngx-package');

module.exports = ngxPackageConfig;

⚙️ Lint-on-Save Configuration

Critical: Configure ESLint to run ONLY on save, not on type!

VSCode/Cursor Settings

Create .vscode/settings.json in your project root:

{
  "eslint.run": "onSave",
  "eslint.workingDirectories": [{ "mode": "auto" }],
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "eslint.validate": [
    "javascript",
    "typescript"
  ]
}

Workspace vs User Settings

  • Workspace settings (.vscode/settings.json): Apply only to current project
  • User settings: Apply globally to all projects

For team consistency, use workspace settings.

Multi-Root Workspace Configuration

For workspaces with multiple projects:

{
  "eslint.run": "onSave",
  "eslint.workingDirectories": [
    { "mode": "auto" },
    { "directory": "./packages/package-a" },
    { "directory": "./packages/package-b" }
  ],
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  }
}

🔧 Custom Dynamo Rules

This package includes custom ESLint rules for Dynamo conventions:

Import Rules

  • @futdevpro/dynamo/import-order: Enforces consistent import ordering
  • @futdevpro/dynamo/no-import-type: Forbids TypeScript import type syntax
  • @futdevpro/dynamo/no-js-import: Prevents importing .js files in TypeScript

Naming Rules

  • @futdevpro/dynamo/naming-patterns: Enforces DyFM naming conventions

Type Rules

  • @futdevpro/dynamo/explicit-types: Enforces explicit type annotations on all TypeScript declarations (functions, variables, parameters, class properties, destructuring)

Security Rules

  • @futdevpro/dynamo/no-unlisted-inner-html (BFR-QA-005): XSS-surface guard — reports every [innerHTML] binding (.html and inline .ts templates) and every bypassSecurityTrust…(…) call, EXCEPT in reviewed files on the allow list and up to the committed per-file baseline. So today's surfaces pass and every NEW one fails. Options: allow: string[] (path suffixes) · baselineFile (default .dynamo/xss-surface-baseline.json) · escapePipe (path suffix of your escaping pipe — it must escape & < > " BEFORE producing HTML). Comments and *.spec.ts files are ignored.

    Adopt it in a project (run in the folder ESLint runs in, e.g. client/):

    npx dynamo-xss-surface-baseline          # writes .dynamo/xss-surface-baseline.json — commit it
    npx dynamo-xss-surface-baseline --check  # exit 1 if the surface grew beyond the committed baseline

    The ngx preset switches the rule on (error) only when that baseline file exists — without it nothing changes, so a dependency bump never breaks an existing lint step. Regenerate the baseline only after a reviewed change. ⚠️ A rule-level baseline on purpose: ESLint's own --suppress-rule is applied only by the ESLint CLI, not by the ESLint API that ng lint uses (measured on eslint 9.39.5).

UI Building-Block Rules

  • @futdevpro/dynamo/scroll-container-min-h-0 (BFR-QA-004 ①): a scroll container (overflow-(y-)auto|scroll, or a component tag you list as a scroller) that will NOT scroll — between it and the element giving the chain its height (h-full, a fixed height) a column-flex item lacks min-h-0, so the chain grows to the content height. Not reported: a scroll container with its own fixed height, an outer scroll container on the way, an absolute/fixed ancestor, a component host without classes in the template (its host/:host styles are not visible), or no height source in the template at all. The chain is followed inside one template.

  • @futdevpro/dynamo/module-load-failed-branch (BFR-QA-004 ②): a module (…/_modules/<name>/) whose templates show a loading state (…Loading…, inProgress_$, loading-skeleton) but none of which shows a failed state (@if (…error|…failed…), a …load-failed / …error-state component, a load…error|failed test id). A list OF errors (errors) is not a failed state.

  • @futdevpro/dynamo/empty-state-requires-guard (BFR-QA-003): an empty-state message — a Hungarian "none / not yet" sentence (Nincs…, Még nincs…, also in an empty-state component's message) or a @for … @empty branch — with no loading / failed guard: neither an ancestor @if / @else if of the same template nor any template up the rendering parent chain guards it (inProgress, failed_$(), loading, skeleton, load-failed, …Loaded_$()). Unguarded, the user reads "none" WHILE the data loads and AFTER a failed load. Not reported: the empty-state component tag alone (it is also a "select something" placeholder), a permission denial ("Nincs jogosultság…"). Known limits: a guard passed through an [input], an i18n-bound message, a descriptive "Nincs…" sentence, an @empty over a locally computed list — silence a NEW such case with <!-- eslint-disable-next-line @futdevpro/dynamo/empty-state-requires-guard -->. Counted per file in the same baseline (emptyStatesWithoutGuard); the ngx preset switches it on only when the baseline has that section, i.e. after you regenerate the baseline with a version that knows the rule.

    Adopt them in a project (run in the folder ESLint runs in, e.g. client/):

    npx dynamo-ui-building-blocks-baseline                                   # writes .dynamo/ui-building-blocks-baseline.json — commit it
    npx dynamo-ui-building-blocks-baseline --scroller-tag app-pull-to-refresh # a component that IS a scroll container
    npx dynamo-ui-building-blocks-baseline --check                           # exit 1 on a new case

    Exactly like the XSS guard: the ngx preset switches the first two rules on (error) only when that baseline file exists (the empty-state rule: only when it also has its section), so a dependency bump never breaks a --max-warnings=0 lint step. The listed scroller tags live in the baseline's settings, so the rules and the generator always agree. Lower the baseline when you fix a case.

Unused Component Rule

  • @futdevpro/dynamo/no-unused-component (BFR-QA-006, project-wide): an Angular @Component that is built but used NOWHERE in the folder ESLint runs in — its selector is in no comment-free template (.html, or an inline template: in backticks or quotes) and nothing references its class in a usage position (route, lazy route, dialog.open(…), bootstrap, createComponent(…), an assignment…). NOT usages: import … from lines (a route can disappear while its import stays), imports / declarations / exports entries, the component's own file, specs and stories. When a reference exists only in a comment (// X_Component,, <!-- <app-x> -->) the message says a finished feature may be switched off. Meant for apps — in a library every public component is "unused" inside the package.

    Adopt it in a project (run in the folder ESLint runs in, e.g. client/):

    npx dynamo-unused-components-baseline          # writes .dynamo/unused-components-baseline.json — commit it
    npx dynamo-unused-components-baseline --check  # exit 1 on a new unused component

    Same gate as the other baseline guards: the ngx preset switches it on (error) only when that file exists. The project scan is cached per process and re-stamped every 3 s (editor lint-on-save).

🛠️ CLI Validation Tools

Use these commands to validate your codebase:

# Validate import ordering across all TypeScript files
dynamo-validate-imports

# Validate naming conventions across all TypeScript files  
dynamo-validate-naming

# Audit ESLint configurations for duplicate rules
dynamo-eslintrc-audit

# Run comprehensive fixes
dynamo-fix

# Fix missing type annotations (functions, variables, parameters, class properties)
dynamo-fix-return-types

NPM Scripts Integration

Add to your package.json:

{
  "scripts": {
    "lint": "eslint src --ext .ts",
    "lint:fix": "eslint src --ext .ts --fix",
    "validate:imports": "dynamo-validate-imports",
    "validate:naming": "dynamo-validate-naming",
    "audit:eslintrc": "dynamo-eslintrc-audit",
    "fix": "dynamo-fix",
    "fix:types": "dynamo-fix-return-types"
  }
}

Strict lint gate — dynamo-lint-strict

A release/CI gate whose exit code comes from ESLint's aggregated counters (the project's own flat config):

dynamo-lint-strict [patterns...] [--max-warnings <n>] [--json]
dynamo-lint-strict src --max-warnings 0     # zero-warning gate
dynamo-lint-strict src --max-warnings 1200  # ratchet for a known warning backlog

| exit | meaning | |---|---| | 0 | 0 errors (parsing errors included) and warnings within the budget | | 1 | any error, or more warnings than --max-warnings | | 2 | lint could not run — config error, no file matched, crash (never a pass) |

  • Warning budget: without --max-warnings warnings are reported but don't fail; set it explicitly for a gate.
  • --json: the last stdout line is { errorCount, fatalErrorCount, warningCount, fileCount, maxWarnings, legacyEslintignore, passed, exitCode }.
  • .eslintignore is dead in ESLint 9 flat config — the files listed there ARE linted. The gate reports it loudly; move the patterns into an ignores entry of eslint.config.*: module.exports = [ ...require('@futdevpro/dynamo-eslint/ngx'), { ignores: [ 'dist-electron/**' ] } ];

Explicit legacy boolean-name exceptions

dynamo-validate-naming is strict by default. A consumer that must preserve an existing persisted or public contract can allow individual boolean property names in its package.json:

{
  "dynamoEslint": {
    "naming": {
      "allowedBooleanPropertyNames": ["closed", "revoked"]
    }
  }
}

Use this only for fields whose rename requires an explicit data/API migration. The validator rejects malformed configuration and continues to enforce every unlisted boolean property.

🔄 Migration from Manual Configs

Quick Migration Checklist

  1. Install the package and peer dependencies
  2. Replace your .eslintrc.json with the appropriate preset
  3. Configure lint-on-save in VSCode/Cursor settings
  4. Run validation tools to check for issues
  5. Update CI/CD to use the new configuration

Common Migration Issues

  • Peer dependency conflicts: Ensure all peer dependencies are installed
  • Working directory issues: Use "eslint.workingDirectories": [{ "mode": "auto" }]
  • Rule conflicts: The presets handle most conflicts automatically

📖 Detailed Migration Guide: See Migration Guide for step-by-step instructions.

🐛 Troubleshooting

Lint-on-Save Not Working

  1. Check ESLint is running on save only:

    {
      "eslint.run": "onSave"  // NOT "onType"
    }
  2. Verify working directories:

    {
      "eslint.workingDirectories": [{ "mode": "auto" }]
    }
  3. Check file associations:

    {
      "eslint.validate": ["javascript", "typescript"]
    }

Peer Dependency Issues

Ensure all peer dependencies are installed with compatible versions:

npm ls typescript-eslint angular-eslint eslint typescript

ESLint v9 Flat Config

This package now uses ESLint v9 flat config format (eslint.config.js) for all exported presets. The package itself also uses flat config for self-linting.

📁 Examples

Reference implementations are available in the samples/ directory:

  • samples/base/eslint.config.js - Base preset example
  • samples/nts/eslint.config.js - Node TypeScript example
  • samples/ngx/eslint.config.js - Angular example
  • samples/fsm/eslint.config.js - Full Stack Module example
  • samples/nts-package/eslint.config.js - Node TypeScript Package example
  • samples/ngx-package/eslint.config.js - Angular Package example

🔧 Recent Fixes

TypeScript AST Transformation Context Fix

The dynamo-fix-return-types script includes a fix for TypeScript AST transformation context issues. This resolves compilation errors when using ts.visitEachChild() by properly providing the TransformationContext parameter:

// Fixed implementation
return ts.visitEachChild(node, visit, {} as ts.TransformationContext);

This ensures compatibility with TypeScript's AST transformation APIs.

Enhanced Type Annotation Fixing

The dynamo-fix-return-types script now handles comprehensive type annotation fixing:

  • Function declarations: Adds return type annotations
  • Arrow functions: Adds return type annotations
  • Variable declarations: Adds type annotations based on initializer types
  • Function parameters: Adds parameter type annotations
  • Class properties: Adds property type annotations

The script uses TypeScript's type checker to infer appropriate types and automatically adds them to your code.

📚 Self-Linting

This package uses its own presets and rules for self-linting. The ESLint v9 flat config is in eslint.config.js and demonstrates advanced configuration patterns.

🏗️ Architecture

  • Presets: Standardized rule configurations for different project types
  • Custom Rules: Dynamo-specific linting rules for import order and naming
  • CLI Tools: Validation and fixing utilities
  • TypeScript Integration: Full TypeScript AST transformation support

Maintained by: Future Development Program Ltd.
License: ISC
Version: 1.20.3