@dylanmerigaud/config
v0.4.0
Published
Shared eslint presets (+ bundled custom-rule plugin), prettier config, and tsconfig base for Dylan Merigaud's micro-SaaS bets.
Readme
@dylanmerigaud/config
Shared ESLint presets (with a bundled custom-rule plugin), Prettier config, and a TypeScript base for my micro-SaaS bets. One package, one version bump, every repo stays in lockstep.
Built on the modern eslint 10 stack: @eslint-react (React + hooks + the React
Compiler rules, one plugin), eslint-plugin-import-x, eslint-plugin-unicorn
(curated), and eslint-plugin-perfectionist for sorted imports.
Install
pnpm add -D @dylanmerigaud/config eslint typescript prettiereslint (>=10.3), typescript (>=5.5 <6.1, the range typescript-eslint
supports), and prettier are peer dependencies. Every ESLint plugin the presets
use is a regular dependency of this package, so you install nothing else.
ESLint
Presets are functions that take { tsconfigRootDir } so the type-checked rules
resolve against your tsconfig (pass import.meta.dirname).
eslint.config.mts (or .mjs) in a Next.js app:
import { next } from "@dylanmerigaud/config/eslint/next";
export default next({ tsconfigRootDir: import.meta.dirname });Framework-agnostic (no React/Next layer):
import { base } from "@dylanmerigaud/config/eslint/base";
export default base({ tsconfigRootDir: import.meta.dirname });Add the opt-in Vitest rules (scoped to test files):
import { next } from "@dylanmerigaud/config/eslint/next";
import { vitest } from "@dylanmerigaud/config/eslint/vitest";
export default [
...next({ tsconfigRootDir: import.meta.dirname }),
...vitest(),
];Add a repo-local rule layer under its own namespace (keep app-specific rules out of this package):
import { next } from "@dylanmerigaud/config/eslint/next";
import { customLocal } from "./config/eslint-rules/index.mjs";
export default [
...next({ tsconfigRootDir: import.meta.dirname }),
{ plugins: { "custom-local": customLocal }, rules: { "custom-local/enforce-api-routes": "error" } },
];Custom rules (namespace custom)
no-emdash-in-text (rule #1), no-console-use-logger, no-index-files,
no-empty-string-fallback, no-vibe-coded-naming are ON in both presets.
component-props-type ships but is OFF; turn it on per repo:
{ rules: { "custom/component-props-type": "error" } }no-index-files bans barrel files. Whitelist genuine entry points by path suffix:
{ rules: { "custom/no-index-files": ["error", { allow: ["src/mastra/index.ts"] }] } }Filenames
Filenames are enforced kebab-case (user-card.tsx, not UserCard.tsx) via
unicorn/filename-case, the one casing consistent across components, lib, and
Next's own lowercase route files. Next dynamic segments ([postId], [...slug])
are exempted.
Prettier
In package.json:
{ "prettier": "@dylanmerigaud/config/prettier" }The Tailwind class-sorting plugin is bundled and resolved for you.
TypeScript
tsconfig.json:
{
"extends": "@dylanmerigaud/config/tsconfig/next.json",
"compilerOptions": {
"paths": { "@/*": ["./*"] },
"plugins": [{ "name": "next" }]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}The base sets strict, noUncheckedIndexedAccess, noUnusedLocals/Parameters,
ES2022, bundler resolution. You add paths, the Next plugin, and include/exclude.
Version notes
- 0.3.0: warn tier abolished; every enabled rule is an error (third-party recommended warns are promoted at composition).
Publishing (maintainer)
Publishing uses npm Trusted Publishing (OIDC), no NPM_TOKEN secret. One-time
setup on npmjs.com: package settings, Publishing access, add a Trusted Publisher
(GitHub Actions, repo DylanMerigaud/config, workflow release.yml). Then:
npm version patch # bumps package.json + creates the tag
git push --follow-tagsrelease.yml verifies the tag matches package.json, builds, and publishes with
provenance.
