Skip to content

Commit 8cdcaa4

Browse files
committed
Change lang
1 parent 6d967ee commit 8cdcaa4

10 files changed

Lines changed: 314 additions & 318 deletions

File tree

README.md

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
1-
# eslint-plugin-devup
2-
3-
`devup`은 데브파이브에서 사용되는 더 빠르고 더 정확한 소프트웨어 개발을 위한 시스템입니다.
4-
5-
`devup-eslint-plugin`은 빠르고 정확하게 소프트웨어 개발을 할 수 있도록 도움을 줍니다.
6-
7-
각 룰에 대해서는 `src/rules` 디렉토리에 있는 파일을 참고하세요.
8-
9-
사내에서 사용하다가 외부에 공개된 만큼, 회사 내의 시스템을 위한 룰도 존재합니다.
10-
11-
원하는 룰만 사용할 수 있도록 `named export`로 모든 룰을 제공합니다.
12-
13-
## Installation
14-
15-
```bash
16-
pnpm install --save-dev eslint-plugin-devup
17-
```
18-
19-
## Usage
20-
21-
create `eslint.config.mjs` file in your project root.
22-
23-
```js
24-
import { configs } from 'eslint-plugin-devup'
25-
26-
export default configs.recommended
27-
```
28-
29-
## Test
30-
31-
Coverage score must be 100%.
32-
33-
```bash
34-
pnpm test
35-
```
36-
37-
## Contributing
38-
39-
- 룰을 추가하거나 수정할 때는 `src/rules` 디렉토리에 파일을 추가하거나 수정합니다.
40-
- 룰을 추가하거나 수정할 때는 `README.md`에 룰에 대한 설명을 추가합니다.
41-
42-
모든 의견과 기여를 환영합니다.
43-
44-
## Join the Community
45-
46-
[Discord](https://discord.gg/8zjcGc7cWh)
1+
# eslint-plugin-devup
2+
3+
`devup` is a system for faster and more accurate software development used at DevFive.
4+
5+
`eslint-plugin-devup` helps you develop software quickly and accurately.
6+
7+
For details on each rule, please refer to the files in the `src/rules` directory.
8+
9+
As this was originally used internally and has now been made public, some rules exist for company-specific systems.
10+
11+
All rules are provided as `named exports` so you can use only the rules you want.
12+
13+
## Installation
14+
15+
```bash
16+
bun add -d eslint-plugin-devup
17+
```
18+
19+
## Usage
20+
21+
Create an `eslint.config.mjs` file in your project root.
22+
23+
```js
24+
import { configs } from 'eslint-plugin-devup'
25+
26+
export default configs.recommended
27+
```
28+
29+
## Test
30+
31+
Coverage score must be 100%.
32+
33+
```bash
34+
bun test
35+
```
36+
37+
## Contributing
38+
39+
- When adding or modifying rules, add or modify files in the `src/rules` directory.
40+
- When adding or modifying rules, add a description of the rule in `README.md`.
41+
42+
All opinions and contributions are welcome.
43+
44+
## Join the Community
45+
46+
[Discord](https://discord.gg/8zjcGc7cWh)

bun.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
},
4646
"devDependencies": {
4747
"@changesets/cli": "^2.29",
48-
"@types/bun": "^1.2",
48+
"@types/bun": "^1.3",
4949
"@types/eslint": "^9.6",
5050
"@types/eslint__js": "^9.14",
5151
"@typescript-eslint/rule-tester": "^8.51",

src/rules/app-page/README.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
# app-page
2-
3-
## Description
4-
5-
app 내의 page.tsx 혹은 layout.tsx 파일을 생성한 후 파일이 비어 있다면 경고를 발생시키고 자동으로 컴포넌트를 생성합니다.
6-
7-
## Example
8-
9-
```jsx
10-
// app/hello/page.tsx
11-
export default function HelloPage() {
12-
return <div>...</div>
13-
}
14-
```
15-
16-
```jsx
17-
// app/page.tsx
18-
export default function IndexPage() {
19-
return <div>...</div>
20-
}
21-
```
1+
# app-page
2+
3+
## Description
4+
5+
When creating a page.tsx or layout.tsx file inside the app directory, this rule warns if the file is empty and automatically generates a component.
6+
7+
## Example
8+
9+
```jsx
10+
// app/hello/page.tsx
11+
export default function HelloPage() {
12+
return <div>...</div>
13+
}
14+
```
15+
16+
```jsx
17+
// app/page.tsx
18+
export default function IndexPage() {
19+
return <div>...</div>
20+
}
21+
```

src/rules/app-page/index.ts

Lines changed: 116 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,116 @@
1-
import { ESLintUtils } from '@typescript-eslint/utils'
2-
import { relative } from 'path'
3-
4-
const createRule = ESLintUtils.RuleCreator(
5-
(name) =>
6-
`https://github.com/dev-five-git/devup/tree/main/packages/eslint-plugin/src/rules/${name}`,
7-
)
8-
9-
export const appPage = createRule({
10-
name: 'app-page',
11-
defaultOptions: [],
12-
meta: {
13-
schema: [],
14-
messages: {
15-
pageOrLayoutComponentShouldDefaultExport:
16-
'페이지나 레이아웃 컴포넌트는 반드시 `export default`로 내보내야 합니다.',
17-
18-
nameOfPageOrLayoutComponentShouldHaveSuffix:
19-
'페이지나 레이아웃 컴포넌트의 이름은 반드시 `Page`나 `Layout`으로 끝나야 합니다.',
20-
pathParamsShouldExist:
21-
'경로 변수를 사용할 수 있을 경우 `params`는 반드시 존재해야 합니다.',
22-
},
23-
type: 'problem',
24-
fixable: 'code',
25-
docs: {
26-
description:
27-
'required 페이지나 레이아웃 컴포넌트는 반드시 export default로 내보내야 합니다.',
28-
},
29-
},
30-
create(context) {
31-
const filename = relative(context.cwd, context.physicalFilename)
32-
33-
if (!/src[/\\]app[/\\]/.test(filename)) return {}
34-
const type = /page\.[j|t]sx?$/.test(filename)
35-
? 'page'
36-
: /layout\.[j|t]sx?$/.test(filename)
37-
? 'layout'
38-
: /404\.[j|t]sx?$/.test(filename)
39-
? '404'
40-
: 'component'
41-
if (type === 'component') return {}
42-
43-
const functionSuffix = type === 'layout' ? 'Layout' : 'Page'
44-
const pathParams = filename.match(/\[.*?]/g) ?? []
45-
const onlyLocale = pathParams.length === 1 && pathParams[0] === '[locale]'
46-
// locale 만 있을 경우 무시합니다.
47-
48-
let ok = false
49-
return {
50-
ExportDefaultDeclaration(defaultExport) {
51-
ok = true
52-
const declaration = defaultExport.declaration
53-
if (declaration.type !== 'FunctionDeclaration') return
54-
if (
55-
declaration.id?.name &&
56-
!declaration.id.name.endsWith(functionSuffix)
57-
) {
58-
const func = declaration.id
59-
context.report({
60-
node: func,
61-
messageId: 'nameOfPageOrLayoutComponentShouldHaveSuffix',
62-
fix(fixer) {
63-
return fixer.replaceText(func, func.name + functionSuffix)
64-
},
65-
})
66-
}
67-
if (
68-
declaration.id &&
69-
pathParams.length &&
70-
declaration.params.length === 0 &&
71-
!onlyLocale
72-
) {
73-
context.report({
74-
node: declaration,
75-
messageId: 'pathParamsShouldExist',
76-
fix(fixer) {
77-
return fixer.replaceTextRange(
78-
[
79-
declaration.id!.range[1],
80-
declaration.returnType
81-
? declaration.returnType.range[0]
82-
: declaration.body.range[0],
83-
],
84-
`({params}:{params:Promise<{${pathParams
85-
.map((param) => `${param.slice(1, -1)}:string`)
86-
.join(';')}}>})`,
87-
)
88-
},
89-
})
90-
}
91-
return
92-
},
93-
'Program:exit'(program) {
94-
// 소스코드가 비어있으면 자동생성
95-
if (ok) return
96-
context.report({
97-
node: program,
98-
messageId: 'pageOrLayoutComponentShouldDefaultExport',
99-
fix(fixer) {
100-
return fixer.insertTextAfter(
101-
program,
102-
`${context.sourceCode.text.trim().length ? '\n' : ''}export default function ` +
103-
(type === '404' ? 'NotFoundPage' : functionSuffix) +
104-
`(${
105-
pathParams.length
106-
? `{params}:{params:Promise<{${pathParams
107-
.map((param) => `${param.slice(1, -1)}:string`)
108-
.join(';')}}>}`
109-
: ''
110-
}){return <></>}`,
111-
)
112-
},
113-
})
114-
},
115-
}
116-
},
117-
})
1+
import { ESLintUtils } from '@typescript-eslint/utils'
2+
import { relative } from 'path'
3+
4+
const createRule = ESLintUtils.RuleCreator(
5+
(name) =>
6+
`https://github.com/dev-five-git/devup/tree/main/packages/eslint-plugin/src/rules/${name}`,
7+
)
8+
9+
export const appPage = createRule({
10+
name: 'app-page',
11+
defaultOptions: [],
12+
meta: {
13+
schema: [],
14+
messages: {
15+
pageOrLayoutComponentShouldDefaultExport:
16+
'Page or layout component must be exported with `export default`.',
17+
nameOfPageOrLayoutComponentShouldHaveSuffix:
18+
'Page or layout component name must end with `Page` or `Layout`.',
19+
pathParamsShouldExist:
20+
'`params` must exist when path parameters are available.',
21+
},
22+
type: 'problem',
23+
fixable: 'code',
24+
docs: {
25+
description:
26+
'Require page or layout component to be exported with export default.',
27+
},
28+
},
29+
create(context) {
30+
const filename = relative(context.cwd, context.physicalFilename)
31+
32+
if (!/src[/\\]app[/\\]/.test(filename)) return {}
33+
const type = /page\.[j|t]sx?$/.test(filename)
34+
? 'page'
35+
: /layout\.[j|t]sx?$/.test(filename)
36+
? 'layout'
37+
: /404\.[j|t]sx?$/.test(filename)
38+
? '404'
39+
: 'component'
40+
if (type === 'component') return {}
41+
42+
const functionSuffix = type === 'layout' ? 'Layout' : 'Page'
43+
const pathParams = filename.match(/\[.*?]/g) ?? []
44+
// Ignore when only locale param exists
45+
const onlyLocale = pathParams.length === 1 && pathParams[0] === '[locale]'
46+
47+
let ok = false
48+
return {
49+
ExportDefaultDeclaration(defaultExport) {
50+
ok = true
51+
const declaration = defaultExport.declaration
52+
if (declaration.type !== 'FunctionDeclaration') return
53+
if (
54+
declaration.id?.name &&
55+
!declaration.id.name.endsWith(functionSuffix)
56+
) {
57+
const func = declaration.id
58+
context.report({
59+
node: func,
60+
messageId: 'nameOfPageOrLayoutComponentShouldHaveSuffix',
61+
fix(fixer) {
62+
return fixer.replaceText(func, func.name + functionSuffix)
63+
},
64+
})
65+
}
66+
if (
67+
declaration.id &&
68+
pathParams.length &&
69+
declaration.params.length === 0 &&
70+
!onlyLocale
71+
) {
72+
context.report({
73+
node: declaration,
74+
messageId: 'pathParamsShouldExist',
75+
fix(fixer) {
76+
return fixer.replaceTextRange(
77+
[
78+
declaration.id!.range[1],
79+
declaration.returnType
80+
? declaration.returnType.range[0]
81+
: declaration.body.range[0],
82+
],
83+
`({params}:{params:Promise<{${pathParams
84+
.map((param) => `${param.slice(1, -1)}:string`)
85+
.join(';')}}>})`,
86+
)
87+
},
88+
})
89+
}
90+
return
91+
},
92+
'Program:exit'(program) {
93+
// Auto-generate if source code is empty
94+
if (ok) return
95+
context.report({
96+
node: program,
97+
messageId: 'pageOrLayoutComponentShouldDefaultExport',
98+
fix(fixer) {
99+
return fixer.insertTextAfter(
100+
program,
101+
`${context.sourceCode.text.trim().length ? '\n' : ''}export default function ` +
102+
(type === '404' ? 'NotFoundPage' : functionSuffix) +
103+
`(${
104+
pathParams.length
105+
? `{params}:{params:Promise<{${pathParams
106+
.map((param) => `${param.slice(1, -1)}:string`)
107+
.join(';')}}>}`
108+
: ''
109+
}){return <></>}`,
110+
)
111+
},
112+
})
113+
},
114+
}
115+
},
116+
})

0 commit comments

Comments
 (0)