Skip to content

Commit 87796c7

Browse files
warnigomtakhirov
andauthored
Environment Generator Script (#3)
* chore: added switch env script * fix: fixed script config in packages.json * fix: fix script and fix comments * chore: added npmrc and fix package chalk * chore: configure eslint settings * chore: format code with prettier --------- Co-authored-by: Muhammaddiyor Tohirov <mtohirov60@gmail.com>
1 parent 43532e4 commit 87796c7

9 files changed

+182
-36
lines changed

.npmrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Allows installing dependencies with version ranges (e.g., ^1.0.0)
2+
// instead of exact versions, enabling minor and patch updates.
3+
save-exact=false

.prettierrc

-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,5 @@
1616
"arrowParens": "avoid",
1717
"endOfLine": "crlf",
1818

19-
"parser": "typescript",
2019
"plugins": ["prettier-plugin-tailwindcss"]
2120
}

eslint.config.mjs

+24-22
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,46 @@
1-
import { fixupConfigRules, fixupPluginRules } from '@eslint/compat';
2-
import { FlatCompat } from '@eslint/eslintrc';
3-
import js from '@eslint/js';
4-
import globals from 'globals';
5-
import path from 'node:path';
6-
import { fileURLToPath } from 'node:url';
1+
import { fixupConfigRules, fixupPluginRules } from '@eslint/compat'
2+
import { FlatCompat } from '@eslint/eslintrc'
3+
import js from '@eslint/js'
4+
import globals from 'globals'
5+
import path from 'node:path'
6+
import { fileURLToPath } from 'node:url'
77

88
// Config/Plugins
9-
import typescriptEslint from '@typescript-eslint/eslint-plugin';
10-
import tsParser from '@typescript-eslint/parser';
11-
import react from 'eslint-plugin-react';
12-
import tailwindcss from 'eslint-plugin-tailwindcss';
9+
import typescriptEslint from '@typescript-eslint/eslint-plugin'
10+
import tsParser from '@typescript-eslint/parser'
11+
import reactHooks from 'eslint-plugin-react-hooks'
12+
import tailwindcss from 'eslint-plugin-tailwindcss'
1313

14-
const __filename = fileURLToPath(import.meta.url);
15-
const __dirname = path.dirname(__filename);
14+
const __filename = fileURLToPath(import.meta.url)
15+
const __dirname = path.dirname(__filename)
1616
const compat = new FlatCompat({
1717
baseDirectory: __dirname,
1818
recommendedConfig: js.configs.recommended,
1919
allConfig: js.configs.all,
20-
});
20+
})
2121

2222
const twOptions = {
2323
callees: ['clsx', 'cva', 'cn'],
2424
classRegex: '^class(Name)?$',
25-
};
25+
}
2626

