Refactor ESLint configuration and update TypeScript dependencies for improved type safety
- Enhanced ESLint configuration to better support TypeScript file patterns and added centralized dependency versions using pnpm catalogs. - Updated TypeScript configurations across applications to utilize new file structure and improved type inference with Zod. - Refactored domain modules to replace deprecated type inference methods, ensuring better type safety and consistency. - Cleaned up package.json files to standardize dependency versions and improve overall project maintainability.
This commit is contained in:
parent
ece89de49a
commit
3f7fa02b83
@ -53,7 +53,7 @@
|
||||
"rxjs": "^7.8.2",
|
||||
"salesforce-pubsub-api-client": "^5.5.1",
|
||||
"ssh2-sftp-client": "^12.0.1",
|
||||
"zod": "4.1.13"
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^11.0.14",
|
||||
@ -65,6 +65,6 @@
|
||||
"@types/ssh2-sftp-client": "^9.0.6",
|
||||
"pino-pretty": "^13.1.3",
|
||||
"tsc-alias": "^1.8.16",
|
||||
"typescript": "5.9.3"
|
||||
"typescript": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"extends": "../../tsconfig.node.json",
|
||||
"compilerOptions": {
|
||||
"verbatimModuleSyntax": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
"react-dom": "19.2.1",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"world-countries": "^5.1.0",
|
||||
"zod": "4.1.13",
|
||||
"zod": "catalog:",
|
||||
"zustand": "^5.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -39,6 +39,6 @@
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"typescript": "5.9.3"
|
||||
"typescript": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-env node */
|
||||
/* global console, process */
|
||||
|
||||
/**
|
||||
* Bundle size monitoring script
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
import { mkdirSync, existsSync, writeFileSync, rmSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { URL } from "node:url";
|
||||
/* global console */
|
||||
|
||||
const root = new URL("..", import.meta.url).pathname; // apps/portal
|
||||
const nextDir = join(root, ".next");
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-env node */
|
||||
/* global __dirname, console, process */
|
||||
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
@ -1,12 +1,6 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"extends": "../../tsconfig.next.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"jsx": "preserve",
|
||||
"noEmit": true,
|
||||
"plugins": [{ "name": "next" }],
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": ".typecheck/tsconfig.tsbuildinfo",
|
||||
|
||||
@ -4,12 +4,24 @@ import process from "node:process";
|
||||
import js from "@eslint/js";
|
||||
import nextPlugin from "@next/eslint-plugin-next";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
import tseslint from "typescript-eslint";
|
||||
import prettier from "eslint-plugin-prettier";
|
||||
import globals from "globals";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
const TS_FILES = ["**/*.{ts,tsx}"];
|
||||
const BFF_TS_FILES = ["apps/bff/**/*.ts"];
|
||||
const PACKAGES_TS_FILES = ["packages/**/*.ts"];
|
||||
const PORTAL_FILES = ["apps/portal/**/*.{js,jsx,ts,tsx}"];
|
||||
|
||||
const withFiles = (configs, files) =>
|
||||
configs.map(config => ({
|
||||
...config,
|
||||
files,
|
||||
}));
|
||||
|
||||
export default [
|
||||
// =============================================================================
|
||||
// Global ignores
|
||||
// =============================================================================
|
||||
{
|
||||
ignores: [
|
||||
"**/node_modules/**",
|
||||
@ -26,30 +38,22 @@ export default [
|
||||
],
|
||||
},
|
||||
|
||||
// Base JS recommendations
|
||||
// =============================================================================
|
||||
// Base JS
|
||||
// =============================================================================
|
||||
js.configs.recommended,
|
||||
|
||||
// Prettier integration
|
||||
{
|
||||
plugins: { prettier },
|
||||
rules: { "prettier/prettier": "warn" },
|
||||
},
|
||||
// =============================================================================
|
||||
// TypeScript (fast rules, no type information)
|
||||
// =============================================================================
|
||||
...withFiles(tseslint.configs.recommended, TS_FILES),
|
||||
|
||||
// TypeScript recommended rules (fast, no type info)
|
||||
...tseslint.configs.recommended.map((config) => ({
|
||||
// =============================================================================
|
||||
// TypeScript (type-aware rules) — only where we want the cost
|
||||
// =============================================================================
|
||||
...tseslint.configs.recommendedTypeChecked.map(config => ({
|
||||
...config,
|
||||
files: ["**/*.{ts,tsx}"],
|
||||
languageOptions: {
|
||||
...(config.languageOptions || {}),
|
||||
// Keep config simple: allow both environments; app-specific blocks can tighten later
|
||||
globals: { ...globals.browser, ...globals.node },
|
||||
},
|
||||
})),
|
||||
|
||||
// TypeScript type-aware rules only where we really want them (backend + shared packages)
|
||||
...tseslint.configs.recommendedTypeChecked.map((config) => ({
|
||||
...config,
|
||||
files: ["apps/bff/**/*.ts", "packages/**/*.ts"],
|
||||
files: [...BFF_TS_FILES, ...PACKAGES_TS_FILES],
|
||||
languageOptions: {
|
||||
...(config.languageOptions || {}),
|
||||
parserOptions: {
|
||||
@ -57,13 +61,14 @@ export default [
|
||||
projectService: true,
|
||||
tsconfigRootDir: process.cwd(),
|
||||
},
|
||||
globals: { ...globals.node },
|
||||
},
|
||||
})),
|
||||
|
||||
// Backend & domain packages
|
||||
// =============================================================================
|
||||
// Backend + domain packages: sensible defaults
|
||||
// =============================================================================
|
||||
{
|
||||
files: ["apps/bff/**/*.ts", "packages/domain/**/*.ts"],
|
||||
files: [...BFF_TS_FILES, "packages/domain/**/*.ts"],
|
||||
rules: {
|
||||
"@typescript-eslint/consistent-type-imports": "error",
|
||||
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
|
||||
@ -71,9 +76,11 @@ export default [
|
||||
},
|
||||
},
|
||||
|
||||
// Strict rules for shared packages
|
||||
// =============================================================================
|
||||
// Shared packages: stricter safety
|
||||
// =============================================================================
|
||||
{
|
||||
files: ["packages/**/*.ts"],
|
||||
files: PACKAGES_TS_FILES,
|
||||
rules: {
|
||||
"@typescript-eslint/no-redundant-type-constituents": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
@ -83,13 +90,14 @@ export default [
|
||||
},
|
||||
},
|
||||
|
||||
// Portal (Next.js) rules (flat-config friendly)
|
||||
// =============================================================================
|
||||
// Portal (Next.js)
|
||||
// =============================================================================
|
||||
{
|
||||
...nextPlugin.configs["core-web-vitals"],
|
||||
files: ["apps/portal/**/*.{js,jsx,ts,tsx}"],
|
||||
files: PORTAL_FILES,
|
||||
},
|
||||
{
|
||||
// Keep this minimal (defaults-first): only the two classic hook rules.
|
||||
files: ["apps/portal/**/*.{jsx,tsx}"],
|
||||
plugins: { "react-hooks": reactHooks },
|
||||
rules: {
|
||||
@ -97,23 +105,23 @@ export default [
|
||||
"react-hooks/exhaustive-deps": "warn",
|
||||
},
|
||||
},
|
||||
|
||||
// Portal overrides
|
||||
{
|
||||
files: ["apps/portal/**/*.{ts,tsx}"],
|
||||
languageOptions: {
|
||||
globals: { ...globals.browser, ...globals.node },
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
"@next/next/no-html-link-for-pages": "off",
|
||||
},
|
||||
},
|
||||
|
||||
// Prevent hard navigation in authenticated pages
|
||||
// =============================================================================
|
||||
// Portal navigation guardrails
|
||||
// =============================================================================
|
||||
{
|
||||
files: ["apps/portal/src/app/(authenticated)/**/*.{ts,tsx}"],
|
||||
rules: {
|
||||
@ -126,8 +134,6 @@ export default [
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// Exceptions for specific files
|
||||
{
|
||||
files: ["apps/portal/src/app/(authenticated)/layout.tsx"],
|
||||
rules: { "no-restricted-imports": "off" },
|
||||
@ -137,7 +143,9 @@ export default [
|
||||
rules: { "no-restricted-syntax": "off" },
|
||||
},
|
||||
|
||||
// Enforce domain imports architecture
|
||||
// =============================================================================
|
||||
// Architecture: import boundaries
|
||||
// =============================================================================
|
||||
{
|
||||
files: ["apps/portal/src/**/*.{ts,tsx}", "apps/bff/src/**/*.ts"],
|
||||
rules: {
|
||||
@ -155,9 +163,11 @@ export default [
|
||||
},
|
||||
},
|
||||
|
||||
// BFF strict type safety
|
||||
// =============================================================================
|
||||
// BFF: stricter type safety (type-aware)
|
||||
// =============================================================================
|
||||
{
|
||||
files: ["apps/bff/**/*.ts"],
|
||||
files: BFF_TS_FILES,
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-unsafe-assignment": "error",
|
||||
@ -170,13 +180,16 @@ export default [
|
||||
},
|
||||
},
|
||||
|
||||
// Node globals for config files
|
||||
// =============================================================================
|
||||
// Node globals for tooling/config files
|
||||
// =============================================================================
|
||||
{
|
||||
files: [
|
||||
"*.config.*",
|
||||
"apps/portal/next.config.mjs",
|
||||
"config/**/*.{js,cjs,mjs}",
|
||||
"scripts/**/*.{js,cjs,mjs}",
|
||||
"apps/**/scripts/**/*.{js,cjs,mjs}",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: { ...globals.node },
|
||||
|
||||
10
package.json
10
package.json
@ -53,24 +53,20 @@
|
||||
"devDependencies": {
|
||||
"@next/eslint-plugin-next": "16.0.9",
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@types/node": "^24.10.3",
|
||||
"@types/node": "catalog:",
|
||||
"eslint": "^9.39.1",
|
||||
"lint-staged": "^16.2.7",
|
||||
"eslint-plugin-prettier": "^5.5.4",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"globals": "^16.5.0",
|
||||
"husky": "^9.1.7",
|
||||
"prettier": "^3.7.4",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript": "catalog:",
|
||||
"typescript-eslint": "^8.49.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"js-yaml": ">=4.1.1",
|
||||
"typescript": "5.9.3",
|
||||
"@types/node": "24.10.3",
|
||||
"zod": "4.1.13"
|
||||
"js-yaml": ">=4.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { infer as ZodInfer } from "zod";
|
||||
import type { z } from "zod";
|
||||
import type {
|
||||
activityTypeSchema,
|
||||
activitySchema,
|
||||
@ -11,12 +11,12 @@ import type {
|
||||
dashboardSummaryResponseSchema,
|
||||
} from "./schema.js";
|
||||
|
||||
export type ActivityType = ZodInfer<typeof activityTypeSchema>;
|
||||
export type Activity = ZodInfer<typeof activitySchema>;
|
||||
export type DashboardStats = ZodInfer<typeof dashboardStatsSchema>;
|
||||
export type NextInvoice = ZodInfer<typeof nextInvoiceSchema>;
|
||||
export type DashboardSummary = ZodInfer<typeof dashboardSummarySchema>;
|
||||
export type DashboardError = ZodInfer<typeof dashboardErrorSchema>;
|
||||
export type ActivityFilter = ZodInfer<typeof activityFilterSchema>;
|
||||
export type ActivityFilterConfig = ZodInfer<typeof activityFilterConfigSchema>;
|
||||
export type DashboardSummaryResponse = ZodInfer<typeof dashboardSummaryResponseSchema>;
|
||||
export type ActivityType = z.infer<typeof activityTypeSchema>;
|
||||
export type Activity = z.infer<typeof activitySchema>;
|
||||
export type DashboardStats = z.infer<typeof dashboardStatsSchema>;
|
||||
export type NextInvoice = z.infer<typeof nextInvoiceSchema>;
|
||||
export type DashboardSummary = z.infer<typeof dashboardSummarySchema>;
|
||||
export type DashboardError = z.infer<typeof dashboardErrorSchema>;
|
||||
export type ActivityFilter = z.infer<typeof activityFilterSchema>;
|
||||
export type ActivityFilterConfig = z.infer<typeof activityFilterConfigSchema>;
|
||||
export type DashboardSummaryResponse = z.infer<typeof dashboardSummaryResponseSchema>;
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* These rules represent domain logic and should be reusable across frontend/backend.
|
||||
*/
|
||||
|
||||
import type { infer as ZodInfer } from "zod";
|
||||
import type { z } from "zod";
|
||||
import { orderBusinessValidationSchema } from "./schema.js";
|
||||
|
||||
// ============================================================================
|
||||
@ -101,7 +101,7 @@ export const orderWithSkuValidationSchema = orderBusinessValidationSchema
|
||||
path: ["skus"],
|
||||
});
|
||||
|
||||
export type OrderWithSkuValidation = ZodInfer<typeof orderWithSkuValidationSchema>;
|
||||
export type OrderWithSkuValidation = z.infer<typeof orderWithSkuValidationSchema>;
|
||||
|
||||
// ============================================================================
|
||||
// Validation Error Messages
|
||||
|
||||
@ -133,10 +133,10 @@
|
||||
"typecheck": "pnpm run type-check"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "4.1.13"
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "5.9.3",
|
||||
"zod": "4.1.13"
|
||||
"typescript": "catalog:",
|
||||
"zod": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"extends": "../../tsconfig.node.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"declaration": true,
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
packages:
|
||||
- apps/*
|
||||
- packages/*
|
||||
|
||||
# Centralized dependency versions (pnpm Catalogs)
|
||||
catalog:
|
||||
zod: "4.1.13"
|
||||
typescript: "5.9.3"
|
||||
"@types/node": "24.10.3"
|
||||
|
||||
@ -65,6 +65,31 @@ if (hasDrift) {
|
||||
}
|
||||
"
|
||||
|
||||
# 2b. Ensure a single installed Zod version (lockfile-level)
|
||||
echo "🧩 Checking for multiple installed Zod versions..."
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const lock = fs.readFileSync('pnpm-lock.yaml', 'utf8');
|
||||
const versions = new Set();
|
||||
const re = /\\n\\s{2}zod@([^:\\s]+):/g;
|
||||
let m;
|
||||
while ((m = re.exec(lock)) !== null) versions.add(m[1]);
|
||||
|
||||
if (versions.size === 0) {
|
||||
console.log('⚠️ No zod entries found in lockfile (unexpected).');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (versions.size > 1) {
|
||||
console.log('❌ Multiple zod versions installed:');
|
||||
[...versions].sort().forEach(v => console.log(' - zod@' + v));
|
||||
console.log('\\n💡 Fix by aligning dependencies or adding a pnpm override for zod.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('✅ Single zod version installed:', 'zod@' + [...versions][0]);
|
||||
"
|
||||
|
||||
# 3. Security audit
|
||||
echo "🔒 Running security audit..."
|
||||
if pnpm audit --audit-level moderate; then
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"target": "ES2024",
|
||||
"lib": ["ES2024"],
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
12
tsconfig.next.json
Normal file
12
tsconfig.next.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"jsx": "preserve",
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
10
tsconfig.node.json
Normal file
10
tsconfig.node.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2024",
|
||||
"lib": ["ES2024"],
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext"
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user