Skip to content

Commit 26f479a

Browse files
authored
refactor: change UserRule 'no' field to 'id' with string type (#11)
Replace the 'no' field with 'id' across the codebase for better clarity and consistency. Changed from int to string type to align with linter configuration requirements. Changes: - Update UserRule schema: no (int) -> id (string) - Update policy-editor.js: all references from 'no' to 'id' - Update policy validation in manager.go - Update all template JSON files with string-typed id values - Remove parseInt() calls in JavaScript, use string comparison
1 parent 61612b5 commit 26f479a

File tree

9 files changed

+84
-85
lines changed

9 files changed

+84
-85
lines changed

internal/policy/manager.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,18 @@ func ValidatePolicy(policy *schema.UserPolicy) error {
9292
}
9393

9494
// Validate rules
95-
ruleNumbers := make(map[int]bool)
95+
ruleIDs := make(map[string]bool)
9696
for i, rule := range policy.Rules {
9797
if rule.Say == "" {
9898
return fmt.Errorf("rule %d: 'say' field is required", i+1)
9999
}
100-
if rule.No <= 0 {
101-
return fmt.Errorf("rule %d: 'no' field must be positive", i+1)
100+
if rule.ID == "" {
101+
return fmt.Errorf("rule %d: 'id' field is required", i+1)
102102
}
103-
if ruleNumbers[rule.No] {
104-
return fmt.Errorf("duplicate rule number: %d", rule.No)
103+
if ruleIDs[rule.ID] {
104+
return fmt.Errorf("duplicate rule id: %s", rule.ID)
105105
}
106-
ruleNumbers[rule.No] = true
106+
ruleIDs[rule.ID] = true
107107
}
108108

109109
// Validate RBAC roles

internal/policy/templates/go-template.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,54 +15,54 @@
1515
},
1616
"rules": [
1717
{
18-
"no": 1,
18+
"id": "1",
1919
"say": "패키지 이름은 소문자 한 단어로 작성합니다 (예: http, json, user)",
2020
"category": "naming",
2121
"example": "// ✅ 좋은 예:\npackage user\npackage database\npackage httputil\n\n// ❌ 나쁜 예:\npackage UserManagement\npackage data_base\npackage HTTP_Util"
2222
},
2323
{
24-
"no": 2,
24+
"id": "2",
2525
"say": "변수와 함수 이름은 camelCase 또는 PascalCase를 사용합니다 (public은 대문자 시작)",
2626
"category": "naming"
2727
},
2828
{
29-
"no": 3,
29+
"id": "3",
3030
"say": "에러는 항상 처리하고, 무시하는 경우 명시적으로 _ 를 사용합니다",
3131
"category": "error_handling",
3232
"example": "// ✅ 좋은 예:\nfile, err := os.Open(\"config.json\")\nif err != nil {\n return fmt.Errorf(\"failed to open config: %w\", err)\n}\ndefer file.Close()\n\n// ❌ 나쁜 예:\nfile, _ := os.Open(\"config.json\")\ndefer file.Close()"
3333
},
3434
{
35-
"no": 4,
35+
"id": "4",
3636
"say": "함수는 에러를 마지막 반환값으로 반환합니다",
3737
"category": "error_handling"
3838
},
3939
{
40-
"no": 5,
40+
"id": "5",
4141
"say": "인터페이스 이름은 -er 접미사를 사용합니다 (예: Reader, Writer, Handler)",
4242
"category": "naming"
4343
},
4444
{
45-
"no": 6,
45+
"id": "6",
4646
"say": "gofmt로 코드를 포맷팅합니다",
4747
"category": "formatting"
4848
},
4949
{
50-
"no": 7,
50+
"id": "7",
5151
"say": "공개(exported) 함수와 타입에는 주석을 작성합니다",
5252
"category": "documentation"
5353
},
5454
{
55-
"no": 8,
55+
"id": "8",
5656
"say": "context.Context를 함수의 첫 번째 파라미터로 전달합니다",
5757
"category": "error_handling"
5858
},
5959
{
60-
"no": 9,
60+
"id": "9",
6161
"say": "goroutine 사용 시 적절한 동기화(sync, channel)를 사용합니다",
6262
"category": "error_handling"
6363
},
6464
{
65-
"no": 10,
65+
"id": "10",
6666
"say": "defer를 사용하여 리소스 정리를 보장합니다",
6767
"category": "error_handling"
6868
}

internal/policy/templates/node-template.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,55 +19,55 @@
1919
},
2020
"rules": [
2121
{
22-
"no": 1,
22+
"id": "1",
2323
"say": "환경 변수는 process.env가 아닌 설정 파일(config.js)을 통해 접근합니다",
2424
"category": "security"
2525
},
2626
{
27-
"no": 2,
27+
"id": "2",
2828
"say": "민감한 정보(API 키, 비밀번호)는 절대 하드코딩하지 않습니다",
2929
"category": "security",
3030
"example": "// ✅ 좋은 예:\nconst apiKey = process.env.API_KEY;\nconst dbPassword = config.get('database.password');\n\n// ❌ 나쁜 예:\nconst apiKey = 'sk-1234567890abcdef';\nconst dbPassword = 'mySecretPassword123';"
3131
},
3232
{
33-
"no": 3,
33+
"id": "3",
3434
"say": "모든 비동기 함수는 try-catch 블록으로 에러를 처리합니다",
3535
"category": "error_handling",
3636
"example": "// ✅ 좋은 예:\nasync function fetchUser(id) {\n try {\n const user = await db.users.findById(id);\n return user;\n } catch (error) {\n logger.error('Failed to fetch user:', error);\n throw new ApiError('User not found', 404);\n }\n}\n\n// ❌ 나쁜 예:\nasync function fetchUser(id) {\n const user = await db.users.findById(id);\n return user;\n}"
3737
},
3838
{
39-
"no": 4,
39+
"id": "4",
4040
"say": "API 라우트 핸들러는 항상 적절한 HTTP 상태 코드를 반환합니다",
4141
"category": "error_handling"
4242
},
4343
{
44-
"no": 5,
44+
"id": "5",
4545
"say": "데이터베이스 쿼리는 SQL injection을 방지하기 위해 parameterized query를 사용합니다",
4646
"category": "security",
4747
"example": "// ✅ 좋은 예:\nconst result = await db.query('SELECT * FROM users WHERE id = ?', [userId]);\n\n// ❌ 나쁜 예:\nconst result = await db.query(`SELECT * FROM users WHERE id = ${userId}`);"
4848
},
4949
{
50-
"no": 6,
50+
"id": "6",
5151
"say": "파일 이름은 kebab-case를 사용합니다 (예: user-controller.js, auth-service.js)",
5252
"category": "naming"
5353
},
5454
{
55-
"no": 7,
55+
"id": "7",
5656
"say": "클래스 이름은 PascalCase, 함수/변수는 camelCase를 사용합니다",
5757
"category": "naming"
5858
},
5959
{
60-
"no": 8,
60+
"id": "8",
6161
"say": "미들웨어 함수는 next()를 명시적으로 호출하거나 응답을 보냅니다",
6262
"category": "error_handling"
6363
},
6464
{
65-
"no": 9,
65+
"id": "9",
6666
"say": "큰 의존성 패키지는 필요한 부분만 import합니다 (tree-shaking)",
6767
"category": "performance"
6868
},
6969
{
70-
"no": 10,
70+
"id": "10",
7171
"say": "로그 메시지는 적절한 레벨(debug, info, warn, error)을 사용합니다",
7272
"category": "documentation"
7373
}

internal/policy/templates/python-template.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,55 +19,55 @@
1919
},
2020
"rules": [
2121
{
22-
"no": 1,
22+
"id": "1",
2323
"say": "PEP 8 스타일 가이드를 준수합니다 (들여쓰기 4칸, 최대 라인 길이 79자)",
2424
"category": "formatting"
2525
},
2626
{
27-
"no": 2,
27+
"id": "2",
2828
"say": "함수와 변수 이름은 snake_case를 사용합니다 (예: calculate_total, user_name)",
2929
"category": "naming",
3030
"example": "# ✅ 좋은 예:\ndef calculate_total_price(items):\n total_price = sum(item.price for item in items)\n return total_price\n\n# ❌ 나쁜 예:\ndef calculateTotalPrice(items):\n totalPrice = sum(item.price for item in items)\n return totalPrice"
3131
},
3232
{
33-
"no": 3,
33+
"id": "3",
3434
"say": "클래스 이름은 PascalCase를 사용합니다 (예: UserModel, DataProcessor)",
3535
"category": "naming",
3636
"example": "# ✅ 좋은 예:\nclass UserProfile:\n def __init__(self, name):\n self.name = name\n\n# ❌ 나쁜 예:\nclass user_profile:\n def __init__(self, name):\n self.name = name"
3737
},
3838
{
39-
"no": 4,
39+
"id": "4",
4040
"say": "상수는 대문자와 언더스코어를 사용합니다 (예: MAX_SIZE, API_KEY)",
4141
"category": "naming"
4242
},
4343
{
44-
"no": 5,
44+
"id": "5",
4545
"say": "모든 함수와 클래스는 docstring을 작성합니다",
4646
"category": "documentation"
4747
},
4848
{
49-
"no": 6,
49+
"id": "6",
5050
"say": "타입 힌트를 사용하여 함수 시그니처를 명확히 합니다",
5151
"category": "documentation"
5252
},
5353
{
54-
"no": 7,
54+
"id": "7",
5555
"say": "예외는 구체적인 타입으로 처리합니다 (Exception보다는 ValueError, TypeError 등)",
5656
"category": "error_handling",
5757
"example": "# ✅ 좋은 예:\ntry:\n result = int(user_input)\nexcept ValueError as e:\n logger.error(f\"Invalid input: {e}\")\n result = 0\n\n# ❌ 나쁜 예:\ntry:\n result = int(user_input)\nexcept:\n result = 0"
5858
},
5959
{
60-
"no": 8,
60+
"id": "8",
6161
"say": "리소스(파일, 데이터베이스)는 with 문으로 관리합니다",
6262
"category": "error_handling"
6363
},
6464
{
65-
"no": 9,
65+
"id": "9",
6666
"say": "민감한 정보는 환경 변수나 설정 파일을 통해 관리합니다",
6767
"category": "security"
6868
},
6969
{
70-
"no": 10,
70+
"id": "10",
7171
"say": "리스트 컴프리헨션은 3줄 이내로 유지하고, 복잡한 경우 일반 for문을 사용합니다",
7272
"category": "formatting"
7373
}

internal/policy/templates/react-template.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,60 +19,60 @@
1919
},
2020
"rules": [
2121
{
22-
"no": 1,
22+
"id": "1",
2323
"say": "컴포넌트 이름은 PascalCase를 사용합니다 (예: UserProfile, NavBar)",
2424
"category": "naming",
2525
"languages": ["javascript", "typescript", "jsx", "tsx"],
2626
"example": "// ✅ 좋은 예:\nfunction UserProfile() { ... }\nfunction NavBar() { ... }\n\n// ❌ 나쁜 예:\nfunction userProfile() { ... }\nfunction nav_bar() { ... }"
2727
},
2828
{
29-
"no": 2,
29+
"id": "2",
3030
"say": "React Hooks는 함수 컴포넌트 최상단에서만 호출합니다",
3131
"category": "error_handling",
3232
"languages": ["javascript", "typescript", "jsx", "tsx"],
3333
"example": "// ✅ 좋은 예:\nfunction MyComponent() {\n const [count, setCount] = useState(0);\n const value = useMemo(() => count * 2, [count]);\n return <div>{value}</div>;\n}\n\n// ❌ 나쁜 예:\nfunction MyComponent() {\n if (condition) {\n const [count, setCount] = useState(0); // 조건부 호출 금지\n }\n}"
3434
},
3535
{
36-
"no": 3,
36+
"id": "3",
3737
"say": "useEffect의 의존성 배열을 정확히 명시하여 무한 루프를 방지합니다",
3838
"category": "error_handling",
3939
"languages": ["javascript", "typescript"]
4040
},
4141
{
42-
"no": 4,
42+
"id": "4",
4343
"say": "Props는 구조 분해 할당으로 받습니다 (예: function Button({ label, onClick }) {...})",
4444
"category": "formatting",
4545
"languages": ["javascript", "typescript", "jsx", "tsx"],
4646
"example": "// ✅ 좋은 예:\nfunction Button({ label, onClick, disabled = false }) {\n return <button onClick={onClick} disabled={disabled}>{label}</button>;\n}\n\n// ❌ 나쁜 예:\nfunction Button(props) {\n return <button onClick={props.onClick}>{props.label}</button>;\n}"
4747
},
4848
{
49-
"no": 5,
49+
"id": "5",
5050
"say": "컴포넌트 파일 하나당 하나의 컴포넌트만 export합니다",
5151
"category": "formatting"
5252
},
5353
{
54-
"no": 6,
54+
"id": "6",
5555
"say": "이벤트 핸들러 함수는 'handle' 접두사를 사용합니다 (예: handleClick, handleSubmit)",
5656
"category": "naming"
5757
},
5858
{
59-
"no": 7,
59+
"id": "7",
6060
"say": "boolean 타입의 Props는 'is', 'has', 'should' 접두사를 사용합니다 (예: isOpen, hasError)",
6161
"category": "naming"
6262
},
6363
{
64-
"no": 8,
64+
"id": "8",
6565
"say": "인라인 스타일 대신 CSS 모듈 또는 styled-components를 사용합니다",
6666
"category": "formatting"
6767
},
6868
{
69-
"no": 9,
69+
"id": "9",
7070
"say": "Key prop에 배열 인덱스를 사용하지 않습니다. 고유한 ID를 사용하세요",
7171
"category": "performance",
7272
"example": "// ✅ 좋은 예:\n{users.map(user => <UserCard key={user.id} user={user} />)}\n\n// ❌ 나쁜 예:\n{users.map((user, index) => <UserCard key={index} user={user} />)}"
7373
},
7474
{
75-
"no": 10,
75+
"id": "10",
7676
"say": "큰 리스트는 React.memo 또는 useMemo로 최적화합니다",
7777
"category": "performance"
7878
}

internal/policy/templates/typescript-template.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,54 +15,54 @@
1515
},
1616
"rules": [
1717
{
18-
"no": 1,
18+
"id": "1",
1919
"say": "any 타입 사용을 최소화하고 구체적인 타입을 정의합니다",
2020
"category": "error_handling",
2121
"example": "// ✅ 좋은 예:\ninterface User {\n id: number;\n name: string;\n}\nfunction processUser(user: User): void { ... }\n\n// ❌ 나쁜 예:\nfunction processUser(user: any): void { ... }"
2222
},
2323
{
24-
"no": 2,
24+
"id": "2",
2525
"say": "인터페이스와 타입 별칭의 이름은 PascalCase를 사용합니다",
2626
"category": "naming"
2727
},
2828
{
29-
"no": 3,
29+
"id": "3",
3030
"say": "타입 정의 파일(.d.ts)은 types/ 폴더에 위치시킵니다",
3131
"category": "formatting"
3232
},
3333
{
34-
"no": 4,
34+
"id": "4",
3535
"say": "제네릭 타입 파라미터는 의미 있는 이름을 사용합니다 (T보다는 TItem, TResponse)",
3636
"category": "naming"
3737
},
3838
{
39-
"no": 5,
39+
"id": "5",
4040
"say": "유틸리티 타입(Partial, Pick, Omit 등)을 적극 활용합니다",
4141
"category": "performance"
4242
},
4343
{
44-
"no": 6,
44+
"id": "6",
4545
"say": "strict 모드를 활성화하여 엄격한 타입 체크를 수행합니다",
4646
"category": "error_handling"
4747
},
4848
{
49-
"no": 7,
49+
"id": "7",
5050
"say": "열거형(enum) 대신 const assertion이나 union 타입을 고려합니다",
5151
"category": "performance"
5252
},
5353
{
54-
"no": 8,
54+
"id": "8",
5555
"say": "함수 시그니처에 반환 타입을 명시적으로 선언합니다",
5656
"category": "documentation",
5757
"example": "// ✅ 좋은 예:\nfunction calculateTotal(price: number, quantity: number): number {\n return price * quantity;\n}\n\n// ❌ 나쁜 예:\nfunction calculateTotal(price: number, quantity: number) {\n return price * quantity;\n}"
5858
},
5959
{
60-
"no": 9,
60+
"id": "9",
6161
"say": "readonly를 사용하여 불변성을 보장합니다",
6262
"category": "error_handling"
6363
},
6464
{
65-
"no": 10,
65+
"id": "10",
6666
"say": "타입 가드를 사용하여 런타임 타입 안전성을 확보합니다",
6767
"category": "error_handling"
6868
}

0 commit comments

Comments
 (0)