27-
export default [
27+
const config = [
2828
...fixupConfigRules(
2929
compat.extends(
3030
'eslint:recommended',
31-
'plugin:@typescript-eslint/recommended',
32-
'plugin:react/recommended',
33-
'plugin:react-hooks/recommended',
31+
'next',
32+
'next/typescript',
33+
'next/core-web-vitals',
3434
'plugin:jsx-a11y/recommended',
35-
'plugin:@next/next/recommended',
3635
'plugin:tailwindcss/recommended',
3736
'prettier',
3837
),
3938
),
4039
{
4140
plugins: {
42-
react: fixupPluginRules(react),
41+
'react-hooks': fixupPluginRules(reactHooks),
4342
'@typescript-eslint': fixupPluginRules(typescriptEslint),
44-
tailwindcss: fixupPluginRules(tailwindcss),
43+
'tailwindcss': fixupPluginRules(tailwindcss),
4544
},
4645

4746
languageOptions: {
@@ -77,6 +76,8 @@ export default [
7776
{
7877
argsIgnorePattern: '^_',
7978
varsIgnorePattern: '^_',
79+
caughtErrorsIgnorePattern: '^_',
80+
destructuredArrayIgnorePattern: '^_',
8081
},
8182
],
8283

@@ -89,5 +90,6 @@ export default [
8990
'tailwindcss/no-unnecessary-arbitrary-value': ['error', twOptions],
9091
},
9192
},
92-
];
93+
]
9394

95+
export default config

package.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
"name": "fin",
33
"version": "1.0.0",
44
"private": true,
5+
"type": "module",
56
"description": "helps users track their expenses, manage budgets and receive financial insights directly via Telegram.",
67
"scripts": {
78
"dev": "next dev",
89
"build": "next build",
910
"start": "next start",
10-
"lint": "next lint"
11+
"lint": "next lint",
12+
"prepare": "npm run generate:env",
13+
"generate:env": "node scripts/generate_env.mjs"
1114
},
1215
"keywords": [
1316
"finance",
@@ -37,8 +40,10 @@
3740
"@typescript-eslint/eslint-plugin": "^8.10.0",
3841
"@typescript-eslint/parser": "^8.10.0",
3942
"autoprefixer": "^10.4.20",
43+
"chalk": "^5.3.0",
4044
"clsx": "^2.1.1",
4145
"eslint": "^9.12.0",
46+
"eslint-config-next": "^15.0.1",
4247
"eslint-config-prettier": "^9.1.0",
4348
"eslint-plugin-jsx-a11y": "^6.10.0",
4449
"eslint-plugin-react": "^7.37.1",

pnpm-lock.yaml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/generate_env.mjs

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* @fileoverview Environment File Generator
3+
*
4+
* This script generates environment configuration files for development and production
5+
* environments based on a template (.env.example). It performs the following tasks:
6+
*
7+
* 1. Copies the .env.example file to create .env.development and .env.production.
8+
* 2. Updates the content of these files with environment-specific configurations.
9+
* 3. Ensures proper file permissions and handles potential errors.
10+
*
11+
* Usage: Run this script from the project root directory.
12+
*
13+
* # Types:
14+
* ---
15+
* Configuration for environment files:
16+
* @typedef {Object} EnvFileConfig
17+
* @property {string} path - The file path.
18+
* @property {string} content - The file content.
19+
*/
20+
21+
import fs from 'node:fs/promises'
22+
import path from 'node:path'
23+
24+
import chalk from 'chalk'
25+
26+
const ROOT = process.cwd()
27+
const ENV_SOURCE = path.resolve(ROOT, '.env.example')
28+
29+
/** @type {Record<string, EnvFileConfig>} */
30+
const ENV_FILES = {
31+
development: {
32+
path: path.join(ROOT, '.env.development'),
33+
content: `
34+
# Set the Node.js environment (production: for live deployment, development: for local development)
35+
NODE_ENV=development
36+
37+
# Enable or disable bundle analysis (true/false)
38+
ANALYZE=false
39+
40+
# Open bundle analyzer automatically after build (true/false)
41+
OPEN_ANALYZER=false
42+
43+
# Set the mode for bundle analyzer output (static: HTML file, json: JSON file)
44+
ANALYZER_MODE=static
45+
`.trim(),
46+
},
47+
production: {
48+
path: path.join(ROOT, '.env.production'),
49+
content: `
50+
# Set the Node.js environment (production: for live deployment, development: for local development)
51+
NODE_ENV=production
52+
53+
# Enable or disable bundle analysis (true/false)
54+
ANALYZE=false
55+
56+
# Open bundle analyzer automatically after build (true/false)
57+
OPEN_ANALYZER=false
58+
59+
# Set the mode for bundle analyzer output (static: HTML file, json: JSON file)
60+
ANALYZER_MODE=static
61+
`.trim(),
62+
},
63+
}
64+
65+
/**
66+
* Copies the source file to the destination and updates its content.
67+
*
68+
* @param {string} destination - The path of the destination file.
69+
* @param {string} content - The content to write to the file.
70+
* @returns {Promise<void>}
71+
*/
72+
async function copyFile(destination, content) {
73+
const prompt = chalk.bgBlue('[COPY]')
74+
75+
try {
76+
await fs.copyFile(ENV_SOURCE, destination)
77+
console.info(prompt, chalk.blue(`${destination} created`))
78+
79+
await fs.writeFile(destination, content)
80+
console.info(prompt, chalk.blue(`${destination} updated`))
81+
} catch (error) {
82+
console.error(chalk.red(`Error copying file to ${destination}`), error)
83+
}
84+
}
85+
86+
/**
87+
* Checks if the source file is accessible for reading and writing.
88+
*
89+
* @param {string} source - The path of the source file.
90+
* @throws {Error} If the file is not accessible.
91+
*/
92+
async function checkSourceFileAccess(source) {
93+
try {
94+
await fs.access(source, fs.constants.R_OK)
95+
} catch (_error) {
96+
throw new Error("You don't have permission to read the .env.example file")
97+
}
98+
}
99+
100+
/**
101+
* Main function to generate environment files.
102+
*/
103+
async function main() {
104+
try {
105+
await checkSourceFileAccess(ENV_SOURCE)
106+
107+
const promises = Object.values(ENV_FILES).map(({ path, content }) => {
108+
return copyFile(path, content)
109+
})
110+
await Promise.all(promises)
111+
112+
console.info(
113+
chalk.green('All environment files have been generated successfully.'),
114+
)
115+
} catch (error) {
116+
console.error(chalk.red('An error occurred:'), error.message)
117+
console.warn(chalk.yellow('Please check your file permissions.'))
118+
process.exit(-1)
119+
}
120+
}
121+
122+
main().catch(error => {
123+
console.error(chalk.red('An unexpected error occurred:'), error)
124+
process.exit(-1)
125+
})

src/utils/cn.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import type { ClassValue } from 'clsx';
1+
import type { ClassValue } from 'clsx'
22

3-
import { clsx } from 'clsx';
4-
import { twMerge } from 'tailwind-merge';
3+
import clsx from 'clsx'
4+
import { twMerge } from 'tailwind-merge'
55

6-
export function cn(...classNames: ClassValue[]) {
7-
return twMerge(clsx(classNames));
6+
export function cn(...classNames: ClassValue[]): string {
7+
return twMerge(clsx(classNames))
88
}
99

10-
export default cn;
10+
export default cn

src/utils/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { cn } from '#utils/cn';
1+
export { cn } from '#utils/cn'

tailwind.config.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import type { Config } from 'tailwindcss';
1+
import type { Config } from 'tailwindcss'
22

3-
import colors from 'tailwindcss/colors';
4-
import { fontFamily } from 'tailwindcss/defaultTheme';
3+
import colors from 'tailwindcss/colors'
4+
import { fontFamily } from 'tailwindcss/defaultTheme'
55

6-
export default {
6+
const config: Config = {
77
content: [
88
'src/app/**/*.{ts,tsx}',
99
'src/components/**/*.{ts,tsx}',
1010
'src/layouts/**/*.{ts,tsx}',
1111
'src/widgets/**/*.{ts,tsx}',
1212
],
13+
1314
theme: {
1415
colors: {
1516
inherit: colors.inherit,
@@ -32,5 +33,8 @@ export default {
3233
},
3334
},
3435
},
36+
3537
plugins: [],
36-
} satisfies Config;
38+
}
39+
40+
export default config

0 commit comments

Comments
 (0)