diff --git a/README.ko.md b/README.ko.md index b25bda5..d93fc84 100644 --- a/README.ko.md +++ b/README.ko.md @@ -17,13 +17,13 @@ PleaseAI 프로젝트를 위한 공유 코드 스타일 설정 모노레포 — ## `@pleaseai/eslint-config` -### 설치 +### eslint-config 설치 ```sh bun add -D @pleaseai/eslint-config eslint ``` -### 사용법 +### eslint-config 사용법 ```ts // eslint.config.ts @@ -51,12 +51,34 @@ export default pleaseai( ) ``` -### 기본값 +### eslint-config 기본값 - `stylistic`: `indent: 2`, `quotes: 'single'`, `semi: false` - `typescript: true` - `gitignore: true` +## `@pleaseai/ast-grep-config` + +### ast-grep-config 설치 + +```sh +bun add -D @pleaseai/ast-grep-config @ast-grep/cli +``` + +### ast-grep-config 사용법 + +```yaml +# sgconfig.yml +ruleDirs: + - node_modules/@pleaseai/ast-grep-config/rules +``` + +```sh +bunx ast-grep scan +``` + +모든 규칙은 경고(warning)로 배포됩니다. 규칙 목록과 위반을 고치는 방법은 [ast-grep Config 가이드](https://code-style.pages.dev/ko/ast-grep-config)를 참고하세요. + ## 개발 로컬에서 저장소를 설정하고 빌드·린트하는 방법은 [CONTRIBUTING.md의 Getting started](./CONTRIBUTING.md#getting-started)(영문)를 따르세요. diff --git a/README.md b/README.md index c0d2e19..6a877fa 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,13 @@ See the [code-style documentation site](https://code-style.pages.dev) for full g ## `@pleaseai/eslint-config` -### Installation +### eslint-config installation ```sh bun add -D @pleaseai/eslint-config eslint ``` -### Usage +### eslint-config usage ```ts // eslint.config.ts @@ -51,12 +51,34 @@ export default pleaseai( ) ``` -### Defaults +### eslint-config defaults - `stylistic`: `indent: 2`, `quotes: 'single'`, `semi: false` - `typescript: true` - `gitignore: true` +## `@pleaseai/ast-grep-config` + +### ast-grep-config installation + +```sh +bun add -D @pleaseai/ast-grep-config @ast-grep/cli +``` + +### ast-grep-config usage + +```yaml +# sgconfig.yml +ruleDirs: + - node_modules/@pleaseai/ast-grep-config/rules +``` + +```sh +bunx ast-grep scan +``` + +Every rule ships as a warning. See the [ast-grep Config guide](https://code-style.pages.dev/en/ast-grep-config) for the rule list and how to fix each violation. + ## Development To set up the repo, build, and lint locally, follow [Getting started in CONTRIBUTING.md](./CONTRIBUTING.md#getting-started). diff --git a/apps/docs/src/content/docs/en/ast-grep-config.mdx b/apps/docs/src/content/docs/en/ast-grep-config.mdx new file mode 100644 index 0000000..695b27f --- /dev/null +++ b/apps/docs/src/content/docs/en/ast-grep-config.mdx @@ -0,0 +1,184 @@ +--- +title: "ast-grep Config" +description: "ast-grep rules that keep a codebase navigable for coding agents." +sidebar: + order: 5 +--- +`@pleaseai/ast-grep-config` is a set of [ast-grep](https://ast-grep.github.io/) rules that keep a codebase navigable for coding agents: public symbols you can find by name, error types in a designated file, and no tests inside source files. It enforces layer 2 (structural rules) of [ADR-0022](https://github.com/chatbot-pf/engineering-standards/blob/main/docs/adr/0022-agent-navigable-code-organization-standard.md) for TypeScript, Dart, Kotlin, Java, and Rust. + +Every rule ships as a **warning**. Nothing here fails a build unless you raise a rule's severity in your own config. + +## Installation + + + +```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/cli`](https://ast-grep.github.io/) is a peer dependency that provides the `ast-grep` binary. Install it next to this package so `ast-grep` is on your project's bin path. + +With bun, add `@ast-grep/cli` to `trustedDependencies` so its postinstall step runs. Otherwise `ast-grep` prints a fallback warning on every call (`please-style check` is unaffected). + +```json title="package.json" +{ + "trustedDependencies": ["@ast-grep/cli"] +} +``` + + + +## Usage + +Point your project's `sgconfig.yml` at the rules: + +```yaml title="sgconfig.yml" +ruleDirs: + - node_modules/@pleaseai/ast-grep-config/rules +``` + +```bash +bunx ast-grep scan +``` + +Or scan with the package's own config without adding one: + +```bash +bunx ast-grep scan -c node_modules/@pleaseai/ast-grep-config/sgconfig.yml +``` + +## The Five Principles + +| Slug | Principle | +| --- | --- | +| `code-greppable-public-symbols` | Public symbols are named declarations, so one name search finds the definition and every use. | +| `code-filename-matches-primary-symbol` | A file with one public symbol is named after it (normalized to the language's file-name convention). | +| `code-error-types-in-dedicated-module` | A module's error types live in its designated error file or package. | +| `test-path-derivable-from-source` | Tests live under the toolchain's test root, at a path mirrored from the source they test. | +| `test-helpers-in-dedicated-location` | Helpers shared by several tests live in the designated helper location. | + +The checks run in two layers: + +- **Layer 2** — the ast-grep rules in this package, run with `ast-grep scan`. +- **Layer 3** — [`please-style check`](/en/cli#check), a path checker for what ast-grep cannot see (file names, test paths, and which helpers are shared). It runs the extraction rules in this package's `extract/` directory. `extract/` is not listed in `ruleDirs`, so its matches never appear in `ast-grep scan` output. + +## Rules + +| Rule | Slug | Language | +| --- | --- | --- | +| [`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 | + +Each rule has a README next to it with the reason, a wrong and a right example, and the steps to fix a violation. The warning message names the slug and the README path inside `node_modules`, so an agent can fix the violation from the message alone: + +```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 +``` + +### No default exports + +`ts-no-default-export` and `tsx-no-default-export` flag `export default …`, `export { foo as default }`, and `export { default } from './x'`. A default import lets every importer pick its own local name, so a search for the declaration's name misses those import sites. A named import must mention the exported name. + +```ts +// Wrong +export default class UserService {} + +// Right +export class UserService {} +``` + +### No glob re-exports + +`rust-no-glob-reexport` flags any `use` with a visibility modifier (`pub`, `pub(crate)`, `pub(super)`) that contains a `*`. Private glob imports such as `use super::*;` are not matched. Replace the glob with an explicit list of the items it exports today: + +```rust +// Wrong +pub use crate::model::*; + +// Right +pub use crate::model::{Account, User}; +``` + +### Error types in a dedicated module + +ast-grep has no type information, so the error rules match by name. For the class-based languages, a class is flagged when its supertype ends in `Error` or `Exception`, or when its own name ends in `Error` or `Exception` and it also has a supertype: + +- TypeScript / TSX: the `extends` superclass only. `implements` does not match, and a class named `*Error` or `*Exception` is flagged only when it has an `extends` clause. +- Java: the superclass only (`Throwable` also counts). `implements` does not match. +- Dart: the superclass or any implemented type. A class named `*Error` or `*Exception` needs a superclass or `implements` clause. +- Kotlin: any supertype (`Throwable` also counts), on `class` and `object` declarations. + +Rust flags a `struct` or `enum` whose name ends in `Error` (not `Exception`) or that has `#[derive(…Error)]`, plus any `impl Error for T` (including `std::error::Error` and `core::error::Error`). Each language has its own designated location: + +| Language | Error types live in | Also exempt | +| --- | --- | --- | +| TypeScript / TSX | `errors.ts` in the module directory | `*.d.ts`, `*.test.*`, `*.spec.*`, `test/`, `tests/`, `__tests__/` | +| Dart / Flutter | `errors.dart` in the library directory | `*_test.dart`, `test/`, `integration_test/`, `test_driver/` | +| Kotlin | `Errors.kt` in the package directory | `src/test/`, `src/testFixtures/`, source sets ending in `Test` | +| Java | an `error/` subpackage of the module | `src/test/`, `src/testFixtures/`, `src/androidTest/` | +| Rust | `error.rs` next to the module root (or an `error/` module) | integration tests under `tests/` | + +Only the location is checked — the error file may contain helpers and imports. + +### No in-source tests + +`ts-no-in-source-test` and `tsx-no-in-source-test` flag Vitest [in-source tests](https://vitest.dev/guide/in-source.html) (`if (import.meta.vitest) { … }`). A `test/**` glob cannot find them, and production builds need a bundler `define` to strip them. Move the block into a test file under the package's test root, at a path mirrored from the source: `src/math/add.ts` becomes `test/math/add.test.ts`. + +## Framework Files + +Files whose shape a framework dictates are excluded from `ts-no-default-export` and `tsx-no-default-export` through their `ignores` lists: + +- Type declarations: `*.d.ts`, `*.d.mts`, `*.d.cts` +- Config files: `*.config.ts` and `*.config.*.ts` (for example `vite.config.prod.ts`), in their `.mts`, `.cts`, and `.tsx` forms too +- Storybook stories (`*.stories.ts`, `*.stories.tsx`, …), `.vitepress/`, and `.storybook/` +- Nuxt 4: `app/pages/`, `app/layouts/`, `app/middleware/`, `app/plugins/`, plus `app/app.config.ts` and `app/router.options.ts` +- Nitro: `server/api/`, `server/routes/`, `server/middleware/`, `server/plugins/`, `server/tasks/` + +The full lists are in [`ts-no-default-export.yml`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/typescript/ts-no-default-export.yml) and [`tsx-no-default-export.yml`](https://github.com/pleaseai/code-style/blob/main/packages/ast-grep-config/rules/tsx/tsx-no-default-export.yml). No other rule exempts these paths, except type declarations, which `ts-error-outside-errors-file` and `tsx-error-outside-errors-file` also skip. + +Nuxt 3 root directories (`pages/`, `layouts/`, `middleware/`, and `plugins/` without `app/`) are **not** excluded: a glob such as `**/plugins/**` would also exempt every unrelated directory named `plugins`. ast-grep cannot override a shipped rule's `ignores`, so scope the rules from the command line instead — turn them off in the main scan and run them once more with your framework directories excluded: + +```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' +``` + +Put both commands in one package script (for example `lint:structure`) so CI and agents run the same thing. After migrating to the Nuxt 4 `app/` layout, replace the two-step workaround with a single plain `ast-grep scan`. Keeping only the first command would leave both rules turned off for every file. + + + +## Compatibility + +- `@ast-grep/cli` `^0.45.3` +- Node.js `>=22.0.0` diff --git a/apps/docs/src/content/docs/en/index.mdx b/apps/docs/src/content/docs/en/index.mdx index b83ca86..92bbffe 100644 --- a/apps/docs/src/content/docs/en/index.mdx +++ b/apps/docs/src/content/docs/en/index.mdx @@ -36,6 +36,12 @@ Shared `.editorconfig` for consistent editor settings. + + +ast-grep rules that keep a codebase navigable for coding agents. + + + One-command setup for eslint, prettier, editorconfig, and the `AGENTS.md` rules block. diff --git a/apps/docs/src/content/docs/ko/ast-grep-config.mdx b/apps/docs/src/content/docs/ko/ast-grep-config.mdx new file mode 100644 index 0000000..5f5eaf7 --- /dev/null +++ b/apps/docs/src/content/docs/ko/ast-grep-config.mdx @@ -0,0 +1,184 @@ +--- +title: "ast-grep Config" +description: "코딩 에이전트가 코드베이스를 쉽게 탐색하도록 돕는 ast-grep 규칙." +sidebar: + order: 5 +--- +`@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"] +} +``` + + + +## 사용법 + +프로젝트의 `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`을 한 번 실행하세요. 첫 번째 명령만 남기면 두 규칙이 모든 파일에서 꺼집니다. + + + +## 호환성 + +- `@ast-grep/cli` `^0.45.3` +- Node.js `>=22.0.0` diff --git a/apps/docs/src/content/docs/ko/index.mdx b/apps/docs/src/content/docs/ko/index.mdx index 047d5c7..1629c16 100644 --- a/apps/docs/src/content/docs/ko/index.mdx +++ b/apps/docs/src/content/docs/ko/index.mdx @@ -36,6 +36,12 @@ tableOfContents: false + + +코딩 에이전트가 코드베이스를 쉽게 탐색하도록 돕는 ast-grep 규칙. + + + eslint, prettier, editorconfig, 그리고 `AGENTS.md` 규칙 블록을 한 번에 설정.