Skip to content

Commit 374ea69

Browse files
update spec (#2)
1 parent 5d3832d commit 374ea69

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1154
-605
lines changed

.changeset/new-guests-cough.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"urlspec-vscode-extension": minor
3+
"@urlspec/language": minor
4+
"@urlspec/builder": minor
5+
---
6+
7+
BREAKING CHANGE: update spec

CLAUDE.md

Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
# URLSpec - Claude Code Guide
2+
3+
## 최근 주요 변경사항
4+
5+
### ✨ 새로운 기능
6+
- **Endpoint 선언**: 파일 레벨에서 `endpoint` 키워드로 API 엔드포인트 설정 가능
7+
- **주석 지원**: `//` 형태의 한 줄 주석 완전 지원
8+
- **테스트 픽스처 구조화**: 30개 이상의 `.urlspec` 픽스처 파일로 테스트 관리
9+
10+
### 🔧 네이밍 규칙 변경
11+
- **Namespace**: 따옴표 제거, camelCase만 허용 (`"app-name"``appName`)
12+
- **Page 이름**: camelCase만 허용 (`detail_view``detailView`)
13+
- **ParamType 이름**: camelCase만 허용 (`sort_order``sortOrder`)
14+
- **Parameter 이름**: snake_case 유지 (`job_id`, `utm_source`)
15+
16+
### 📁 환경별 Endpoint 관리
17+
파일 단위로 endpoint를 선언하므로, 환경별로 다른 파일 사용을 권장:
18+
- `jobs.dev.urlspec`, `jobs.staging.urlspec`, `jobs.prod.urlspec`
19+
20+
---
21+
22+
## 프로젝트 개요
23+
24+
URLSpec은 웹 애플리케이션의 URL 구조를 타입 안전하게 정의하고 문서화하기 위한 DSL(Domain-Specific Language)입니다. URL 문자열을 하드코딩하는 대신, 선언적으로 URL 아키텍처를 정의하여 타입 안전성과 유지보수성을 제공합니다.
25+
26+
### 해결하는 문제
27+
- 타입 오류와 URL 파라미터 오타로 인한 런타임 에러 방지
28+
- 쿼리 파라미터와 경로 세그먼트에 대한 타입 체킹 제공
29+
- URL 구조에 대한 단일 진실 공급원(Single Source of Truth) 제공
30+
- 대규모 코드베이스에서 URL 변경 시 리팩토링 용이성 향상
31+
32+
## 아키텍처
33+
34+
이 프로젝트는 Yarn Workspaces를 사용하는 모노레포 구조입니다.
35+
36+
```
37+
urlspec/
38+
├── packages/
39+
│ ├── language/ # 핵심 언어 구현 (Langium 기반)
40+
│ ├── builder/ # 프로그래매틱 API
41+
│ └── urlspec-vscode-extension/ # VS Code 확장
42+
└── examples/ # 예제 파일
43+
```
44+
45+
### 패키지별 역할
46+
47+
#### 1. @urlspec/language
48+
**핵심 언어 구현 패키지**
49+
50+
- **주요 기술**: Langium 4.1.3 (언어 프레임워크)
51+
- **책임**: URLSpec 문법의 파싱, 검증, 리졸빙
52+
- **핵심 파일**:
53+
- `src/urlspec.langium` - 언어 문법 정의
54+
- `src/parser.ts` - 파서 진입점
55+
- `src/resolver.ts` - AST를 사용자 친화적 타입으로 변환
56+
- `src/validator.ts` - 커스텀 검증 규칙
57+
- `src/printer.ts` - AST를 `.urlspec` 포맷으로 출력
58+
- `src/ast-builder.ts` - AST 노드를 프로그래매틱하게 생성
59+
60+
**작업 시 참고사항**:
61+
- 문법 변경 시 `yarn langium:generate`로 파서 재생성 필요
62+
- `src/__generated__/` 디렉토리는 자동 생성되므로 직접 수정 금지
63+
- 새로운 검증 규칙은 `validator.ts``URLSpecValidator` 클래스에 추가
64+
65+
#### 2. @urlspec/builder
66+
**프로그래매틱 API 패키지**
67+
68+
- **책임**: 코드로 URLSpec 문서를 생성할 수 있는 빌더 API 제공
69+
- **핵심 파일**:
70+
- `src/index.ts` - `URLSpec` 클래스와 빌더 API
71+
- **주요 메서드**:
72+
- `setNamespace(name)` - namespace 설정 (camelCase)
73+
- `setEndpoint(url)` - endpoint 설정 (선택적)
74+
- `addParamType(name, type)` - param type 추가 (camelCase)
75+
- `addGlobalParam(param)` - global parameter 추가 (snake_case)
76+
- `addPage(page)` - page 추가 (camelCase 이름, snake_case 파라미터)
77+
- `toString()` - .urlspec 형식 문자열로 변환
78+
- `writeFile(path)` - 파일로 저장
79+
80+
**작업 시 참고사항**:
81+
- 파일 경로 보안 검증 로직이 포함되어 있음 (경로 탐색 공격 방지)
82+
- `@urlspec/language`에 의존하여 AST 생성 및 프린팅 수행
83+
84+
#### 3. urlspec-vscode-extension
85+
**VS Code 통합 패키지**
86+
87+
- **책임**: IDE 지원 (문법 강조, 검증, 언어 서버)
88+
- **핵심 파일**:
89+
- `src/extension.ts` - 확장 진입점
90+
- `src/language-server.ts` - 언어 서버 구현
91+
- `syntaxes/urlspec.tmLanguage.json` - TextMate 문법
92+
93+
**작업 시 참고사항**:
94+
- 개발 시 `yarn watch` 사용
95+
- 확장 테스트 시 F5로 Extension Development Host 실행
96+
97+
## 개발 워크플로우
98+
99+
### 초기 설정
100+
101+
```bash
102+
# 의존성 설치
103+
yarn install
104+
105+
# 전체 빌드 (패키지 의존성 순서대로)
106+
yarn build
107+
```
108+
109+
### 개발 사이클
110+
111+
**언어 문법 수정 시**:
112+
```bash
113+
cd packages/language
114+
# 1. urlspec.langium 파일 수정
115+
# 2. 파서 재생성
116+
yarn langium:generate
117+
# 3. 테스트 실행
118+
yarn test
119+
```
120+
121+
**빌더 API 수정 시**:
122+
```bash
123+
cd packages/builder
124+
yarn test:watch # 테스트 감시 모드
125+
```
126+
127+
**VS Code 확장 개발 시**:
128+
```bash
129+
cd packages/urlspec-vscode-extension
130+
yarn watch # 변경사항 감시
131+
# VS Code에서 F5 눌러 Extension Development Host 실행
132+
```
133+
134+
### 코드 품질
135+
136+
```bash
137+
# 포맷 체크 및 수정 (Biome 사용)
138+
yarn format
139+
```
140+
141+
## 주요 파일 및 디렉토리
142+
143+
### 언어 정의
144+
- `packages/language/src/urlspec.langium` - **가장 중요**: 언어 문법 정의
145+
- 문법 변경 시 파서/AST 타입이 자동으로 재생성됨
146+
- NamespaceDeclaration, EndpointDeclaration, ParamTypeDeclaration, PageDeclaration 등의 규칙 정의
147+
- `hidden terminal SL_COMMENT`로 주석(`//`) 지원
148+
149+
### 타입 정의
150+
- `packages/language/src/resolved-types.ts` - 사용자 대면 타입 정의
151+
- `ResolvedURLSpec`, `ResolvedPage`, `ResolvedParameter`
152+
- `packages/language/src/__generated__/ast.ts` - Langium이 생성한 AST 타입
153+
154+
### 핵심 로직
155+
- `packages/language/src/resolver.ts` - AST → 리졸브된 타입 변환
156+
- 타입 참조 해석
157+
- 전역 파라미터 병합
158+
- 주석에서 설명(description) 추출 (// 주석은 `hidden` terminal로 파싱됨)
159+
160+
### 테스트
161+
- `packages/language/test/` - 언어 패키지 테스트
162+
- `test/fixtures/*.urlspec` - 테스트용 URLSpec 파일들 (30개 이상)
163+
- `parser.test.ts`, `resolver.test.ts`, `printer.test.ts`, `validation.test.ts`
164+
- `packages/builder/test/` - 빌더 패키지 테스트
165+
166+
## 언어 문법 가이드
167+
168+
### 기본 구조
169+
170+
```urlspec
171+
// namespace는 camelCase로 작성 (따옴표 없음)
172+
namespace jobs;
173+
174+
// endpoint는 선택적으로 파일 레벨에서 한 번만 선언 가능
175+
endpoint "https://api.example.com";
176+
177+
// 파라미터 타입 정의 (재사용 가능) - camelCase로 작성
178+
param sortOrder = "recent" | "popular";
179+
param jobStatus = "active" | "closed";
180+
181+
// 전역 파라미터 (모든 페이지에 적용) - snake_case로 작성
182+
global {
183+
utm_source?: string;
184+
referrer?: string;
185+
}
186+
187+
// 페이지 정의 - 페이지 이름은 camelCase
188+
page list = /jobs {
189+
sort?: sortOrder;
190+
category?: string;
191+
}
192+
193+
page detail = /jobs/:job_id {
194+
job_id: string; // 파라미터는 snake_case
195+
preview?: "true" | "false";
196+
}
197+
```
198+
199+
### 타입 시스템
200+
201+
- `string` - 문자열 타입
202+
- `"literal"` - 문자열 리터럴
203+
- `"a" | "b" | "c"` - 유니온 타입
204+
- `paramTypeName` - 타입 참조 (camelCase)
205+
206+
### 환경별 Endpoint 관리
207+
208+
Endpoint 설정은 파일 레벨에서 선언하므로, 환경별로 다른 파일을 사용하는 패턴을 권장합니다:
209+
210+
```
211+
specs/
212+
├── jobs.dev.urlspec # endpoint "https://dev-api.example.com";
213+
├── jobs.staging.urlspec # endpoint "https://staging-api.example.com";
214+
└── jobs.prod.urlspec # endpoint "https://api.example.com";
215+
```
216+
217+
각 파일은 동일한 namespace와 page 정의를 가지지만 endpoint만 다르게 설정하여 환경별로 사용할 수 있습니다.
218+
219+
### 검증 규칙
220+
221+
1. **Namespace**: camelCase만 허용 (예: `jobs`, `userSettings`)
222+
2. **Page 이름**: camelCase만 허용 (예: `list`, `detailView`)
223+
3. **ParamType 이름**: camelCase만 허용 (예: `sortOrder`, `jobStatus`)
224+
4. **Parameter 이름**: snake_case만 허용 (예: `job_id`, `utm_source`)
225+
5. **경로 파라미터**: `:param_name` 형태는 반드시 파라미터 블록에 선언되어야 함
226+
6. **문자열 리터럴**: 유니온 타입과 문자열 리터럴은 따옴표로 감싸야 함
227+
7. **Endpoint**: 파일당 한 번만 선언 가능 (선택적)
228+
229+
## 개발 시 주의사항
230+
231+
### 문법 변경 시
232+
1. `urlspec.langium` 파일 수정
233+
2. **반드시** `yarn langium:generate` 실행
234+
3. 생성된 AST 타입에 맞춰 resolver, validator 코드 업데이트
235+
4. 테스트 작성/업데이트
236+
237+
### 타입 안전성
238+
- `packages/language/src/resolved-types.ts``src/__generated__/ast.ts`의 타입이 다름
239+
- AST 타입: Langium이 생성한 내부 표현
240+
- Resolved 타입: 사용자 대면 API
241+
242+
### 보안
243+
- `packages/builder`의 파일 쓰기 기능은 경로 검증 포함
244+
- 경로 탐색 공격 방지 로직 유지 필수
245+
246+
### 테스트
247+
- 언어 변경 시 파서, 리졸버, 프린터 테스트 모두 확인
248+
- 빌더 API 변경 시 파일 생성 테스트 확인
249+
- **테스트 픽스처 관리**:
250+
- `packages/language/test/fixtures/` 디렉토리에 `.urlspec` 파일로 관리
251+
- 테스트 코드는 `parseFile(fixture("name.urlspec"))` 패턴 사용
252+
- 인라인 문자열보다 픽스처 파일 사용으로 유지보수성 향상
253+
254+
## 테스트 실행
255+
256+
```bash
257+
# 전체 테스트
258+
yarn test
259+
260+
# 패키지별 테스트
261+
cd packages/language && yarn test
262+
cd packages/builder && yarn test
263+
264+
# 감시 모드
265+
yarn test:watch
266+
```
267+
268+
## 빌드 및 배포
269+
270+
### 로컬 빌드
271+
```bash
272+
# 전체 빌드
273+
yarn build
274+
275+
# 패키지별 빌드
276+
cd packages/language && yarn build
277+
cd packages/builder && yarn build
278+
cd packages/urlspec-vscode-extension && yarn build
279+
```
280+
281+
### 버전 관리
282+
- Changesets 사용 (`@changesets/cli`)
283+
- 변경사항 기록: `yarn changeset`
284+
- 버전 업데이트: `yarn changeset version`
285+
286+
### 배포
287+
- GitHub Actions로 자동 배포 (`.github/workflows/deploy-packages.yml`)
288+
- npm에 `@urlspec/` 네임스페이스로 퍼블리시
289+
290+
## 기술 스택
291+
292+
| 도구 | 용도 | 버전 |
293+
|------|------|------|
294+
| Langium | 언어 프레임워크 | 4.1.3 |
295+
| TypeScript | 프로그래밍 언어 | 5.9.3 |
296+
| Vitest | 테스트 러너 | 3.0.5 |
297+
| Biome | 포매터/린터 | 2.3.11 |
298+
| ultra-runner | 모노레포 태스크 러너 | 3.10.5 |
299+
| tsdown | 번들러 | 0.20.0-beta.3 |
300+
| Yarn | 패키지 매니저 | 4.12.0+ |
301+
302+
## Builder API 예제
303+
304+
```typescript
305+
import { URLSpec } from '@urlspec/builder';
306+
307+
const spec = new URLSpec();
308+
309+
// Namespace 설정 (camelCase)
310+
spec.setNamespace('jobs');
311+
312+
// Endpoint 설정 (선택적)
313+
spec.setEndpoint('https://api.example.com');
314+
315+
// ParamType 정의 (camelCase)
316+
spec.addParamType('sortOrder', ['recent', 'popular', 'trending']);
317+
spec.addParamType('jobStatus', ['active', 'closed', 'draft']);
318+
319+
// Global 파라미터 추가 (snake_case)
320+
spec.addGlobalParam({
321+
name: 'utm_source',
322+
type: 'string',
323+
optional: true,
324+
});
325+
326+
// 페이지 추가 (camelCase 이름, snake_case 파라미터)
327+
spec.addPage({
328+
name: 'list',
329+
path: '/jobs',
330+
parameters: [
331+
{ name: 'category', type: 'string', optional: true },
332+
{ name: 'sort', type: 'sortOrder' },
333+
],
334+
});
335+
336+
spec.addPage({
337+
name: 'detail',
338+
path: '/jobs/:job_id',
339+
parameters: [
340+
{ name: 'job_id', type: 'string' },
341+
{ name: 'preview', type: ['true', 'false'], optional: true },
342+
],
343+
});
344+
345+
// .urlspec 형식으로 출력
346+
console.log(spec.toString());
347+
348+
// 파일로 저장
349+
await spec.writeFile('./output.urlspec');
350+
```
351+
352+
## 디버깅 팁
353+
354+
### 파서 문제 디버깅
355+
```typescript
356+
import { parse } from '@urlspec/language';
357+
358+
const result = await parse(source);
359+
console.log(result.diagnostics); // 검증 에러 확인
360+
console.log(result.value); // AST 출력
361+
```
362+
363+
### 리졸버 문제 디버깅
364+
```typescript
365+
import { resolve } from '@urlspec/language';
366+
367+
const resolved = await resolve(source);
368+
console.log(resolved.pages); // 리졸브된 페이지 구조 확인
369+
```
370+
371+
### VS Code 확장 디버깅
372+
1. `packages/urlspec-vscode-extension`에서 F5 누르기
373+
2. Extension Development Host에서 `.urlspec` 파일 열기
374+
3. Output 패널에서 "URLSpec Language Server" 로그 확인
375+
376+
## 참고 자료
377+
378+
- [Langium 문서](https://langium.org/)
379+
- [Language Server Protocol](https://microsoft.github.io/language-server-protocol/)
380+
- [TextMate Grammar](https://macromates.com/manual/en/language_grammars)
381+
382+
## 라이센스
383+
384+
MIT License

0 commit comments

Comments
 (0)