---
title: "ast-grep Config"
description: "코딩 에이전트가 코드베이스를 쉽게 탐색하도록 돕는 ast-grep 규칙."
---

> Documentation Index
> Fetch the complete documentation index at: https://code-style.pages.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# ast-grep Config

`@pleaseai/ast-grep-config`는 코딩 에이전트가 코드베이스를 쉽게 탐색하도록 돕는 [ast-grep](https://ast-grep.github.io/) 규칙 모음입니다. 공개 심볼은 이름으로 찾을 수 있어야 하고, 에러 타입은 지정된 파일에 모으며, 소스 파일 안에 테스트를 두지 않습니다. TypeScript, Dart, Kotlin, Java, Rust에 대해 [ADR-0022](https://github.com/chatbot-pf/engineering-standards/blob/main/docs/adr/0022-agent-navigable-code-organization-standard.md)의 2층(구조 규칙)을 집행합니다.

모든 규칙은 **경고(warning)**로 배포됩니다. 직접 규칙의 심각도를 올리지 않는 한 빌드를 막지 않습니다.

## 설치

```bash
bun add -D @pleaseai/ast-grep-config @ast-grep/cli
```

```bash
pnpm add -D @pleaseai/ast-grep-config @ast-grep/cli
```

```bash
npm install -D @pleaseai/ast-grep-config @ast-grep/cli
```

`ast-grep` 바이너리는 peer dependency인 [`@ast-grep/cli`](https://ast-grep.github.io/)가 제공합니다. 프로젝트의 bin 경로에 `ast-grep`이 잡히도록 이 패키지와 함께 설치하세요.

bun을 쓴다면 `trustedDependencies`에 `@ast-grep/cli`를 추가해 postinstall 단계가 실행되게 하세요. 그렇지 않으면 `ast-grep`을 실행할 때마다 대체 경로 경고가 출력됩니다(`please-style check`는 영향을 받지 않습니다).

```json title="package.json"
{
  "trustedDependencies": ["@ast-grep/cli"]
}
```

> **Tip**
>
> `bunx @pleaseai/code-style init`에서 **ast-grep**을 선택하면 CLI가 두 패키지를 설치하고 `sgconfig.yml`까지 작성해 줍니다.

## 사용법

프로젝트의 `sgconfig.yml`이 규칙 디렉터리를 가리키게 합니다.

```yaml title="sgconfig.yml"
ruleDirs:
  - node_modules/@pleaseai/ast-grep-config/rules
```

```bash
bunx ast-grep scan
```

설정 파일을 따로 두지 않고 패키지의 설정을 바로 쓸 수도 있습니다.

```bash
bunx ast-grep scan -c node_modules/@pleaseai/ast-grep-config/sgconfig.yml
```

## 다섯 가지 원칙

| Slug | 원칙 |
| --- | --- |
| `code-greppable-public-symbols` | 공개 심볼은 이름 있는 선언으로 정의하고 노출해, 이름 검색 한 번으로 정의와 사용처를 모두 찾는다. |
| `code-filename-matches-primary-symbol` | 공개 심볼이 하나인 파일은 언어의 파일 이름 규약으로 정규화했을 때 그 심볼 이름과 일치한다. |
| `code-error-types-in-dedicated-module` | 모듈의 에러 타입은 지정된 에러 파일이나 패키지에 모은다. |
| `test-path-derivable-from-source` | 테스트는 툴체인이 정한 테스트 루트 아래, 대상 소스 경로를 미러링한 위치에 둔다. |
| `test-helpers-in-dedicated-location` | 여러 테스트가 공유하는 헬퍼는 지정된 위치에 둔다. |

검사는 두 층으로 나뉩니다.

- **2층** — 이 패키지의 ast-grep 규칙으로, `ast-grep scan`으로 실행합니다.
- **3층** — ast-grep이 보지 못하는 것(파일 이름, 테스트 경로, 헬퍼 공유 여부)을 맡는 경로 검사기 [`please-style check`](/ko/cli#check)입니다. 이 패키지의 `extract/` 디렉터리에 있는 추출 규칙을 실행합니다. `extract/`는 `ruleDirs`에 들어 있지 않으므로 `ast-grep scan` 출력에는 나타나지 않습니다.

## 규칙

| 규칙 | Slug | 언어 |
| --- | --- | --- |
| [`ts-no-default-export`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/typescript/ts-no-default-export.md) | `code-greppable-public-symbols` | TypeScript |
| [`tsx-no-default-export`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/tsx/tsx-no-default-export.md) | `code-greppable-public-symbols` | TSX |
| [`rust-no-glob-reexport`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/rust/rust-no-glob-reexport.md) | `code-greppable-public-symbols` | Rust |
| [`ts-error-outside-errors-file`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/typescript/ts-error-outside-errors-file.md) | `code-error-types-in-dedicated-module` | TypeScript |
| [`tsx-error-outside-errors-file`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/tsx/tsx-error-outside-errors-file.md) | `code-error-types-in-dedicated-module` | TSX |
| [`dart-error-outside-errors-file`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/dart/dart-error-outside-errors-file.md) | `code-error-types-in-dedicated-module` | Dart |
| [`kotlin-error-outside-errors-file`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/kotlin/kotlin-error-outside-errors-file.md) | `code-error-types-in-dedicated-module` | Kotlin |
| [`java-error-outside-error-package`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/java/java-error-outside-error-package.md) | `code-error-types-in-dedicated-module` | Java |
| [`rust-error-outside-error-file`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/rust/rust-error-outside-error-file.md) | `code-error-types-in-dedicated-module` | Rust |
| [`ts-no-in-source-test`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/typescript/ts-no-in-source-test.md) | `test-path-derivable-from-source` | TypeScript |
| [`tsx-no-in-source-test`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/tsx/tsx-no-in-source-test.md) | `test-path-derivable-from-source` | TSX |

규칙마다 옆에 README가 있고, 규칙의 이유, 틀린 예와 올바른 예, 위반을 고치는 단계를 적어 두었습니다(영문). 경고 메시지에 slug와 `node_modules` 안의 README 경로가 들어 있어 에이전트가 메시지만 보고도 위반을 고칠 수 있습니다.

```text
[code-greppable-public-symbols] Default export hides the symbol's name from
grep. Export a named declaration instead. Fix guide:
node_modules/@pleaseai/ast-grep-config/rules/typescript/ts-no-default-export.md
```

### default export 금지

`ts-no-default-export`와 `tsx-no-default-export`는 `export default …`, `export { foo as default }`, `export { default } from './x'`를 잡아냅니다. default import는 가져오는 쪽마다 로컬 이름을 마음대로 정할 수 있어서, 선언 이름으로 검색하면 그런 import 위치를 놓칩니다. named import는 내보낸 이름을 반드시 적어야 합니다.

```ts
// 틀린 예
export default class UserService {}

// 올바른 예
export class UserService {}
```

### glob 재export 금지

`rust-no-glob-reexport`는 가시성 수식어(`pub`, `pub(crate)`, `pub(super)`)가 붙은 `use` 중 `*`가 들어간 것을 잡아냅니다. `use super::*;` 같은 비공개 glob import는 대상이 아닙니다. glob을 지금 내보내는 항목의 명시적 목록으로 바꾸세요.

```rust
// 틀린 예
pub use crate::model::*;

// 올바른 예
pub use crate::model::{Account, User};
```

### 에러 타입은 전용 모듈에

ast-grep에는 타입 정보가 없으므로 에러 규칙은 이름으로 판단합니다. 클래스 기반 언어에서는 상위 타입 이름이 `Error` 또는 `Exception`으로 끝나거나, 자신의 이름이 `Error` 또는 `Exception`으로 끝나면서 상위 타입도 있는 클래스가 대상입니다.

- TypeScript / TSX: `extends`로 지정한 상위 클래스만 확인합니다. `implements`는 대상이 아니며, 이름이 `*Error`/`*Exception`인 클래스는 `extends` 절이 있을 때만 대상입니다.
- Java: 상위 클래스만 확인합니다(`Throwable`도 포함). `implements`는 대상이 아닙니다.
- Dart: 상위 클래스 또는 구현한 타입을 확인합니다. 이름이 `*Error`/`*Exception`인 클래스는 상위 클래스 또는 `implements` 절이 있어야 합니다.
- Kotlin: 모든 상위 타입을 확인하며(`Throwable`도 포함) `class`와 `object` 선언이 대상입니다.

Rust는 이름이 `Error`로 끝나는(`Exception`은 제외) `struct`/`enum`, `#[derive(…Error)]`가 붙은 `struct`/`enum`, 그리고 모든 `impl Error for T`(`std::error::Error`, `core::error::Error` 포함)를 잡아냅니다. 에러 타입을 두는 위치는 언어마다 다릅니다.

| 언어 | 에러 타입 위치 | 함께 제외되는 경로 |
| --- | --- | --- |
| TypeScript / TSX | 모듈 디렉터리의 `errors.ts` | `*.d.ts`, `*.test.*`, `*.spec.*`, `test/`, `tests/`, `__tests__/` |
| Dart / Flutter | 라이브러리 디렉터리의 `errors.dart` | `*_test.dart`, `test/`, `integration_test/`, `test_driver/` |
| Kotlin | 패키지 디렉터리의 `Errors.kt` | `src/test/`, `src/testFixtures/`, 이름이 `Test`로 끝나는 소스 세트 |
| Java | 모듈 아래 `error/` 하위 패키지 | `src/test/`, `src/testFixtures/`, `src/androidTest/` |
| Rust | 모듈 루트 옆 `error.rs`(또는 `error/` 모듈) | `tests/` 아래 통합 테스트 |

검사하는 것은 위치뿐입니다. 에러 파일에 헬퍼나 import가 있어도 됩니다.

### 소스 내 테스트 금지

`ts-no-in-source-test`와 `tsx-no-in-source-test`는 Vitest [in-source 테스트](https://vitest.dev/guide/in-source.html)(`if (import.meta.vitest) { … }`)를 잡아냅니다. `test/**` glob으로 찾을 수 없고, 프로덕션 빌드에서 제거하려면 번들러 `define`이 필요하기 때문입니다. 블록을 패키지 테스트 루트 아래, 소스 경로를 미러링한 테스트 파일로 옮기세요. `src/math/add.ts`라면 `test/math/add.test.ts`가 됩니다.

## 프레임워크 파일

프레임워크가 형태를 정하는 파일은 `ts-no-default-export`와 `tsx-no-default-export`의 `ignores` 목록으로만 제외합니다.

- 타입 선언: `*.d.ts`, `*.d.mts`, `*.d.cts`
- 설정 파일: `*.config.ts`와 `*.config.*.ts`(예: `vite.config.prod.ts`). `.mts`, `.cts`, `.tsx` 형태도 포함합니다
- Storybook story(`*.stories.ts`, `*.stories.tsx` 등), `.vitepress/`, `.storybook/`
- Nuxt 4: `app/pages/`, `app/layouts/`, `app/middleware/`, `app/plugins/`, 그리고 `app/app.config.ts`, `app/router.options.ts`
- Nitro: `server/api/`, `server/routes/`, `server/middleware/`, `server/plugins/`, `server/tasks/`

전체 목록은 [`ts-no-default-export.yml`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/typescript/ts-no-default-export.yml)과 [`tsx-no-default-export.yml`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/tsx/tsx-no-default-export.yml)에 있습니다. 다른 규칙은 이 경로를 제외하지 않습니다. 단, 타입 선언 파일은 `ts-error-outside-errors-file`과 `tsx-error-outside-errors-file`에서도 제외됩니다.

`app/` 없이 루트에 `pages/`, `layouts/`, `middleware/`, `plugins/`를 두는 Nuxt 3 구조는 제외하지 **않습니다**. `**/plugins/**` 같은 glob은 이름이 `plugins`인 무관한 디렉터리까지 모두 제외해 버리기 때문입니다. ast-grep은 배포된 규칙의 `ignores`를 덮어쓸 수 없으므로 명령줄에서 규칙 범위를 좁히세요. 기본 스캔에서는 두 규칙을 끄고, 프레임워크 디렉터리를 제외한 채 한 번 더 실행합니다.

```bash
ast-grep scan --off=ts-no-default-export --off=tsx-no-default-export
ast-grep scan --filter '^(ts|tsx)-no-default-export$' \
  --globs '!pages/**' --globs '!layouts/**' \
  --globs '!middleware/**' --globs '!plugins/**' --globs '!app.config.ts'
```

CI와 에이전트가 같은 명령을 실행하도록 두 명령을 하나의 패키지 스크립트(예: `lint:structure`)에 넣으세요. Nuxt 4의 `app/` 구조로 옮기면 이 두 단계 대신 일반 `ast-grep scan`을 한 번 실행하세요. 첫 번째 명령만 남기면 두 규칙이 모든 파일에서 꺼집니다.

> **Caution**
>
> 규칙을 끄려고 `ast-grep-ignore` 주석을 추가하지 마세요. 리뷰에서 걸러지는 억제(suppression)입니다. 다른 프레임워크가 다른 위치에 default export를 요구한다면 `@pleaseai/ast-grep-config`에 허용 목록 경로를 제안하세요.

## 호환성

- `@ast-grep/cli` `^0.45.3`
- Node.js `>=22.0.0`

Source: https://code-style.pages.dev/ko/ast-grep-config/index.mdx
