saz-standards 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # @saz/standards
2
+
3
+ > Enterprise React/Next.js coding standards by **Salman Ali Zahid**.
4
+
5
+ One command sets up your entire project with enterprise-grade folder structure, components, configs, and coding rules.
6
+
7
+ ---
8
+
9
+ ## Quick Start
10
+
11
+ ```bash
12
+ npx @saz/standards init
13
+ ```
14
+
15
+ It will ask you:
16
+
17
+ ```
18
+ Framework?
19
+ 1 = React
20
+ 2 = Next.js
21
+
22
+ Language?
23
+ 1 = JavaScript
24
+ 2 = TypeScript
25
+ ```
26
+
27
+ Then it copies everything into your project automatically.
28
+
29
+ ---
30
+
31
+ ## What Gets Copied
32
+
33
+ - Full enterprise folder structure (4 variants)
34
+ - All coding standards markdown files
35
+ - ESLint, Tailwind, and TypeScript base configs
36
+
37
+ ---
38
+
39
+ ## Use the Configs
40
+
41
+ ### ESLint
42
+
43
+ ```js
44
+ // .eslintrc.js
45
+ module.exports = {
46
+ extends: ["./node_modules/@saz/standards/configs/eslint.js"]
47
+ }
48
+ ```
49
+
50
+ ### Tailwind
51
+
52
+ ```js
53
+ // tailwind.config.js
54
+ const sazBase = require("@saz/standards/configs/tailwind");
55
+ module.exports = { presets: [sazBase] }
56
+ ```
57
+
58
+ ### TypeScript
59
+
60
+ ```json
61
+ // tsconfig.json
62
+ {
63
+ "extends": "@saz/standards/configs/tsconfig.json"
64
+ }
65
+ ```
66
+
67
+ ---
68
+
69
+ ## What Is Included
70
+
71
+ ### Standards Files
72
+
73
+ | File | Description |
74
+ | --- | --- |
75
+ | CODING_STANDARDS.md | Enums, naming, exports, imports |
76
+ | DESIGN_SYSTEM.md | Tailwind tokens, typography, dark mode |
77
+ | COMPONENT_PATTERNS.md | Button, Input, Select, Modal, Table |
78
+ | FORM_SYSTEM.md | useForm, Joi, Zod, validation |
79
+ | DATA_FETCHING.md | Axios, thunks, abort controller |
80
+ | STATE_MANAGEMENT.md | Redux Toolkit slices |
81
+ | PERFORMANCE.md | Memoization, virtualization, splits |
82
+ | SECURITY_AND_ACCESSIBILITY.md | ARIA, landmarks, CSP, env rules |
83
+
84
+ ### Project Variants
85
+
86
+ | Variant | Stack |
87
+ | --- | --- |
88
+ | react-js | React + JavaScript + Vite |
89
+ | react-ts | React + TypeScript + Vite |
90
+ | nextjs-js | Next.js App Router + JavaScript |
91
+ | nextjs-ts | Next.js App Router + TypeScript |
92
+
93
+ ---
94
+
95
+ ## Standards Rating
96
+
97
+ This system is rated **10/10** covering:
98
+
99
+ - Component patterns
100
+ - Form validation (Joi + Zod)
101
+ - Redux Toolkit state management
102
+ - Axios service layer with HTTP-only cookie auth
103
+ - Accessibility (ARIA, focus-visible, landmarks)
104
+ - Dark mode strategy
105
+ - List virtualization
106
+ - Cross-browser compatibility
107
+ - Security rules
108
+ - Performance (Core Web Vitals)
109
+
110
+ ---
111
+
112
+ ## Author
113
+
114
+ **Salman Ali Zahid**
115
+
116
+ - GitHub: [MuhammadSalman0151](https://github.com/MuhammadSalman0151)
117
+ - Package: [@saz/standards](https://www.npmjs.com/package/@saz/standards)
118
+
119
+ ---
120
+
121
+ ## License
122
+
123
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const readline = require("readline");
6
+
7
+ const rl = readline.createInterface({
8
+ input: process.stdin,
9
+ output: process.stdout,
10
+ });
11
+
12
+ const ask = (question) =>
13
+ new Promise((resolve) => rl.question(question, resolve));
14
+
15
+ async function main() {
16
+ console.log("");
17
+ console.log("========================================");
18
+ console.log(" Welcome to @saz/standards");
19
+ console.log(" Enterprise React/Next.js Standards");
20
+ console.log(" by Salman Ali Zahid");
21
+ console.log("========================================");
22
+ console.log("");
23
+
24
+ const framework = await ask(
25
+ "Framework?\n 1 = React\n 2 = Next.js\nYour choice: ",
26
+ );
27
+ const language = await ask(
28
+ "\nLanguage?\n 1 = JavaScript\n 2 = TypeScript\nYour choice: ",
29
+ );
30
+
31
+ let variant = "";
32
+
33
+ if (framework === "1" && language === "1") variant = "react-js";
34
+ else if (framework === "1" && language === "2") variant = "react-ts";
35
+ else if (framework === "2" && language === "1") variant = "nextjs-js";
36
+ else if (framework === "2" && language === "2") variant = "nextjs-ts";
37
+ else {
38
+ console.log("\nInvalid choice. Please run again and enter 1 or 2.");
39
+ rl.close();
40
+ return;
41
+ }
42
+
43
+ const dest = process.cwd();
44
+
45
+ // Copy template files
46
+ const templateSrc = path.join(__dirname, "../templates", variant);
47
+ if (fs.existsSync(templateSrc)) {
48
+ fs.cpSync(templateSrc, dest, { recursive: true });
49
+ }
50
+
51
+ // Copy standards markdown files
52
+ const standardsSrc = path.join(__dirname, "../standards");
53
+ const standardsDest = path.join(dest, "standards");
54
+ if (fs.existsSync(standardsSrc)) {
55
+ fs.cpSync(standardsSrc, standardsDest, { recursive: true });
56
+ }
57
+
58
+ console.log("");
59
+ console.log("========================================");
60
+ console.log(" Done! Your project is ready.");
61
+ console.log(" Variant: " + variant);
62
+ console.log(" Standards copied to: /standards");
63
+ console.log("========================================");
64
+ console.log("");
65
+
66
+ rl.close();
67
+ }
68
+
69
+ main();
@@ -0,0 +1,45 @@
1
+ module.exports = {
2
+ env: {
3
+ browser: true,
4
+ es2021: true,
5
+ node: true,
6
+ },
7
+ extends: [
8
+ "eslint:recommended",
9
+ "plugin:react/recommended",
10
+ "plugin:react-hooks/recommended",
11
+ ],
12
+ parserOptions: {
13
+ ecmaVersion: "latest",
14
+ sourceType: "module",
15
+ ecmaFeatures: {
16
+ jsx: true,
17
+ },
18
+ },
19
+ settings: {
20
+ react: {
21
+ version: "detect",
22
+ },
23
+ },
24
+ rules: {
25
+ // Variables
26
+ "no-unused-vars": "error",
27
+ "no-var": "error",
28
+ "prefer-const": "error",
29
+
30
+ // Code quality
31
+ "no-console": "warn",
32
+ "no-debugger": "error",
33
+ eqeqeq: ["error", "always"],
34
+ "no-duplicate-imports": "error",
35
+ "no-empty": "error",
36
+ "no-shadow": "error",
37
+
38
+ // React
39
+ "react/react-in-jsx-scope": "off",
40
+ "react/prop-types": "off",
41
+ "react/self-closing-comp": "warn",
42
+ "react-hooks/rules-of-hooks": "error",
43
+ "react-hooks/exhaustive-deps": "warn",
44
+ },
45
+ };
@@ -0,0 +1,34 @@
1
+ module.exports = {
2
+ content: ["./src/**/*.{js,jsx,ts,tsx}"],
3
+ darkMode: "class",
4
+ theme: {
5
+ extend: {
6
+ colors: {
7
+ "base-primary": "#3b82f6",
8
+ "base-primary-hover": "#2563eb",
9
+ "base-danger": "#ef4444",
10
+ "base-danger-hover": "#dc2626",
11
+ "base-success": "#22c55e",
12
+ "base-warning": "#f59e0b",
13
+ "base-info": "#3b82f6",
14
+ "base-surface": "#ffffff",
15
+ "base-surface-hover": "#f9fafb",
16
+ "base-border": "#e5e7eb",
17
+ "base-input": "#111827",
18
+ "base-placeholder": "#9ca3af",
19
+ "base-muted": "#6b7280",
20
+ "base-heading": "#111827",
21
+ "base-label": "#374151",
22
+ },
23
+ borderRadius: {
24
+ "base-radius-md": "0.375rem",
25
+ "base-radius-lg": "0.5rem",
26
+ },
27
+ boxShadow: {
28
+ "base-shadow-md": "0 4px 6px -1px rgb(0 0 0 / 0.1)",
29
+ "base-shadow-lg": "0 10px 15px -3px rgb(0 0 0 / 0.1)",
30
+ },
31
+ },
32
+ },
33
+ plugins: [],
34
+ };
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "strict": true,
4
+ "jsx": "react-jsx",
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "resolveJsonModule": true,
11
+ "isolatedModules": true,
12
+ "noEmit": true
13
+ },
14
+ "include": ["src"],
15
+ "exclude": ["node_modules"]
16
+ }
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "saz-standards",
3
+ "version": "1.0.0",
4
+ "description": "Enterprise React/Next.js coding standards — ESLint, Tailwind, TypeScript configs + CLI by Salman Ali Zahid",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "saz": "./bin/cli.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "configs",
12
+ "templates",
13
+ "standards"
14
+ ],
15
+ "scripts": {
16
+ "test": "echo \"No tests yet\""
17
+ },
18
+ "keywords": [
19
+ "react",
20
+ "nextjs",
21
+ "eslint",
22
+ "tailwind",
23
+ "typescript",
24
+ "coding-standards",
25
+ "enterprise",
26
+ "boilerplate",
27
+ "starter"
28
+ ],
29
+ "author": "Salman Ali Zahid",
30
+ "license": "MIT",
31
+ "type": "commonjs"
32
+ }
@@ -0,0 +1,272 @@
1
+ # Coding Standards
2
+
3
+ > Universal coding rules applied to every project variant.
4
+
5
+ ---
6
+
7
+ ## Enum Rules
8
+
9
+ - All enum keys must be `SCREAMING_SNAKE_CASE` (uppercase with underscores)
10
+ - All enum values must be uppercase strings — never lowercase, never mixed case
11
+ - Enums must be defined in `shared/constants/` or inside the module's `types/` folder when scoped to a single module
12
+ - Never use numeric enums — always use string enums for readability and serialization safety
13
+ - Never use inline object literals as a substitute for enums when the value set is fixed
14
+ - In TypeScript projects, always use `const enum` or a plain `enum` with explicit string values — never rely on auto-incremented numeric values
15
+ - Enum names must be PascalCase (e.g., `UserRole`, `OrderStatus`, `PaymentMethod`)
16
+ - All enum members must be used — do not declare unused enum values
17
+ - Never mutate or reassign enum values at runtime
18
+
19
+ ### TypeScript Example
20
+
21
+ ```ts
22
+ enum UserRole {
23
+ SUPER_ADMIN = "SUPER_ADMIN",
24
+ ADMIN = "ADMIN",
25
+ MANAGER = "MANAGER",
26
+ STAFF = "STAFF",
27
+ GUEST = "GUEST",
28
+ }
29
+
30
+ enum OrderStatus {
31
+ PENDING = "PENDING",
32
+ CONFIRMED = "CONFIRMED",
33
+ IN_PROGRESS = "IN_PROGRESS",
34
+ COMPLETED = "COMPLETED",
35
+ CANCELLED = "CANCELLED",
36
+ }
37
+ ```
38
+
39
+ ### JavaScript Example
40
+
41
+ ```js
42
+ const UserRole = Object.freeze({
43
+ SUPER_ADMIN: "SUPER_ADMIN",
44
+ ADMIN: "ADMIN",
45
+ MANAGER: "MANAGER",
46
+ STAFF: "STAFF",
47
+ GUEST: "GUEST",
48
+ });
49
+
50
+ const OrderStatus = Object.freeze({
51
+ PENDING: "PENDING",
52
+ CONFIRMED: "CONFIRMED",
53
+ IN_PROGRESS: "IN_PROGRESS",
54
+ COMPLETED: "COMPLETED",
55
+ CANCELLED: "CANCELLED",
56
+ });
57
+ ```
58
+
59
+ ---
60
+
61
+ ## ESLint and Code Quality Rules
62
+
63
+ - No unused variables, imports, or functions
64
+ - No `console` statements in production code
65
+ - No `debugger` statements
66
+ - Avoid shadowed variables
67
+ - Prefer `const` over `let` when values do not change
68
+ - Avoid `var` entirely
69
+ - Use strict equality (`===` and `!==`)
70
+ - No empty functions or empty blocks
71
+ - No duplicate code
72
+ - Keep functions small and focused
73
+ - Use early returns for clarity
74
+ - Avoid side effects in render logic
75
+ - No mutation of props or external state
76
+ - Follow consistent formatting and naming conventions
77
+ - Ensure all dependencies are correctly specified in React hook dependency arrays
78
+ - Do not disable ESLint rules unless absolutely necessary
79
+
80
+ ---
81
+
82
+ ## File Naming Rules
83
+
84
+ | Type | Convention | Example |
85
+ | --- | --- | --- |
86
+ | Components | PascalCase | `UserCard.tsx` |
87
+ | Hooks | useCamelCase | `useForm.ts` |
88
+ | Utilities | camelCase | `formatDate.ts` |
89
+ | Types (TS) | PascalCase | `User.types.ts` |
90
+ | Enums | PascalCase name, SCREAMING_SNAKE_CASE keys/values | `UserRole` |
91
+
92
+ ---
93
+
94
+ ## Export Rules
95
+
96
+ - Components: `default export` allowed
97
+ - Utilities, hooks, and constants: named exports preferred
98
+ - Enums: named exports only
99
+
100
+ ---
101
+
102
+ ## Barrel Export Rules
103
+
104
+ Apply barrel exports in any component folder containing more than 3 files.
105
+
106
+ ```js
107
+ // components/buttons/index.js
108
+ export { default as CloseButton } from "./CloseButton";
109
+ export { default as FormSubmitButton } from "./FormSubmitButton";
110
+ export { default as IconButton } from "./IconButton";
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Import Pattern
116
+
117
+ Use relative imports only. Use root index exports when importing multiple components from the same folder.
118
+
119
+ ```js
120
+ import { CloseButton, FormSubmitButton } from "../../../components/buttons";
121
+ import { Inputfield, SelectFromObject } from "../../../components/form";
122
+ import { cn } from "../../utils/cn";
123
+ ```
124
+
125
+ Next.js imports when needed:
126
+
127
+ ```js
128
+ import Image from "next/image";
129
+ import Link from "next/link";
130
+ import { useRouter } from "next/navigation";
131
+ import dynamic from "next/dynamic";
132
+ import { Metadata } from "next";
133
+ ```
134
+
135
+ ---
136
+
137
+ ## General Component Rules
138
+
139
+ - Default export function component
140
+ - Props destructured in parameters with safe default values
141
+ - No PropTypes
142
+ - No `React.FC`
143
+ - No class components
144
+ - No unnecessary fragments or wrappers
145
+ - No inline styles
146
+ - Explicit conditional rendering only: `condition ? <Component /> : null`
147
+
148
+ ---
149
+
150
+ ## Runtime and Prop Safety Rules
151
+
152
+ - Validate critical data before use
153
+ - Check for `null` or `undefined` before property access
154
+ - Use optional chaining for nested values: `data?.map(...)`
155
+ - Provide safe default values for all optional props
156
+ - Ensure values are arrays before mapping
157
+ - Provide fallback UI when arrays are empty
158
+ - Do not assume API response structure — handle missing or malformed data gracefully
159
+
160
+ ---
161
+
162
+ ## List Rendering Rules
163
+
164
+ - Always use optional chaining before map: `data?.map(...)`
165
+ - Key must be dynamic and stable when available: `key={item._id || item.id || item.value}`
166
+ - Use index as key only when required by UI conditions or when no stable key exists: `key={index}`
167
+ - Do not use random values as keys
168
+ - Do not omit keys
169
+
170
+ ---
171
+
172
+ ## UI State Rules
173
+
174
+ - Always handle the loading state when async data is used
175
+ - Provide fallback UI for empty data
176
+ - Display error state when operations fail
177
+ - Do not render undefined data
178
+
179
+ ---
180
+
181
+ ## Event Handler Types (TypeScript)
182
+
183
+ ```ts
184
+ React.ChangeEvent<HTMLInputElement>
185
+ React.FormEvent<HTMLFormElement>
186
+ React.MouseEvent<HTMLButtonElement>
187
+ ```
188
+
189
+ ---
190
+
191
+ ## TypeScript Rules
192
+
193
+ > Applied only when TypeScript is selected (Q4 = B).
194
+
195
+ - Strict typing required
196
+ - Do NOT use `any`
197
+ - Do NOT use `unknown` as a shortcut
198
+ - Use proper interfaces or types for all props, state, API responses, and Redux data
199
+ - Prefer explicit types over inference when unclear
200
+ - Use union types when appropriate
201
+ - Use generics when needed
202
+ - All component props must be typed
203
+ - Event handlers must use correct React types
204
+ - Nullable values must be typed explicitly
205
+ - Avoid the non-null assertion operator (`!`) unless the value is guaranteed to be non-null
206
+
207
+ ---
208
+
209
+ ## Environment Rules
210
+
211
+ - Access environment variables safely
212
+ - Do NOT hardcode secrets or sensitive URLs
213
+ - In Next.js, prefix only public variables with `NEXT_PUBLIC_`
214
+ - In Vite, prefix only public variables with `VITE_`
215
+ - Never expose server-only secrets to the client bundle
216
+ - Every project must include a `.env.example` file at the root listing all required variable names with placeholder values — never commit `.env` or `.env.local`
217
+
218
+ ```sh
219
+ # .env.example
220
+ VITE_API_BASE_URL=https://api.example.com # React/Vite
221
+ NEXT_PUBLIC_API_BASE_URL=https://api.example.com # Next.js
222
+ ```
223
+
224
+ - `.env` and `.env.local` must be listed in `.gitignore`
225
+ - New developers must copy `.env.example` to `.env` (Vite) or `.env.local` (Next.js) and fill in real values
226
+
227
+ ---
228
+
229
+ ## Styling Constraints
230
+
231
+ - Tailwind only
232
+ - Use project design tokens
233
+ - No CSS modules
234
+ - No styled-components
235
+ - No inline styles
236
+
237
+ ---
238
+
239
+ ## cn() Utility
240
+
241
+ All projects must include a `cn` utility at `src/utils/cn.ts` (TypeScript) or `src/utils/cn.js` (JavaScript). This is the canonical implementation — do not alter it:
242
+
243
+ **TypeScript (`src/utils/cn.ts`):**
244
+
245
+ ```ts
246
+ import { clsx, type ClassValue } from "clsx";
247
+ import { twMerge } from "tailwind-merge";
248
+
249
+ export function cn(...inputs: ClassValue[]): string {
250
+ return twMerge(clsx(inputs));
251
+ }
252
+ ```
253
+
254
+ **JavaScript (`src/utils/cn.js`):**
255
+
256
+ ```js
257
+ import { clsx } from "clsx";
258
+ import { twMerge } from "tailwind-merge";
259
+
260
+ export function cn(...inputs) {
261
+ return twMerge(clsx(inputs));
262
+ }
263
+ ```
264
+
265
+ Usage pattern (from `DESIGN_SYSTEM.md`):
266
+
267
+ ```tsx
268
+ className={cn("base classes", condition && "conditional class", className)}
269
+ ```
270
+
271
+ - Always import `cn` from `../utils/cn` (relative path)
272
+ - Never replicate this logic inline — always import from the utility file