create-alistt69-kit 0.3.6 → 0.3.7
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/LICENSE +20 -20
- package/README.md +189 -189
- package/bin/index.js +24 -24
- package/package.json +44 -44
- package/src/core/apply-features.js +14 -14
- package/src/core/collect-project-info.js +170 -170
- package/src/core/copy-base-template.js +11 -11
- package/src/core/create-project.js +99 -99
- package/src/core/install-dependencies.js +27 -27
- package/src/core/parse-cli-args.js +122 -122
- package/src/core/prepare-target-directory.js +69 -69
- package/src/core/render-project-readme.js +278 -278
- package/src/core/replace-tokens.js +45 -45
- package/src/core/restore-special-files.js +18 -18
- package/src/features/agents-md/files/AGENTS.md +36 -36
- package/src/features/agents-md/index.js +13 -13
- package/src/features/autoprefixer/files/postcss.config.cjs +4 -4
- package/src/features/autoprefixer/index.js +31 -31
- package/src/features/define-feature.js +32 -32
- package/src/features/eslint/files/eslint.config.mjs +135 -135
- package/src/features/eslint/index.js +43 -43
- package/src/features/index.js +28 -28
- package/src/features/prerender/files/prerender.routes.mjs +5 -5
- package/src/features/prerender/files/scripts/prerender.mjs +114 -114
- package/src/features/prerender/index.js +40 -40
- package/src/features/react-router/files/scripts/generate/page.mjs +366 -366
- package/src/features/react-router/files/src/app/App.tsx +18 -18
- package/src/features/react-router/files/src/app/providers/error-boundary/lib/provider/index.tsx +44 -44
- package/src/features/react-router/files/src/app/providers/error-boundary/ui/error-screen/index.tsx +151 -151
- package/src/features/react-router/files/src/app/providers/index.ts +17 -17
- package/src/features/react-router/files/src/app/providers/router/lib/provider/index.tsx +21 -21
- package/src/features/react-router/files/src/app/providers/router/model/router/index.tsx +24 -24
- package/src/features/react-router/files/src/app/providers/router/types/index.ts +10 -10
- package/src/features/react-router/files/src/app/providers/router/ui/app/index.tsx +36 -36
- package/src/features/react-router/files/src/index.tsx +23 -23
- package/src/features/react-router/files/src/pages/error/index.ts +1 -1
- package/src/features/react-router/files/src/pages/error/lazy.ts +3 -3
- package/src/features/react-router/files/src/pages/error/page.tsx +7 -7
- package/src/features/react-router/files/src/pages/main/index.ts +1 -1
- package/src/features/react-router/files/src/pages/main/lazy.ts +3 -3
- package/src/features/react-router/files/src/pages/main/page.tsx +7 -7
- package/src/features/react-router/index.js +36 -36
- package/src/features/stylelint/files/stylelint.config.mjs +13 -13
- package/src/features/stylelint/index.js +37 -37
- package/src/templates/base/.editorconfig +11 -11
- package/src/templates/base/README.md +2 -2
- package/src/templates/base/babel.config.json +12 -12
- package/src/templates/base/gitignore +27 -27
- package/src/templates/base/package.json +48 -48
- package/src/templates/base/public/index.html +12 -12
- package/src/templates/base/src/app/App.tsx +12 -12
- package/src/templates/base/src/app/providers/error-boundary/lib/provider/index.tsx +44 -44
- package/src/templates/base/src/app/providers/error-boundary/ui/error-screen/index.tsx +150 -150
- package/src/templates/base/src/app/providers/index.ts +5 -5
- package/src/templates/base/src/index.tsx +19 -19
- package/src/templates/base/src/styles/index.scss +13 -13
- package/src/templates/base/src/styles/normalize.scss +36 -36
- package/src/templates/base/tsconfig.json +25 -25
- package/src/utils/agents-md.js +52 -52
- package/src/utils/console-format.js +11 -11
- package/src/utils/package-json.js +96 -96
- package/src/utils/package-manager.js +22 -22
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { access, rename } from 'node:fs/promises';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
|
|
4
|
-
async function renameIfExists(fromPath, toPath) {
|
|
5
|
-
try {
|
|
6
|
-
await access(fromPath);
|
|
7
|
-
} catch {
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
await rename(fromPath, toPath);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export async function restoreSpecialFiles(projectPath) {
|
|
15
|
-
await renameIfExists(
|
|
16
|
-
resolve(projectPath, 'gitignore'),
|
|
17
|
-
resolve(projectPath, '.gitignore'),
|
|
18
|
-
);
|
|
1
|
+
import { access, rename } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
async function renameIfExists(fromPath, toPath) {
|
|
5
|
+
try {
|
|
6
|
+
await access(fromPath);
|
|
7
|
+
} catch {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
await rename(fromPath, toPath);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function restoreSpecialFiles(projectPath) {
|
|
15
|
+
await renameIfExists(
|
|
16
|
+
resolve(projectPath, 'gitignore'),
|
|
17
|
+
resolve(projectPath, '.gitignore'),
|
|
18
|
+
);
|
|
19
19
|
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
# AGENTS.md
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This project was scaffolded with `create-alistt69-kit`.
|
|
6
|
-
|
|
7
|
-
## Setup
|
|
8
|
-
|
|
9
|
-
- Install dependencies with the selected package manager.
|
|
10
|
-
- Start dev server with `npm run start`.
|
|
11
|
-
- Type-check with `npm run typecheck`.
|
|
12
|
-
|
|
13
|
-
## Base stack
|
|
14
|
-
|
|
15
|
-
- React
|
|
16
|
-
- TypeScript
|
|
17
|
-
- Webpack
|
|
18
|
-
- SCSS Modules
|
|
19
|
-
|
|
20
|
-
## General rules
|
|
21
|
-
|
|
22
|
-
- Keep code readable and explicit.
|
|
23
|
-
- Prefer small targeted changes over broad refactors.
|
|
24
|
-
- Do not rename public files or exported symbols unless required.
|
|
25
|
-
- Reuse existing project structure and conventions.
|
|
26
|
-
|
|
27
|
-
## Validation
|
|
28
|
-
|
|
29
|
-
Before finishing a task, run the relevant checks available in `package.json`.
|
|
30
|
-
|
|
31
|
-
## Project structure
|
|
32
|
-
|
|
33
|
-
- `src/app/` — app bootstrap and providers
|
|
34
|
-
- `src/styles/` — global styles
|
|
35
|
-
- `config/build/` — webpack config parts
|
|
36
|
-
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This project was scaffolded with `create-alistt69-kit`.
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
- Install dependencies with the selected package manager.
|
|
10
|
+
- Start dev server with `npm run start`.
|
|
11
|
+
- Type-check with `npm run typecheck`.
|
|
12
|
+
|
|
13
|
+
## Base stack
|
|
14
|
+
|
|
15
|
+
- React
|
|
16
|
+
- TypeScript
|
|
17
|
+
- Webpack
|
|
18
|
+
- SCSS Modules
|
|
19
|
+
|
|
20
|
+
## General rules
|
|
21
|
+
|
|
22
|
+
- Keep code readable and explicit.
|
|
23
|
+
- Prefer small targeted changes over broad refactors.
|
|
24
|
+
- Do not rename public files or exported symbols unless required.
|
|
25
|
+
- Reuse existing project structure and conventions.
|
|
26
|
+
|
|
27
|
+
## Validation
|
|
28
|
+
|
|
29
|
+
Before finishing a task, run the relevant checks available in `package.json`.
|
|
30
|
+
|
|
31
|
+
## Project structure
|
|
32
|
+
|
|
33
|
+
- `src/app/` — app bootstrap and providers
|
|
34
|
+
- `src/styles/` — global styles
|
|
35
|
+
- `config/build/` — webpack config parts
|
|
36
|
+
|
|
37
37
|
<!-- @agents-sections -->
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { dirname, resolve } from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
|
|
4
|
-
import { defineFeature } from '../define-feature.js';
|
|
5
|
-
|
|
6
|
-
const currentFilePath = fileURLToPath(import.meta.url);
|
|
7
|
-
const currentDirPath = dirname(currentFilePath);
|
|
8
|
-
|
|
9
|
-
export const agentsMdFeature = defineFeature({
|
|
10
|
-
id: 'agents-md',
|
|
11
|
-
title: 'AGENTS.md',
|
|
12
|
-
hint: 'Root instructions file for AI coding agents',
|
|
13
|
-
copyFiles: resolve(currentDirPath, 'files'),
|
|
1
|
+
import { dirname, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
import { defineFeature } from '../define-feature.js';
|
|
5
|
+
|
|
6
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
7
|
+
const currentDirPath = dirname(currentFilePath);
|
|
8
|
+
|
|
9
|
+
export const agentsMdFeature = defineFeature({
|
|
10
|
+
id: 'agents-md',
|
|
11
|
+
title: 'AGENTS.md',
|
|
12
|
+
hint: 'Root instructions file for AI coding agents',
|
|
13
|
+
copyFiles: resolve(currentDirPath, 'files'),
|
|
14
14
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
plugins: [
|
|
3
|
-
require('autoprefixer'),
|
|
4
|
-
],
|
|
1
|
+
module.exports = {
|
|
2
|
+
plugins: [
|
|
3
|
+
require('autoprefixer'),
|
|
4
|
+
],
|
|
5
5
|
};
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { dirname, resolve } from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
|
|
4
|
-
import { defineFeature } from '../define-feature.js';
|
|
5
|
-
import { appendAgentsSection } from '../../utils/agents-md.js';
|
|
6
|
-
|
|
7
|
-
const currentFilePath = fileURLToPath(import.meta.url);
|
|
8
|
-
const currentDirPath = dirname(currentFilePath);
|
|
9
|
-
|
|
10
|
-
export const autoprefixerFeature = defineFeature({
|
|
11
|
-
id: 'autoprefixer',
|
|
12
|
-
title: 'Autoprefixer',
|
|
13
|
-
hint: 'PostCSS vendor prefixes',
|
|
14
|
-
packageJson: {
|
|
15
|
-
devDependencies: {
|
|
16
|
-
autoprefixer: '^10.4.21',
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
copyFiles: resolve(currentDirPath, 'files'),
|
|
20
|
-
async apply({ projectPath }) {
|
|
21
|
-
await appendAgentsSection(
|
|
22
|
-
projectPath,
|
|
23
|
-
'autoprefixer',
|
|
24
|
-
`
|
|
25
|
-
## CSS compatibility
|
|
26
|
-
|
|
27
|
-
- Vendor prefixing is handled by Autoprefixer.
|
|
28
|
-
- Do not add manual prefixes unless there is a confirmed need.
|
|
29
|
-
`,
|
|
30
|
-
);
|
|
31
|
-
},
|
|
1
|
+
import { dirname, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
import { defineFeature } from '../define-feature.js';
|
|
5
|
+
import { appendAgentsSection } from '../../utils/agents-md.js';
|
|
6
|
+
|
|
7
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
8
|
+
const currentDirPath = dirname(currentFilePath);
|
|
9
|
+
|
|
10
|
+
export const autoprefixerFeature = defineFeature({
|
|
11
|
+
id: 'autoprefixer',
|
|
12
|
+
title: 'Autoprefixer',
|
|
13
|
+
hint: 'PostCSS vendor prefixes',
|
|
14
|
+
packageJson: {
|
|
15
|
+
devDependencies: {
|
|
16
|
+
autoprefixer: '^10.4.21',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
copyFiles: resolve(currentDirPath, 'files'),
|
|
20
|
+
async apply({ projectPath }) {
|
|
21
|
+
await appendAgentsSection(
|
|
22
|
+
projectPath,
|
|
23
|
+
'autoprefixer',
|
|
24
|
+
`
|
|
25
|
+
## CSS compatibility
|
|
26
|
+
|
|
27
|
+
- Vendor prefixing is handled by Autoprefixer.
|
|
28
|
+
- Do not add manual prefixes unless there is a confirmed need.
|
|
29
|
+
`,
|
|
30
|
+
);
|
|
31
|
+
},
|
|
32
32
|
});
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { cp } from 'node:fs/promises';
|
|
2
|
-
|
|
3
|
-
import { patchPackageJson } from '../utils/package-json.js';
|
|
4
|
-
|
|
5
|
-
export function defineFeature({
|
|
6
|
-
id,
|
|
7
|
-
title,
|
|
8
|
-
hint,
|
|
9
|
-
packageJson,
|
|
10
|
-
apply,
|
|
11
|
-
copyFiles,
|
|
12
|
-
}) {
|
|
13
|
-
return {
|
|
14
|
-
id,
|
|
15
|
-
title,
|
|
16
|
-
hint,
|
|
17
|
-
async applyFeature(context) {
|
|
18
|
-
if (packageJson) {
|
|
19
|
-
await patchPackageJson(context.projectPath, packageJson);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (copyFiles) {
|
|
23
|
-
await cp(copyFiles, context.projectPath, {
|
|
24
|
-
recursive: true,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (apply) {
|
|
29
|
-
await apply(context);
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
};
|
|
1
|
+
import { cp } from 'node:fs/promises';
|
|
2
|
+
|
|
3
|
+
import { patchPackageJson } from '../utils/package-json.js';
|
|
4
|
+
|
|
5
|
+
export function defineFeature({
|
|
6
|
+
id,
|
|
7
|
+
title,
|
|
8
|
+
hint,
|
|
9
|
+
packageJson,
|
|
10
|
+
apply,
|
|
11
|
+
copyFiles,
|
|
12
|
+
}) {
|
|
13
|
+
return {
|
|
14
|
+
id,
|
|
15
|
+
title,
|
|
16
|
+
hint,
|
|
17
|
+
async applyFeature(context) {
|
|
18
|
+
if (packageJson) {
|
|
19
|
+
await patchPackageJson(context.projectPath, packageJson);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (copyFiles) {
|
|
23
|
+
await cp(copyFiles, context.projectPath, {
|
|
24
|
+
recursive: true,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (apply) {
|
|
29
|
+
await apply(context);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
33
|
}
|
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
import js from '@eslint/js';
|
|
2
|
-
import stylistic from '@stylistic/eslint-plugin';
|
|
3
|
-
import importPlugin from 'eslint-plugin-import';
|
|
4
|
-
import react from 'eslint-plugin-react';
|
|
5
|
-
import reactHooks from 'eslint-plugin-react-hooks';
|
|
6
|
-
import unused from 'eslint-plugin-unused-imports';
|
|
7
|
-
import tseslint from 'typescript-eslint';
|
|
8
|
-
|
|
9
|
-
export default [
|
|
10
|
-
// ESLint recommended rules
|
|
11
|
-
js.configs.recommended,
|
|
12
|
-
|
|
13
|
-
// Paths to ignore
|
|
14
|
-
{
|
|
15
|
-
ignores: ['**/dist', '**/node_modules', '**/build', 'webpack.config.ts', 'postcss.config.cjs', 'prerender.mjs'],
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
// TypeScript rules
|
|
19
|
-
...tseslint.configs.recommended,
|
|
20
|
-
...tseslint.configs.stylistic,
|
|
21
|
-
|
|
22
|
-
// TypeScript parser configuration
|
|
23
|
-
{
|
|
24
|
-
files: ['**/*.ts', '**/*.tsx'],
|
|
25
|
-
languageOptions: {
|
|
26
|
-
parser: tseslint.parser,
|
|
27
|
-
parserOptions: { sourceType: 'module' },
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
// Stylistic rules (Prettier alternative)
|
|
32
|
-
stylistic.configs.recommended,
|
|
33
|
-
|
|
34
|
-
// Main rule configuration
|
|
35
|
-
{
|
|
36
|
-
plugins: {
|
|
37
|
-
react,
|
|
38
|
-
'react-hooks': reactHooks,
|
|
39
|
-
'@stylistic': stylistic,
|
|
40
|
-
import: importPlugin,
|
|
41
|
-
'unused-imports': unused,
|
|
42
|
-
},
|
|
43
|
-
settings: { react: { version: 'detect' } },
|
|
44
|
-
rules: {
|
|
45
|
-
// === Formatting ===
|
|
46
|
-
'@stylistic/indent': ['error', 4, { SwitchCase: 1 }],
|
|
47
|
-
'@stylistic/semi': ['error', 'always'],
|
|
48
|
-
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
|
|
49
|
-
'@stylistic/comma-dangle': ['error', 'always-multiline'],
|
|
50
|
-
'@stylistic/object-curly-spacing': ['error', 'always'],
|
|
51
|
-
'@stylistic/array-bracket-spacing': ['error', 'never'],
|
|
52
|
-
'@stylistic/eol-last': ['error', 'always'],
|
|
53
|
-
'@stylistic/arrow-parens': ['error', 'always'],
|
|
54
|
-
'@stylistic/quote-props': ['error', 'as-needed', { keywords: false }],
|
|
55
|
-
'@stylistic/member-delimiter-style': ['error', {
|
|
56
|
-
multiline: { delimiter: 'semi', requireLast: true },
|
|
57
|
-
singleline: { delimiter: 'semi', requireLast: false },
|
|
58
|
-
}],
|
|
59
|
-
'@stylistic/no-extra-parens': 'off',
|
|
60
|
-
'@stylistic/jsx-indent-props': 'off',
|
|
61
|
-
'@stylistic/multiline-ternary': 'off',
|
|
62
|
-
|
|
63
|
-
// === Whitespace ===
|
|
64
|
-
'no-trailing-spaces': ['warn', { skipBlankLines: false }],
|
|
65
|
-
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
|
|
66
|
-
'comma-style': ['error', 'last'],
|
|
67
|
-
|
|
68
|
-
// === Line length ===
|
|
69
|
-
'max-len': ['error', {
|
|
70
|
-
code: 120,
|
|
71
|
-
tabWidth: 4,
|
|
72
|
-
ignoreUrls: true,
|
|
73
|
-
ignoreStrings: true,
|
|
74
|
-
ignoreComments: false,
|
|
75
|
-
ignoreTemplateLiterals: true,
|
|
76
|
-
}],
|
|
77
|
-
|
|
78
|
-
// === Imports ===
|
|
79
|
-
'unused-imports/no-unused-imports': 'warn',
|
|
80
|
-
'unused-imports/no-unused-vars': ['warn', {
|
|
81
|
-
args: 'after-used',
|
|
82
|
-
argsIgnorePattern: '^_',
|
|
83
|
-
varsIgnorePattern: '^_',
|
|
84
|
-
caughtErrorsIgnorePattern: '^_',
|
|
85
|
-
}],
|
|
86
|
-
'import/order': ['error', {
|
|
87
|
-
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
|
88
|
-
pathGroups: [
|
|
89
|
-
{ pattern: '@/**', group: 'internal', position: 'after' },
|
|
90
|
-
{ pattern: '@app/**', group: 'internal', position: 'after' },
|
|
91
|
-
{ pattern: '@pages/**', group: 'internal', position: 'after' },
|
|
92
|
-
{ pattern: '@widgets/**', group: 'internal', position: 'after' },
|
|
93
|
-
{ pattern: '@features/**', group: 'internal', position: 'after' },
|
|
94
|
-
{ pattern: '@entities/**', group: 'internal', position: 'after' },
|
|
95
|
-
{ pattern: '@shared/**', group: 'internal', position: 'after' },
|
|
96
|
-
],
|
|
97
|
-
pathGroupsExcludedImportTypes: ['builtin', 'external'],
|
|
98
|
-
'newlines-between': 'never',
|
|
99
|
-
alphabetize: { order: 'asc', caseInsensitive: true },
|
|
100
|
-
}],
|
|
101
|
-
|
|
102
|
-
// === React ===
|
|
103
|
-
...react.configs.recommended.rules,
|
|
104
|
-
...reactHooks.configs.recommended.rules,
|
|
105
|
-
'react/react-in-jsx-scope': 'off', // Not needed in React 17+
|
|
106
|
-
'react/jsx-uses-react': 'off', // Not needed in React 17+
|
|
107
|
-
'react/prop-types': 'off', // TypeScript handles this
|
|
108
|
-
'react-hooks/set-state-in-effect': 'warn',
|
|
109
|
-
|
|
110
|
-
// === JSX formatting ===
|
|
111
|
-
'react/jsx-indent': ['error', 4],
|
|
112
|
-
'react/jsx-indent-props': ['error', 4],
|
|
113
|
-
'react/jsx-curly-spacing': ['error', { when: 'never', children: true }],
|
|
114
|
-
'react/jsx-equals-spacing': ['error', 'never'],
|
|
115
|
-
'react/jsx-tag-spacing': ['error', {
|
|
116
|
-
closingSlash: 'never',
|
|
117
|
-
beforeSelfClosing: 'always',
|
|
118
|
-
afterOpening: 'never',
|
|
119
|
-
beforeClosing: 'never',
|
|
120
|
-
}],
|
|
121
|
-
'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
|
|
122
|
-
'react/jsx-max-props-per-line': ['error', { maximum: 1, when: 'multiline' }],
|
|
123
|
-
'react/jsx-closing-bracket-location': ['error', 'line-aligned'],
|
|
124
|
-
|
|
125
|
-
// === General ===
|
|
126
|
-
'@typescript-eslint/no-unused-vars': 'off', // Handled by unused-imports
|
|
127
|
-
'no-console': ['warn', { allow: ['error'] }],
|
|
128
|
-
'no-restricted-imports': ['error', {
|
|
129
|
-
name: 'react',
|
|
130
|
-
importNames: ['default'],
|
|
131
|
-
message: 'React import is not needed in React 17+. Remove import React from "react".',
|
|
132
|
-
}],
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
];
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import stylistic from '@stylistic/eslint-plugin';
|
|
3
|
+
import importPlugin from 'eslint-plugin-import';
|
|
4
|
+
import react from 'eslint-plugin-react';
|
|
5
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
6
|
+
import unused from 'eslint-plugin-unused-imports';
|
|
7
|
+
import tseslint from 'typescript-eslint';
|
|
8
|
+
|
|
9
|
+
export default [
|
|
10
|
+
// ESLint recommended rules
|
|
11
|
+
js.configs.recommended,
|
|
12
|
+
|
|
13
|
+
// Paths to ignore
|
|
14
|
+
{
|
|
15
|
+
ignores: ['**/dist', '**/node_modules', '**/build', 'webpack.config.ts', 'postcss.config.cjs', 'prerender.mjs'],
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
// TypeScript rules
|
|
19
|
+
...tseslint.configs.recommended,
|
|
20
|
+
...tseslint.configs.stylistic,
|
|
21
|
+
|
|
22
|
+
// TypeScript parser configuration
|
|
23
|
+
{
|
|
24
|
+
files: ['**/*.ts', '**/*.tsx'],
|
|
25
|
+
languageOptions: {
|
|
26
|
+
parser: tseslint.parser,
|
|
27
|
+
parserOptions: { sourceType: 'module' },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// Stylistic rules (Prettier alternative)
|
|
32
|
+
stylistic.configs.recommended,
|
|
33
|
+
|
|
34
|
+
// Main rule configuration
|
|
35
|
+
{
|
|
36
|
+
plugins: {
|
|
37
|
+
react,
|
|
38
|
+
'react-hooks': reactHooks,
|
|
39
|
+
'@stylistic': stylistic,
|
|
40
|
+
import: importPlugin,
|
|
41
|
+
'unused-imports': unused,
|
|
42
|
+
},
|
|
43
|
+
settings: { react: { version: 'detect' } },
|
|
44
|
+
rules: {
|
|
45
|
+
// === Formatting ===
|
|
46
|
+
'@stylistic/indent': ['error', 4, { SwitchCase: 1 }],
|
|
47
|
+
'@stylistic/semi': ['error', 'always'],
|
|
48
|
+
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
|
|
49
|
+
'@stylistic/comma-dangle': ['error', 'always-multiline'],
|
|
50
|
+
'@stylistic/object-curly-spacing': ['error', 'always'],
|
|
51
|
+
'@stylistic/array-bracket-spacing': ['error', 'never'],
|
|
52
|
+
'@stylistic/eol-last': ['error', 'always'],
|
|
53
|
+
'@stylistic/arrow-parens': ['error', 'always'],
|
|
54
|
+
'@stylistic/quote-props': ['error', 'as-needed', { keywords: false }],
|
|
55
|
+
'@stylistic/member-delimiter-style': ['error', {
|
|
56
|
+
multiline: { delimiter: 'semi', requireLast: true },
|
|
57
|
+
singleline: { delimiter: 'semi', requireLast: false },
|
|
58
|
+
}],
|
|
59
|
+
'@stylistic/no-extra-parens': 'off',
|
|
60
|
+
'@stylistic/jsx-indent-props': 'off',
|
|
61
|
+
'@stylistic/multiline-ternary': 'off',
|
|
62
|
+
|
|
63
|
+
// === Whitespace ===
|
|
64
|
+
'no-trailing-spaces': ['warn', { skipBlankLines: false }],
|
|
65
|
+
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
|
|
66
|
+
'comma-style': ['error', 'last'],
|
|
67
|
+
|
|
68
|
+
// === Line length ===
|
|
69
|
+
'max-len': ['error', {
|
|
70
|
+
code: 120,
|
|
71
|
+
tabWidth: 4,
|
|
72
|
+
ignoreUrls: true,
|
|
73
|
+
ignoreStrings: true,
|
|
74
|
+
ignoreComments: false,
|
|
75
|
+
ignoreTemplateLiterals: true,
|
|
76
|
+
}],
|
|
77
|
+
|
|
78
|
+
// === Imports ===
|
|
79
|
+
'unused-imports/no-unused-imports': 'warn',
|
|
80
|
+
'unused-imports/no-unused-vars': ['warn', {
|
|
81
|
+
args: 'after-used',
|
|
82
|
+
argsIgnorePattern: '^_',
|
|
83
|
+
varsIgnorePattern: '^_',
|
|
84
|
+
caughtErrorsIgnorePattern: '^_',
|
|
85
|
+
}],
|
|
86
|
+
'import/order': ['error', {
|
|
87
|
+
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
|
88
|
+
pathGroups: [
|
|
89
|
+
{ pattern: '@/**', group: 'internal', position: 'after' },
|
|
90
|
+
{ pattern: '@app/**', group: 'internal', position: 'after' },
|
|
91
|
+
{ pattern: '@pages/**', group: 'internal', position: 'after' },
|
|
92
|
+
{ pattern: '@widgets/**', group: 'internal', position: 'after' },
|
|
93
|
+
{ pattern: '@features/**', group: 'internal', position: 'after' },
|
|
94
|
+
{ pattern: '@entities/**', group: 'internal', position: 'after' },
|
|
95
|
+
{ pattern: '@shared/**', group: 'internal', position: 'after' },
|
|
96
|
+
],
|
|
97
|
+
pathGroupsExcludedImportTypes: ['builtin', 'external'],
|
|
98
|
+
'newlines-between': 'never',
|
|
99
|
+
alphabetize: { order: 'asc', caseInsensitive: true },
|
|
100
|
+
}],
|
|
101
|
+
|
|
102
|
+
// === React ===
|
|
103
|
+
...react.configs.recommended.rules,
|
|
104
|
+
...reactHooks.configs.recommended.rules,
|
|
105
|
+
'react/react-in-jsx-scope': 'off', // Not needed in React 17+
|
|
106
|
+
'react/jsx-uses-react': 'off', // Not needed in React 17+
|
|
107
|
+
'react/prop-types': 'off', // TypeScript handles this
|
|
108
|
+
'react-hooks/set-state-in-effect': 'warn',
|
|
109
|
+
|
|
110
|
+
// === JSX formatting ===
|
|
111
|
+
'react/jsx-indent': ['error', 4],
|
|
112
|
+
'react/jsx-indent-props': ['error', 4],
|
|
113
|
+
'react/jsx-curly-spacing': ['error', { when: 'never', children: true }],
|
|
114
|
+
'react/jsx-equals-spacing': ['error', 'never'],
|
|
115
|
+
'react/jsx-tag-spacing': ['error', {
|
|
116
|
+
closingSlash: 'never',
|
|
117
|
+
beforeSelfClosing: 'always',
|
|
118
|
+
afterOpening: 'never',
|
|
119
|
+
beforeClosing: 'never',
|
|
120
|
+
}],
|
|
121
|
+
'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
|
|
122
|
+
'react/jsx-max-props-per-line': ['error', { maximum: 1, when: 'multiline' }],
|
|
123
|
+
'react/jsx-closing-bracket-location': ['error', 'line-aligned'],
|
|
124
|
+
|
|
125
|
+
// === General ===
|
|
126
|
+
'@typescript-eslint/no-unused-vars': 'off', // Handled by unused-imports
|
|
127
|
+
'no-console': ['warn', { allow: ['error'] }],
|
|
128
|
+
'no-restricted-imports': ['error', {
|
|
129
|
+
name: 'react',
|
|
130
|
+
importNames: ['default'],
|
|
131
|
+
message: 'React import is not needed in React 17+. Remove import React from "react".',
|
|
132
|
+
}],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
];
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import { dirname, resolve } from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
|
|
4
|
-
import { defineFeature } from '../define-feature.js';
|
|
5
|
-
import { appendAgentsSection } from '../../utils/agents-md.js';
|
|
6
|
-
|
|
7
|
-
const currentFilePath = fileURLToPath(import.meta.url);
|
|
8
|
-
const currentDirPath = dirname(currentFilePath);
|
|
9
|
-
|
|
10
|
-
export const eslintFeature = defineFeature({
|
|
11
|
-
id: 'eslint',
|
|
12
|
-
title: 'ESLint + Stylistic',
|
|
13
|
-
hint: 'JS/TS/React linting',
|
|
14
|
-
packageJson: {
|
|
15
|
-
devDependencies: {
|
|
16
|
-
eslint: '^9.0.0',
|
|
17
|
-
'@eslint/js': '^9.0.0',
|
|
18
|
-
'@stylistic/eslint-plugin': '^5.0.0',
|
|
19
|
-
'typescript-eslint': '^8.0.0',
|
|
20
|
-
'eslint-plugin-import': '^2.0.0',
|
|
21
|
-
'eslint-plugin-react': '^7.0.0',
|
|
22
|
-
'eslint-plugin-react-hooks': '^7.0.0',
|
|
23
|
-
'eslint-plugin-unused-imports': '^4.0.0',
|
|
24
|
-
},
|
|
25
|
-
scripts: {
|
|
26
|
-
lint: 'eslint . --ext .js,.jsx,.ts,.tsx',
|
|
27
|
-
'lint:fix': 'eslint . --ext .js,.jsx,.ts,.tsx --fix',
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
copyFiles: resolve(currentDirPath, 'files'),
|
|
31
|
-
async apply({ projectPath }) {
|
|
32
|
-
await appendAgentsSection(
|
|
33
|
-
projectPath,
|
|
34
|
-
'eslint',
|
|
35
|
-
`
|
|
36
|
-
## ESLint
|
|
37
|
-
|
|
38
|
-
- Lint code with \`npm run lint\`.
|
|
39
|
-
- Apply safe autofixes with \`npm run lint:fix\`.
|
|
40
|
-
- Prefer fixing root-cause issues instead of disabling rules.
|
|
41
|
-
`,
|
|
42
|
-
);
|
|
43
|
-
},
|
|
1
|
+
import { dirname, resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
import { defineFeature } from '../define-feature.js';
|
|
5
|
+
import { appendAgentsSection } from '../../utils/agents-md.js';
|
|
6
|
+
|
|
7
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
8
|
+
const currentDirPath = dirname(currentFilePath);
|
|
9
|
+
|
|
10
|
+
export const eslintFeature = defineFeature({
|
|
11
|
+
id: 'eslint',
|
|
12
|
+
title: 'ESLint + Stylistic',
|
|
13
|
+
hint: 'JS/TS/React linting',
|
|
14
|
+
packageJson: {
|
|
15
|
+
devDependencies: {
|
|
16
|
+
eslint: '^9.0.0',
|
|
17
|
+
'@eslint/js': '^9.0.0',
|
|
18
|
+
'@stylistic/eslint-plugin': '^5.0.0',
|
|
19
|
+
'typescript-eslint': '^8.0.0',
|
|
20
|
+
'eslint-plugin-import': '^2.0.0',
|
|
21
|
+
'eslint-plugin-react': '^7.0.0',
|
|
22
|
+
'eslint-plugin-react-hooks': '^7.0.0',
|
|
23
|
+
'eslint-plugin-unused-imports': '^4.0.0',
|
|
24
|
+
},
|
|
25
|
+
scripts: {
|
|
26
|
+
lint: 'eslint . --ext .js,.jsx,.ts,.tsx',
|
|
27
|
+
'lint:fix': 'eslint . --ext .js,.jsx,.ts,.tsx --fix',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
copyFiles: resolve(currentDirPath, 'files'),
|
|
31
|
+
async apply({ projectPath }) {
|
|
32
|
+
await appendAgentsSection(
|
|
33
|
+
projectPath,
|
|
34
|
+
'eslint',
|
|
35
|
+
`
|
|
36
|
+
## ESLint
|
|
37
|
+
|
|
38
|
+
- Lint code with \`npm run lint\`.
|
|
39
|
+
- Apply safe autofixes with \`npm run lint:fix\`.
|
|
40
|
+
- Prefer fixing root-cause issues instead of disabling rules.
|
|
41
|
+
`,
|
|
42
|
+
);
|
|
43
|
+
},
|
|
44
44
|
});
|