Initial commit

This commit is contained in:
2026-06-10 12:49:53 +09:00
commit b159597559
707 changed files with 551154 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
---
name: "agent-browser"
description: "브라우저 자동화 CLI를 사용해 웹사이트를 탐색하고 조작합니다. 페이지 이동, 폼 입력, 클릭, 스크린샷, 데이터 추출, 웹앱 테스트가 필요할 때 호출합니다."
---
# Agent Browser
에이전트를 위한 빠른 브라우저 자동화 CLI 가이드입니다. 웹사이트 탐색, 폼 입력, 버튼 클릭, 스크린샷 촬영, 데이터 추출, 웹앱 테스트, 탐색적 QA 등에 사용합니다.
## 언제 사용할지
다음과 같은 요청에서 우선 사용합니다.
- 웹사이트를 열어 달라고 할 때
- 폼을 입력하거나 버튼을 클릭해야 할 때
- 페이지 스크린샷이 필요할 때
- 웹페이지 데이터를 추출하거나 스크래핑할 때
- 웹앱을 실제 브라우저에서 테스트할 때
- 로그인, QA, 버그 재현, 탐색적 테스트가 필요할 때
Electron 기반 데스크톱 앱이나 Slack 자동화 같은 확장 작업에도 활용할 수 있습니다.
## 시작 방법
`agent-browser` 명령을 바로 사용하기 전에, 설치된 버전에 맞는 실제 가이드를 CLI에서 불러옵니다.
```bash
agent-browser skills get core
```
전체 명령과 템플릿까지 포함해 보고 싶다면:
```bash
agent-browser skills get core --full
```
이 스킬 문서는 시작점 역할만 합니다. 실제 사용 절차와 최신 명령 형식은 항상 CLI가 제공하는 가이드를 기준으로 확인합니다.
## 특수 가이드
작업 성격에 따라 아래 보조 가이드를 불러올 수 있습니다.
- `agent-browser skills get electron`
- `agent-browser skills get slack`
- `agent-browser skills get dogfood`
- `agent-browser skills get vercel-sandbox`
- `agent-browser skills get agentcore`
사용 가능한 전체 목록은 아래 명령으로 확인합니다.
```bash
agent-browser skills list
```
## 기본 사용 흐름
1. 먼저 `agent-browser skills get core`로 현재 버전 가이드를 읽습니다.
2. 작업이 웹 브라우저인지, Electron인지, Slack인지 성격을 구분합니다.
3. 필요하면 해당 특수 가이드를 추가로 읽습니다.
4. 세션을 열고 탐색, 선택, 입력, 클릭, 추출 같은 실제 작업을 진행합니다.
5. 스크린샷, 상태 저장, 기록 기능이 필요하면 그 옵션을 함께 사용합니다.
## 장점
- 빠른 네이티브 CLI 기반 동작
- Chrome/Chromium 제어
- 접근성 트리 기반 스냅샷과 안정적인 요소 참조
- 세션 유지, 인증 저장, 상태 지속성 지원
- 영상 기록 및 다양한 특수 자동화 시나리오 지원
## 운영 원칙
- 내장 웹 도구보다 `agent-browser`가 더 적합한 작업이면 이를 우선 사용합니다.
- 현재 설치된 버전의 CLI가 제공하는 가이드를 기준으로 작업합니다.
- 오래된 문서 기억보다, 실행 중인 버전의 `skills get` 결과를 신뢰합니다.
## 언제 특히 유용한가
- 실제 브라우저 상호작용이 길거나 반복적일 때
- 접근성 트리 기준의 안정적인 요소 선택이 필요할 때
- 상태 지속, 인증, 녹화, 세션 관리가 중요한 테스트일 때
- 단순 스크래핑이 아니라 탐색적 QA나 실제 사용자 흐름 재현이 필요할 때
## 안티 패턴
- 설치된 버전을 확인하지 않고 예전 명령 기억으로 바로 실행하는 방식
- 일반 웹 도구로 충분한 작업인데 굳이 복잡한 세션을 여는 방식
- 작업 성격이 특수 가이드 대상인데 core만 읽고 끝내는 방식
## 기대 결과
이 스킬을 적용한 결과는 다음을 만족해야 합니다.
- 현재 설치된 버전 기준으로 정확한 사용 절차를 따른다
- 작업 유형에 맞는 특수 가이드를 선택한다
- 브라우저 자동화가 실제 목표에 맞게 안정적으로 수행된다
+191
View File
@@ -0,0 +1,191 @@
---
name: "brainstorming"
description: "구현 전에 아이디어를 질문과 설계안으로 구체화합니다. 기능 추가, 동작 변경, 신규 개발처럼 창의적 작업을 시작하기 전에 반드시 호출합니다."
---
# 아이디어를 설계로 구체화하기
자연스러운 협업형 대화를 통해 아이디어를 완성도 높은 설계와 명세로 바꿉니다.
먼저 현재 프로젝트 문맥을 이해한 뒤, 질문을 한 번에 하나씩 하면서 아이디어를 구체화합니다. 무엇을 만들지 충분히 이해했다면 설계를 제시하고 사용자 승인을 받습니다.
<HARD-GATE>
설계를 제시하고 사용자 승인을 받기 전까지는 구현 스킬 호출, 코드 작성, 프로젝트 스캐폴딩, 기타 구현 행동을 해서는 안 됩니다. 이 규칙은 작업이 얼마나 단순해 보이든 항상 적용됩니다.
</HARD-GATE>
## 안티 패턴: "이건 너무 단순해서 설계가 필요 없다"
모든 작업은 이 과정을 거쳐야 합니다. 할 일 목록, 단일 함수 유틸리티, 설정 변경도 예외가 아닙니다. "단순한" 작업일수록 검증되지 않은 가정 때문에 불필요한 재작업이 생기기 쉽습니다. 설계는 짧아도 되지만, 반드시 제시하고 승인을 받아야 합니다.
## 체크리스트
아래 항목별로 작업을 만들고, 순서대로 완료해야 합니다.
1. **프로젝트 문맥 탐색** - 파일, 문서, 최근 커밋 확인
2. **시각 보조 도구 제안** - 시각적 질문이 예상되면 별도 메시지로 제안
3. **명확화 질문 진행** - 한 번에 하나씩 질문하며 목적, 제약, 성공 기준 파악
4. **2~3개 접근법 제안** - 트레이드오프와 추천안 포함
5. **설계 제시** - 복잡도에 맞춰 섹션별로 설명하고 승인 받기
6. **설계 문서 작성** - `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`에 저장
7. **명세 자체 점검** - placeholder, 모순, 모호성, 범위 확인
8. **사용자 문서 검토** - 구현 전 설계 문서 검토 요청
9. **구현 단계 전환** - 다음 단계로 `writing-plans` 스킬 호출
## 프로세스 흐름
기본 흐름은 아래와 같습니다.
1. 현재 프로젝트 문맥을 탐색합니다.
2. 필요한 경우 시각 보조 도구를 별도 메시지로 제안합니다.
3. 질문을 한 번에 하나씩 하며 요구를 구체화합니다.
4. 2~3개의 접근법을 비교하고 추천안을 제시합니다.
5. 설계를 섹션 단위로 설명하며 단계적으로 승인을 받습니다.
6. 승인된 설계를 문서로 저장합니다.
7. 문서를 스스로 점검해 빈칸, 모순, 모호함을 제거합니다.
8. 사용자에게 문서 검토를 요청합니다.
9. 승인이 끝나면 다음 단계로 `writing-plans`를 호출합니다.
## 프로세스
**아이디어 이해**
- 먼저 현재 프로젝트 상태를 확인합니다.
- 요청이 여러 독립 하위 시스템을 포함하면, 세부 질문 전에 먼저 분해가 필요한지 판단합니다.
- 하나의 명세로 다루기 너무 크다면 하위 프로젝트로 나누고, 첫 번째 하위 프로젝트만 일반 설계 흐름으로 진행합니다.
- 적절한 범위라면 질문을 한 번에 하나씩 하며 구체화합니다.
- 가능하면 객관식 질문을 우선 사용하되, 필요하면 서술형도 사용합니다.
- 각 메시지에는 질문 하나만 포함합니다.
- 목적, 제약 조건, 성공 기준을 이해하는 데 집중합니다.
- 너무 일찍 구현 방향으로 뛰어들지 말고, 범위와 기대 결과를 먼저 고정합니다.
- "간단해 보인다"는 이유로 질문 단계를 생략하지 않습니다.
**접근법 탐색**
- 서로 다른 2~3개의 접근법을 제안합니다.
- 각 접근법의 장단점과 추천 이유를 함께 설명합니다.
- 추천안을 먼저 제시하고, 왜 그 선택이 적합한지 설명합니다.
- 접근법은 기능 관점뿐 아니라 유지보수, 테스트 용이성, 사용자 경험까지 함께 비교합니다.
**설계 제시**
- 무엇을 만들지 충분히 이해했다면 설계를 제시합니다.
- 각 섹션은 복잡도에 맞게 짧게 또는 자세히 설명합니다.
- 각 섹션 뒤에는 지금까지 맞는지 확인을 요청합니다.
- 아키텍처, 구성요소, 데이터 흐름, 오류 처리, 테스트를 다룹니다.
- 이해되지 않는 부분이 있으면 다시 질문하고 명확히 합니다.
- 한 번에 모든 내용을 밀어 넣기보다, 사용자가 따라올 수 있는 단위로 나눠 검증합니다.
**격리와 명확성을 고려한 설계**
- 시스템을 명확한 목적을 가진 작은 단위로 나눕니다.
- 각 단위는 잘 정의된 인터페이스로 통신하고, 독립적으로 이해 및 테스트 가능해야 합니다.
- 각 단위에 대해 "무엇을 하는가, 어떻게 사용하는가, 무엇에 의존하는가"를 설명할 수 있어야 합니다.
- 내부 구현을 몰라도 역할을 이해할 수 있어야 하며, 내부를 바꿔도 소비자가 깨지지 않아야 합니다.
- 파일이 지나치게 커지면 책임이 과도하게 섞였다는 신호로 봅니다.
**기존 코드베이스에서 작업할 때**
- 변경 제안 전에 현재 구조와 패턴을 먼저 탐색합니다.
- 현재 작업에 영향을 주는 구조적 문제는 설계에 포함해 개선할 수 있습니다.
- 현재 목표와 무관한 리팩터링은 제안하지 않습니다.
## 설계 제시 규칙
- 섹션별로 끊어서 설명하고, 각 섹션 뒤에 확인을 받습니다.
- 설계는 복잡도에 맞춰 짧게 또는 자세히 조절합니다.
- 구조, 데이터 흐름, 오류 처리, 테스트 전략을 빠뜨리지 않습니다.
- 사용자가 "지금까지 맞다"고 확인하기 전까지 다음 단계로 밀어붙이지 않습니다.
## 금지 사항
- 설계 승인 전에 구현 스킬 호출
- 설계 승인 전에 코드 작성
- 질문 여러 개를 한 번에 던지는 방식
- 대안 비교 없이 단일 해법만 제시하는 방식
- 현재 목표와 무관한 대형 리팩터링 제안
- 사용자 검토 없이 바로 구현 계획 또는 구현으로 넘어가는 방식
## 설계 후 단계
**문서화**
- 승인된 설계를 `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`에 작성합니다.
- 사용자가 다른 문서 위치를 선호하면 그 경로를 우선합니다.
- 가능하면 명확하고 간결한 문체를 유지합니다.
**명세 자체 점검**
설계 문서를 작성한 뒤 아래 항목을 빠르게 확인합니다.
1. **Placeholder 점검** - `TBD`, `TODO`, 미완성 섹션, 모호한 요구사항이 있는지 확인
2. **내부 일관성 점검** - 섹션끼리 모순되지 않는지 확인
3. **범위 점검** - 단일 구현 계획으로 충분한 범위인지 확인
4. **모호성 점검** - 여러 해석이 가능한 요구사항을 하나로 명확히 고정
문제가 있으면 문서 안에서 바로 수정하고 진행합니다.
**사용자 검토 게이트**
설계 검토가 끝나면, 구현 계획으로 넘어가기 전에 사용자에게 작성된 명세 문서를 검토해 달라고 요청합니다.
예시 문구:
> 명세를 `<path>` 에 작성했습니다. 구현 계획을 쓰기 전에 변경하고 싶은 점이 있는지 검토해 주세요.
사용자가 승인할 때까지 기다립니다. 변경 요청이 있으면 수정하고 다시 점검합니다.
**구현 전환**
- 다음 단계에서는 `writing-plans` 스킬을 호출합니다.
- 다른 구현 스킬을 먼저 호출하지 않습니다.
## 기대 결과
이 스킬의 결과물은 다음을 만족해야 합니다.
- 사용자 의도가 구조화된 설계 문장으로 정리되어 있어야 합니다.
- 구현 전에 범위와 성공 기준이 합의되어 있어야 합니다.
- 설계 문서만 읽어도 다음 단계에서 무엇을 구현할지 알 수 있어야 합니다.
- 설계 문서는 placeholder 없이 구체적이어야 합니다.
## 핵심 원칙
- **한 번에 한 질문** - 여러 질문을 한꺼번에 던지지 않습니다.
- **객관식 우선** - 답하기 쉬운 형식을 우선합니다.
- **YAGNI 준수** - 불필요한 기능은 설계에서 제거합니다.
- **대안 비교** - 항상 2~3개의 접근법을 제시합니다.
- **점진적 검증** - 설계를 제시하고 승인받은 뒤 다음으로 진행합니다.
- **유연한 명확화** - 이해가 부족하면 다시 질문합니다.
## 안티 패턴 신호
다음 생각이 들면 흐름을 다시 점검합니다.
- 이건 너무 간단해서 설계가 필요 없다
- 구현하면서 알아가도 된다
- 사용자 의도는 아마 이럴 것이다
- 설계 문서는 나중에 써도 된다
- 구현 스킬부터 불러도 큰 문제는 없다
이런 생각은 대부분 브레인스토밍 단계를 건너뛰려는 신호입니다.
## 시각 보조 도구
목업, 다이어그램, 시각 옵션을 보여주는 브라우저 기반 보조 수단입니다. 이는 별도 모드가 아니라 필요할 때 사용하는 도구입니다.
**제안 시점**
앞으로의 질문이 시각 요소를 포함할 가능성이 높다면, 아래 문구를 반드시 **단독 메시지**로 제안합니다.
> 지금 논의하는 내용 중 일부는 웹 브라우저에서 직접 보여드리면 더 이해하기 쉬울 수 있습니다. 진행하면서 목업, 다이어그램, 비교안 같은 시각 자료를 준비할 수 있습니다. 아직 새 기능이라 토큰 사용량이 많을 수 있는데, 사용해 보시겠어요? (로컬 URL 열기 필요)
이 제안 메시지에는 다른 질문, 요약, 설명을 섞지 않습니다. 사용자의 답변을 기다린 뒤 계속 진행합니다.
**질문별 판단**
사용자가 수락했더라도 모든 질문을 브라우저로 처리하지는 않습니다. 매 질문마다 "읽는 것보다 보는 것이 더 이해하기 쉬운가?"를 기준으로 판단합니다.
- 브라우저 사용: 목업, 와이어프레임, 레이아웃 비교, 아키텍처 다이어그램 같은 시각 중심 내용
- 터미널 사용: 요구사항 질문, 개념적 선택지, 트레이드오프 설명, 범위 결정 같은 텍스트 중심 내용
자세한 사용법은 [visual-companion.md](./visual-companion.md)를 참고합니다.
@@ -0,0 +1,68 @@
# 시각 보조 도구 가이드
브레인스토밍 중 목업, 다이어그램, 비교안을 보여주기 위한 브라우저 기반 시각 보조 가이드입니다.
## 언제 사용할지
세션 단위가 아니라 질문 단위로 판단합니다. 기준은 하나입니다. **읽는 것보다 보는 것이 더 이해하기 쉬운가?**
**브라우저를 사용할 때**
- UI 목업, 와이어프레임, 레이아웃, 내비게이션 구조
- 시스템 구성도, 데이터 흐름도, 관계도
- 레이아웃이나 스타일의 시각적 비교
- 간격, 시각적 위계, 분위기 같은 디자인 완성도 논의
- 상태 전이, 흐름도, 엔터티 관계처럼 공간적 관계가 중요한 설명
**터미널을 사용할 때**
- 요구사항과 범위 질문
- 개념적 A/B/C 선택
- 장단점 비교와 트레이드오프 정리
- API 설계, 데이터 모델링, 구조 선택 같은 기술 의사결정
- 시각 취향이 아니라 언어 설명이 필요한 명확화 질문
UI 주제에 대한 질문이라고 해서 자동으로 시각 질문이 되는 것은 아닙니다. "어떤 종류의 위저드를 원하나요?"는 개념 질문이고, "이 위저드 레이아웃 중 무엇이 더 맞나요?"는 시각 질문입니다.
## 진행 방식
서버는 HTML 파일이 저장되는 디렉터리를 감시하고 가장 최근 파일을 브라우저에 제공합니다. 화면 내용은 `screen_dir`에 기록하고, 사용자의 클릭/선택 결과는 `state_dir/events`에 저장됩니다.
**콘텐츠 조각과 전체 문서**
- HTML이 `<!DOCTYPE` 또는 `<html`로 시작하면 전체 문서로 그대로 제공합니다.
- 그렇지 않으면 서버가 기본 프레임 템플릿으로 감싸서 보여줍니다.
- 기본적으로는 전체 HTML 문서보다 **콘텐츠 조각** 작성 방식을 사용합니다.
## 세션 시작
- 서버를 시작하고 응답에서 `url`, `screen_dir`, `state_dir`를 저장합니다.
- 사용자에게 URL을 열어 달라고 안내합니다.
- 가능하면 프로젝트 루트를 기준으로 실행해 결과물이 프로젝트 안에 유지되게 합니다.
- 환경상 URL 접근이 어렵다면 호스트 설정을 조정합니다.
## 반복 루프
1. 서버가 살아 있는지 확인하고 `screen_dir`에 새 HTML 파일을 씁니다.
2. 사용자에게 URL과 현재 화면에 무엇이 보이는지 짧게 설명합니다.
3. 사용자가 터미널에서 응답하면 `state_dir/events`를 읽어 브라우저 상호작용을 확인합니다.
4. 피드백에 따라 현재 화면을 수정하거나 다음 질문으로 넘어갑니다.
5. 다음 단계가 시각 자료가 아니라면 대기 화면을 밀어 넣어 오래된 화면이 남지 않게 합니다.
## 작성 원칙
- 파일명은 의미 있게 짓습니다. 예: `layout.html`, `visual-style.html`
- 같은 파일명을 재사용하지 않습니다.
- 한 화면에는 2~4개 선택지만 둡니다.
- 질문 자체를 화면에 명확히 적습니다.
- 레이아웃 검토에는 와이어프레임, 완성도 검토에는 더 실제적인 시안을 사용합니다.
- 필요한 경우 실제 콘텐츠를 사용하고, 불필요한 정교함은 피합니다.
## 이벤트 해석
브라우저 클릭 이벤트는 `state_dir/events`에 JSON Lines 형식으로 기록됩니다. 마지막 선택이 최종 선택인 경우가 많지만, 선택 흐름 전체가 사용자의 망설임이나 선호를 보여줄 수 있습니다.
## 정리
- 세션 종료 시 서버를 중지합니다.
- 프로젝트 기반 세션이라면 결과물은 이후 참고를 위해 남겨둘 수 있습니다.
+132
View File
@@ -0,0 +1,132 @@
---
name: "find-skills"
description: "필요한 기능을 제공하는 커뮤니티 스킬을 검색하고 설치하도록 돕습니다. 특정 작업용 스킬이 있는지 찾거나 에이전트 기능을 확장하고 싶을 때 호출합니다."
---
# 스킬 찾기
이 스킬은 공개 에이전트 스킬 생태계에서 적절한 스킬을 찾고 설치하는 과정을 안내합니다.
## 언제 사용할지
다음과 같은 요청에서 사용합니다.
- X를 어떻게 하냐고 묻는데, 이미 해당 작업용 스킬이 있을 가능성이 있을 때
- 특정 도메인용 스킬을 찾아 달라고 할 때
- 전문 기능을 제공할 수 있는 스킬이 있는지 궁금해할 때
- 에이전트 기능을 확장하고 싶다고 할 때
- 도구, 템플릿, 워크플로를 찾고 싶다고 할 때
## Skills CLI
Skills CLI는 공개 스킬 생태계를 위한 패키지 관리자입니다.
주요 명령:
- `npx skills find [query]` - 키워드로 스킬 검색
- `npx skills add <package>` - GitHub 등에서 스킬 설치
- `npx skills check` - 업데이트 확인
- `npx skills update` - 설치된 스킬 업데이트
브라우징 사이트:
- `https://skills.sh/`
## 추천 절차
### 1. 요구사항 이해
- 도메인이 무엇인지 파악합니다.
- 실제로 하고 싶은 작업이 무엇인지 파악합니다.
- 흔한 문제인지, 이미 스킬이 있을 가능성이 높은지 판단합니다.
- 검색 전에 사용자가 원하는 것이 "기능", "워크플로", "템플릿", "도메인 지식" 중 무엇인지 구분합니다.
### 2. 먼저 인기 스킬 확인
- 검색 전에 leaderboard나 인기 목록에서 검증된 스킬이 있는지 먼저 봅니다.
- 설치 수가 많고 널리 알려진 출처를 우선합니다.
### 3. 검색
필요하면 아래 명령으로 검색합니다.
```bash
npx skills find [query]
```
예:
- React 성능 최적화 -> `npx skills find react performance`
- PR 리뷰 -> `npx skills find pr review`
- changelog 생성 -> `npx skills find changelog`
### 4. 품질 검증
검색 결과만 보고 바로 추천하지 않습니다. 아래를 반드시 확인합니다.
- 설치 수
- 출처 신뢰도
- GitHub 저장소 평판
가능하면 공식 또는 널리 알려진 조직의 스킬을 우선합니다.
추가로 아래도 함께 봅니다.
- 최근에도 관리되고 있는지
- 설명이 실제 사용 시점을 명확히 말하는지
- 사용자가 원하는 작업과 과하게 어긋나지 않는지
### 5. 사용자에게 제시
다음 정보를 함께 제공합니다.
- 스킬 이름과 역할
- 설치 수와 출처
- 설치 명령
- 더 알아볼 링크
### 6. 설치 제안
사용자가 원하면 설치까지 진행할 수 있습니다.
```bash
npx skills add <owner/repo@skill> -g -y
```
## 검색 절차 요약
1. 사용자가 하려는 일을 짧게 재정의합니다.
2. 인기 스킬에서 먼저 후보를 봅니다.
3. 부족하면 `npx skills find`로 구체 검색을 합니다.
4. 검색 결과를 설치 수와 출처 기준으로 걸러냅니다.
5. 사용자에게 1~3개 정도의 실질적인 후보를 제시합니다.
6. 원하면 설치까지 이어집니다.
## 검색 팁
- 너무 넓은 키워드보다 구체적인 키워드를 사용합니다.
- 검색 결과가 약하면 동의어를 바꿔가며 다시 찾습니다.
- 테스트, 디자인, 문서화, 배포, 코드리뷰, 생산성 같은 범주를 기준으로 접근합니다.
## 추천 시 주의점
- 검색 결과만 나왔다고 바로 추천하지 않습니다.
- 설치 수가 지나치게 적고 출처가 불분명하면 주의 표시를 합니다.
- 사용자가 당장 원하는 문제를 일반 역량으로 더 빨리 해결할 수 있다면 그 점도 함께 안내합니다.
## 찾지 못했을 때
적절한 스킬이 없다면 다음 원칙을 따릅니다.
- 스킬을 찾지 못했다고 명확히 알립니다.
- 일반 역량으로 직접 도와줄 수 있다고 제안합니다.
- 반복 작업이라면 새 스킬을 직접 만들 수 있다고 안내합니다.
## 기대 결과
이 스킬의 결과물은 다음을 만족해야 합니다.
- 사용자가 어떤 스킬을 왜 추천받았는지 이해할 수 있어야 합니다.
- 추천 스킬은 최소한의 품질 검증을 통과해야 합니다.
- 설치 명령과 더 알아볼 경로가 함께 제공되어야 합니다.
- 적절한 스킬이 없을 경우에도 다음 행동이 제시되어야 합니다.
+97
View File
@@ -0,0 +1,97 @@
---
name: "frontend-design"
description: "개성 있고 완성도 높은 프론트엔드 UI를 설계하고 구현합니다. 웹 페이지, 컴포넌트, 대시보드, 랜딩페이지, 스타일 개선 요청이 있을 때 호출합니다."
---
# 개성 있는 프로덕션급 프론트엔드 디자인
이 스킬은 흔한 "AI가 만든 티 나는" 결과물을 피하고, 높은 디자인 완성도를 가진 프론트엔드 인터페이스를 만들기 위한 가이드입니다. 미학적 디테일과 창의적 선택에 집중하면서 실제로 동작하는 코드를 구현합니다.
사용자는 컴포넌트, 페이지, 애플리케이션, 포스터, 웹 인터페이스 등의 프론트엔드 요구사항을 제공합니다. 여기에는 목적, 대상 사용자, 기술 제약이 함께 포함될 수 있습니다.
## 디자인 사고
코드를 작성하기 전에 문맥을 이해하고, 분명하고 대담한 미학 방향을 먼저 정합니다.
- **목적** - 이 인터페이스가 해결하는 문제는 무엇인지, 누가 사용하는지 파악합니다.
- **톤** - 극단적인 방향성을 고릅니다. 예: 극단적 미니멀리즘, 맥시멀리즘, 레트로 퓨처리즘, 유기적/자연주의, 고급/정제, 장난감 같은 유쾌함, 에디토리얼/매거진, 브루탈리즘, 아르데코, 소프트/파스텔, 산업적/실용주의 등
- **제약** - 프레임워크, 성능, 접근성 같은 기술 조건을 확인합니다.
- **차별점** - 이 결과물을 잊히지 않게 만드는 핵심 한 가지가 무엇인지 정의합니다.
**중요**: 개념적 방향을 명확히 정하고 정밀하게 실행해야 합니다. 대담한 맥시멀리즘이든 정제된 미니멀리즘이든 모두 가능하지만, 핵심은 강도가 아니라 의도성입니다.
방향을 정할 때는 "멋있어 보이는 것"만이 아니라 "왜 이 제품과 맥락에 맞는가"까지 설명할 수 있어야 합니다.
그 다음, HTML/CSS/JS, React, Vue 등 적절한 기술로 아래 기준을 만족하는 실제 동작 코드를 구현합니다.
- 프로덕션 수준의 완성도와 기능성
- 시각적으로 강렬하고 기억에 남는 결과
- 일관된 미학 관점
- 세부까지 정교하게 다듬어진 표현
## 프론트엔드 미학 가이드라인
다음 요소에 집중합니다.
- **타이포그래피** - 아름답고, 독특하고, 흥미로운 폰트를 선택합니다. Arial, Inter 같은 너무 흔한 폰트는 피합니다. 개성 있는 디스플레이 폰트와 정제된 본문 폰트를 조합합니다.
- **색상과 테마** - 일관된 미학 방향에 확실히 맞춥니다. CSS 변수로 일관성을 유지합니다. 소심하게 균등 분배된 색상보다, 지배적인 메인 컬러와 날카로운 포인트 컬러가 더 강한 인상을 줍니다.
- **모션** - 애니메이션과 마이크로 인터랙션을 활용합니다. HTML에서는 가능하면 CSS 중심으로 해결하고, React에서는 Motion 계열 라이브러리를 활용할 수 있습니다. 페이지 로드 연출, 스태거드 리빌, 스크롤 트리거, 의외성 있는 호버 상태처럼 임팩트 있는 순간에 집중합니다.
- **공간 구성** - 예상 가능한 배치보다 비대칭, 겹침, 대각선 흐름, 그리드를 깨는 요소, 넉넉한 여백 또는 의도된 밀도를 적극 활용합니다.
- **배경과 시각 디테일** - 단색 배경으로 끝내지 말고 분위기와 깊이를 만듭니다. 그래디언트 메시, 노이즈 텍스처, 기하학 패턴, 레이어 투명도, 강한 그림자, 장식 테두리, 커스텀 커서, 그레인 오버레이 등 맥락에 맞는 효과를 활용합니다.
- **맥락 적합성** - 금융, 의료, 패션, 교육처럼 도메인별 기대치를 반영합니다. 시각적으로 강하더라도 제품 신뢰를 해치면 실패입니다.
- **디테일 완성도** - 버튼 상태, 입력 포커스, 빈 상태, 에러 상태, 로딩 상태까지 같은 미학 언어로 정리합니다.
## 반드시 피할 것
다음과 같은 흔한 AI 스타일은 사용하지 않습니다.
- Inter, Roboto, Arial, 시스템 폰트에 과도하게 의존하는 구성
- 흰 배경 위 보라색 그라데이션 같은 진부한 색 조합
- 너무 예측 가능한 레이아웃과 컴포넌트 패턴
- 맥락 고유성이 없는 쿠키커터식 디자인
항상 맥락에 맞게 창의적으로 해석하고, 예상 밖이지만 설득력 있는 선택을 합니다. 모든 디자인은 서로 달라야 하며, 결과물마다 라이트/다크 테마, 폰트, 분위기, 스타일이 달라질 수 있어야 합니다. 여러 세대의 결과물이 공통된 안전한 선택으로 수렴해서는 안 됩니다.
다음 같은 패턴도 피합니다.
- 의미 없는 화려함만 있고 정보 위계가 약한 구성
- 디자인 방향 없이 라이브러리 기본 스타일만 얹은 화면
- 모든 요소에 같은 그림자, 같은 반경, 같은 간격을 기계적으로 적용한 화면
- 제품 목적보다 Dribbble식 비주얼 과시에 치우친 화면
## 구현 복잡도와 미학의 일치
구현 복잡도는 미학 방향과 맞아야 합니다.
- 맥시멀한 디자인이라면 풍부한 애니메이션, 시각 효과, 정교한 레이어링이 필요할 수 있습니다.
- 미니멀하거나 정제된 디자인이라면 절제, 정밀한 간격, 타이포그래피, 미묘한 디테일에 집중해야 합니다.
우아함은 단순함 자체가 아니라, 선택한 비전을 얼마나 정확하게 실행했는지에서 나옵니다.
## 작업 절차
이 스킬을 적용할 때는 보통 아래 순서를 따릅니다.
1. 제품 맥락과 사용자층을 확인합니다.
2. 대담한 미학 방향을 한 문장으로 정의합니다.
3. 색상, 폰트, 레이아웃, 모션 원칙을 결정합니다.
4. 그 방향에 맞는 실제 UI를 구현합니다.
5. 상태 변화, 반응형, 접근성, 디테일 완성도를 점검합니다.
## 산출물 기대치
최종 결과물은 다음을 만족해야 합니다.
- 실제로 동작하는 코드여야 합니다.
- 디자인 방향이 한눈에 읽혀야 합니다.
- 타이포그래피와 색상 시스템이 의도적으로 구성되어야 합니다.
- 상태 변화와 미세 상호작용까지 마감되어야 합니다.
- 흔한 AI 스타일이 아니라, 맥락에 맞는 인상적인 화면이어야 합니다.
## 핵심 원칙
- 프론트엔드 결과물은 항상 실제로 동작해야 합니다.
- 미학 방향은 분명해야 하며, 애매한 절충안으로 흐르지 않습니다.
- 흔한 AI 스타일 대신 맥락에 맞는 독창성을 우선합니다.
- 디테일, 간격, 타이포그래피, 모션, 색상 일관성을 끝까지 다듬습니다.
- 과감한 선택을 두려워하지 말고, 명확한 방향성을 완성도 있게 구현합니다.
+90
View File
@@ -0,0 +1,90 @@
---
name: "karpathy-guidelines"
description: "LLM 코딩 실수를 줄이는 행동 지침입니다. 코드 작성, 리뷰, 리팩터링 시 과설계와 과추정을 줄이고 검증 가능한 목표를 세워야 할 때 호출합니다."
---
# Karpathy 가이드라인
이 스킬은 LLM이 코드 작업에서 자주 하는 실수를 줄이기 위한 행동 규칙입니다. 속도보다 신중함을 약간 더 우선합니다.
사소한 작업에서는 판단의 여지가 있지만, 코드 작성, 리뷰, 리팩터링처럼 실수가 누적되기 쉬운 작업에서는 이 규칙을 기본 행동으로 삼습니다.
## 1. 코딩 전에 먼저 생각하기
- 추정하지 않습니다.
- 헷갈리는 점을 숨기지 않습니다.
- 가정을 명시적으로 드러냅니다.
- 해석이 여러 가지면 조용히 하나를 고르지 말고 선택지를 보여줍니다.
- 더 단순한 방법이 있으면 먼저 제안합니다.
- 불명확하면 멈추고 무엇이 불명확한지 말합니다.
핵심은 "모르는 상태에서 자신감 있게 진행하지 않는 것"입니다.
## 2. 단순함 우선
문제를 해결하는 최소한의 코드만 작성합니다.
- 요청하지 않은 기능은 넣지 않습니다.
- 한 번만 쓰는 코드에 추상화를 만들지 않습니다.
- 요구되지 않은 유연성이나 설정 가능성은 추가하지 않습니다.
- 실제로 불가능한 시나리오까지 과한 예외 처리를 만들지 않습니다.
- 200줄이 50줄로 될 수 있다면 다시 단순화합니다.
항상 스스로 묻습니다. "시니어 엔지니어가 이걸 과하다고 말하지 않을까?"
단순함은 기능 부족이 아니라, 요구에 정확히 맞는 최소 해법을 의미합니다.
## 3. 수술하듯 수정하기
필요한 부분만 건드리고, 내 변경으로 생긴 부산물만 정리합니다.
- 인접 코드, 주석, 포맷을 괜히 손보지 않습니다.
- 고장 나지 않은 부분을 리팩터링하지 않습니다.
- 기존 스타일을 따릅니다.
- 내 변경 때문에 쓰이지 않게 된 import, 변수, 함수만 제거합니다.
- 원래부터 있던 죽은 코드는 함부로 지우지 않고 필요하면 언급만 합니다.
모든 변경 줄은 사용자 요청과 직접 연결되어야 합니다.
관련 없는 개선 욕구는 분리해야 합니다. 지금 작업의 일부가 아니라면 메모만 하고 건드리지 않습니다.
## 4. 목표 기반 실행
작업은 검증 가능한 목표로 바꿉니다.
- 유효성 검사 추가 -> 잘못된 입력 테스트를 쓰고 통과시킨다
- 버그 수정 -> 재현 테스트를 만들고 통과시킨다
- 리팩터링 -> 변경 전후 테스트가 모두 통과하는지 확인한다
여러 단계 작업이라면 짧은 계획과 검증 기준을 함께 둡니다.
예:
1. 단계 수행 -> 어떤 체크로 검증할지 명시
2. 다음 단계 수행 -> 어떤 체크로 검증할지 명시
3. 최종 검증 -> 통과 조건 명시
강한 성공 기준이 있을수록 중간 판단을 줄일 수 있고, 사용자의 재확인 없이도 정확하게 루프를 돌 수 있습니다.
## 자주 막아야 할 실수
- 애매한 요구를 임의로 해석해 구현해 버리는 것
- 한 번만 쓸 로직에 구조를 과하게 씌우는 것
- 요청과 직접 관련 없는 주변 코드까지 손대는 것
- "작동하면 됐다" 수준으로 검증 없이 마무리하는 것
## 기대 결과
이 스킬을 적용한 결과는 다음을 만족해야 합니다.
- 가정이 숨겨지지 않는다
- 코드가 필요한 만큼만 단순하다
- 변경 범위가 요청과 정확히 맞닿아 있다
- 성공 기준이 검증 가능한 문장으로 바뀌어 있다
## 핵심 요약
- 먼저 생각하고, 모르면 묻습니다.
- 최소 코드로 끝냅니다.
- 꼭 필요한 줄만 바꿉니다.
- 검증 가능한 성공 기준을 세웁니다.
+130
View File
@@ -0,0 +1,130 @@
---
name: "systematic-debugging"
description: "버그, 테스트 실패, 예기치 않은 동작을 체계적으로 진단합니다. 수정안을 제시하기 전에 반드시 근본 원인을 먼저 찾아야 할 때 호출합니다."
---
# 체계적 디버깅
무작위 수정은 시간을 낭비하고 새 버그를 만듭니다. 빠른 땜질은 증상만 가릴 뿐입니다. 이 스킬의 핵심은 **수정 전에 반드시 근본 원인을 찾는 것**입니다.
## 철칙
근본 원인 조사 없이 수정하지 않습니다.
다시 말해, 1단계를 끝내지 않았다면 수정안 제시는 아직 허용되지 않습니다.
## 언제 사용할지
다음과 같은 모든 기술 문제에서 사용합니다.
- 테스트 실패
- 운영 중 버그
- 예기치 않은 동작
- 성능 문제
- 빌드 실패
- 통합 문제
특히 아래 상황에서 반드시 사용합니다.
- 시간이 촉박할 때
- "일단 이것만 빨리 고치면 될 것 같을 때"
- 이미 여러 수정안을 시도했을 때
- 이전 수정이 실패했을 때
- 문제를 완전히 이해하지 못한 상태일 때
다음 상황에서도 생략하지 않습니다.
- 문제가 너무 단순해 보일 때
- 급하게 고쳐 달라는 압박이 있을 때
- 지금 보이는 증상만 없애면 될 것처럼 느껴질 때
## 4단계 프로세스
### 1단계: 근본 원인 조사
수정 전에 반드시 아래를 수행합니다.
- 오류 메시지, 경고, 스택 트레이스를 끝까지 읽습니다.
- 재현 절차를 명확히 만들고, 반복 재현 가능한지 확인합니다.
- 최근 변경 사항, 설정 차이, 의존성 변경, 환경 차이를 확인합니다.
- 다중 컴포넌트 시스템이라면 경계마다 로그와 계측을 추가해 어디서 깨지는지 증거를 모읍니다.
- 호출 스택이 깊다면 잘못된 값이 어디서 시작됐는지 거꾸로 추적합니다.
- 재현이 안정적이지 않다면, 추측 대신 로그와 관찰 지점을 늘립니다.
- 레이어가 여러 개인 시스템이라면 각 경계에서 입력, 출력, 상태 전파를 확인합니다.
### 2단계: 패턴 분석
- 같은 코드베이스에서 정상 동작하는 유사 사례를 찾습니다.
- 참조 구현이 있다면 끝까지 읽고 패턴을 정확히 이해합니다.
- 정상 사례와 문제 사례의 차이를 작은 것까지 모두 나열합니다.
- 필요한 설정, 환경, 전제 조건을 파악합니다.
- "이 정도 차이는 중요하지 않겠지"라고 넘기지 않습니다.
### 3단계: 가설과 검증
- "원인은 X이며 이유는 Y다"라는 단일 가설을 명확히 적습니다.
- 가설을 검증할 수 있는 최소 변경만 적용합니다.
- 한 번에 변수 하나만 바꿉니다.
- 실패하면 수정안을 겹쳐 쌓지 말고 새 가설로 돌아갑니다.
- 모르는 것은 모른다고 인정하고 추가 조사 또는 도움 요청을 합니다.
이 단계의 핵심은 과학적 방법입니다.
- 한 번에 하나의 가설만 세웁니다.
- 한 번에 하나의 변수만 바꿉니다.
- 실패하면 더 많은 수정으로 덮지 않고, 얻은 새 증거를 바탕으로 다시 분석합니다.
### 4단계: 구현
- 먼저 실패하는 테스트나 최소 재현 케이스를 만듭니다.
- 확인된 근본 원인만 겨냥해 한 번에 한 수정만 적용합니다.
- 테스트가 통과하는지, 다른 것이 깨지지 않았는지 검증합니다.
- 수정이 실패하면 즉시 멈추고 다시 1단계로 돌아갑니다.
- 세 번 이상 실패했다면 개별 버그가 아니라 구조적 문제일 가능성을 의심합니다.
세 번 이상 수정이 연속 실패했다면 아래를 질문합니다.
- 우리가 증상을 계속 쫓고 있지는 않은가
- 현재 구조 자체가 문제를 유발하고 있지는 않은가
- 고칠 문제가 아니라 패턴을 바꿔야 하는 상황은 아닌가
## 중단 신호
다음 생각이 들면 멈추고 다시 1단계로 돌아갑니다.
- 일단 빨리 고치고 나중에 조사하자
- X를 바꿔보면 될 것 같다
- 여러 개를 같이 바꾸면 빠를 것 같다
- 테스트는 나중에 쓰자
- 완전히 이해는 못 했지만 아마 맞을 것이다
- 한 번만 더 고쳐보자
- 여기 문제들은 대충 이런 것들이다
- 로그 없이 감으로 수정 방향을 정하자
- 여기저기 같이 바꾸면 하나쯤 맞을 것이다
이 신호들은 대부분 조사보다 추측이 앞서고 있다는 뜻입니다.
## 안티 패턴
- 증상만 감추는 빠른 땜질
- 여러 수정안을 한 번에 넣는 방식
- 재현 없이 감으로 고치는 방식
- 비교 대상 없이 현재 코드만 들여다보는 방식
- 세 번 이상 실패했는데도 구조를 의심하지 않는 방식
## 핵심 원칙
- 증상이 아니라 원인을 수정합니다.
- 계측과 증거 없이 추측하지 않습니다.
- 한 번에 하나만 바꿉니다.
- 재현, 비교, 검증이 없는 수정은 완료가 아닙니다.
- 여러 번 실패하면 구조 자체를 의심합니다.
## 기대 결과
이 스킬을 적용한 결과는 다음을 만족해야 합니다.
- 문제의 재현 절차가 설명 가능해야 합니다.
- 근본 원인을 뒷받침하는 증거가 있어야 합니다.
- 수정안은 하나의 원인에 대응해야 합니다.
- 수정 후에는 재현 테스트 또는 검증 절차가 통과해야 합니다.
+116
View File
@@ -0,0 +1,116 @@
---
name: "ui-ux-pro-max"
description: "웹과 모바일 전반의 UI/UX 설계 지능을 제공합니다. 새 페이지 설계, 컴포넌트 리팩터링, 디자인 시스템, 접근성, 상호작용 품질 점검이 필요할 때 호출합니다."
---
# UI/UX Pro Max
웹과 모바일 애플리케이션을 위한 종합 UI/UX 설계 가이드입니다. 다양한 스타일, 색상 팔레트, 폰트 조합, 제품 유형별 추천, UX 가이드라인, 차트 유형 관점을 바탕으로 더 완성도 높은 인터페이스를 설계하도록 돕습니다.
## 언제 적용할지
다음과 같은 작업에서는 이 스킬을 우선 사용합니다.
- 새 페이지를 설계할 때
- 버튼, 모달, 폼, 테이블, 차트 같은 UI 컴포넌트를 만들거나 리팩터링할 때
- 색상 체계, 타이포그래피, 간격, 레이아웃 시스템을 정할 때
- UI 코드의 사용성, 접근성, 시각 일관성을 검토할 때
- 내비게이션, 애니메이션, 반응형 동작을 설계할 때
- 제품 수준의 스타일, 정보 위계, 브랜드 표현을 결정할 때
- 인터페이스의 명확성, 품질감, 사용성을 개선할 때
## 반드시 사용할 상황
아래 상황에서는 이 스킬 사용을 기본값으로 둡니다.
- 랜딩 페이지, 대시보드, 어드민, SaaS, 모바일 앱 등 새 화면 구조를 만들 때
- 버튼, 모달, 폼, 테이블, 차트 같은 핵심 컴포넌트를 설계 또는 개편할 때
- 색상 체계와 타이포그래피 시스템을 결정할 때
- 접근성, 상호작용 품질, 시각 일관성 리뷰를 수행할 때
- 반응형 레이아웃과 내비게이션 구조를 정할 때
다음 경우에는 보조적으로 권장됩니다.
- UI가 "어딘가 덜 프로페셔널해 보이는데 이유가 분명하지 않을 때"
- 사용성 피드백을 받았을 때
- 출시 전 UI 품질을 정리할 때
- 웹, iOS, Android 간 디자인 정렬이 필요할 때
- 디자인 시스템 또는 재사용 가능한 컴포넌트 라이브러리를 만들 때
## 권장 상황
- UI가 덜 프로페셔널해 보이지만 원인이 명확하지 않을 때
- 제품 피드백에서 "불편하다", "헷갈린다"는 의견이 반복될 때
- 출시 직전 품질 점검에서 디자인 완성도를 끌어올려야 할 때
## 불필요한 상황
아래 작업에서는 일반적으로 이 스킬이 우선순위가 아닙니다.
- 순수 백엔드 로직만 다루는 작업
- API 계약, DB 스키마 설계만 다루는 작업
- UI와 무관한 인프라/DevOps 작업
- 시각 요소가 없는 자동화 스크립트 작업
다음 작업에는 일반적으로 필요하지 않습니다.
- 순수 백엔드 로직 개발
- API 또는 데이터베이스 설계만 하는 작업
- 인터페이스와 무관한 성능 최적화
- 인프라, DevOps, 비시각 자동화 작업
판단 기준은 단순합니다. 작업이 기능이 **어떻게 보이고, 느껴지고, 움직이고, 상호작용되는지**를 바꾼다면 이 스킬을 사용합니다.
## 핵심 원칙
- 접근성을 최우선으로 봅니다. 대비, 키보드 탐색, 레이블, 상태 표현을 먼저 확인합니다.
- 시각적 품질보다 정보 구조와 사용 흐름을 먼저 정리합니다.
- 제품 맥락에 맞는 스타일을 선택하고, 유행하는 패턴을 무조건 복제하지 않습니다.
- 타이포그래피, 색상, 간격, 그림자, 애니메이션, 반응형 규칙을 시스템으로 다룹니다.
- 웹과 모바일을 포함한 여러 플랫폼 간 일관성을 유지하되, 플랫폼 고유 상호작용은 존중합니다.
- 차트나 데이터 시각화는 미적인 취향보다 데이터 전달 목적에 맞게 선택합니다.
## 우선순위별 검토 항목
1. **접근성** - 대비, 포커스, 라벨, 키보드 접근성, 보조기기 친화성
2. **상호작용 품질** - 클릭 영역, 터치 친화성, 상태 변화, 피드백
3. **정보 위계** - 가장 중요한 내용이 첫눈에 보이는지 확인
4. **레이아웃 시스템** - 그리드, 여백, 정렬, 반응형 구조
5. **타이포그래피** - 역할이 명확한 글자 크기, 무게, 줄 간격, 폰트 조합
6. **색상 시스템** - 브랜드 적합성, 상태 색, 강조 규칙, 다크/라이트 확장성
7. **모션과 전환** - 의미 있는 움직임만 남기고 산만한 효과는 제거
8. **시각 디테일** - 경계선, 그림자, 반경, 배경 질감, 컴포넌트 완성도
## 워크플로
1. 제품 유형과 목표 사용자, 핵심 과업을 정의합니다.
2. 정보 위계와 화면 구조를 먼저 설계합니다.
3. 스타일 방향, 색상 전략, 타이포그래피 전략을 정합니다.
4. 컴포넌트와 페이지를 같은 시스템 규칙으로 맞춥니다.
5. 접근성, 반응형, 상태 표현, 상호작용 완성도를 점검합니다.
6. 필요한 경우 리뷰 결과를 우선순위별로 정리해 개선합니다.
## 작업 방식
- 먼저 제품 유형과 대상 사용자, 핵심 화면 목적을 확인합니다.
- 그 다음 스타일 방향, 컬러 전략, 타이포그래피 방향, 레이아웃 전략을 제안합니다.
- 필요한 경우 2~3개의 시각 방향을 비교하고 추천안을 제시합니다.
- 구현에 들어갈 때는 컴포넌트 단위 규칙과 페이지 단위 위계를 함께 설계합니다.
- 리뷰 작업이라면 문제를 단순 나열하지 말고, 우선순위와 수정 이유까지 설명합니다.
## 안티 패턴
- 정보 구조를 정하기 전에 시각 효과만 먼저 쌓는 방식
- 모든 화면을 같은 템플릿으로 찍어내는 방식
- 접근성 점검 없이 색상과 애니메이션만 조정하는 방식
- 컴포넌트 규칙 없이 페이지별 임시 스타일을 누적하는 방식
## 산출물 기준
이 스킬을 사용한 결과물은 다음을 만족해야 합니다.
- 보기 좋을 뿐 아니라 읽기 쉽고 사용하기 쉬워야 합니다.
- 단일 화면이 아니라 전체 시스템 관점에서 일관성이 있어야 합니다.
- 컴포넌트와 페이지의 관계가 명확해야 합니다.
- 접근성, 반응형, 상태 표현을 빠뜨리지 않아야 합니다.
- 색상, 폰트, 간격, 인터랙션이 의도적으로 선택되어야 합니다.
+90
View File
@@ -0,0 +1,90 @@
---
name: "using-superpowers"
description: "응답 전에 관련 스킬을 먼저 확인하고 호출하는 운영 규칙입니다. 어떤 작업이든 적절한 스킬 적용 여부를 먼저 판단해야 할 때 호출합니다."
---
# 스킬 사용 운영 규칙
이 스킬은 대화나 작업을 시작할 때, 어떤 스킬을 먼저 확인하고 어떻게 적용할지에 대한 기본 운영 원칙을 정의합니다.
## 최우선 규칙
관련 스킬이 조금이라도 적용될 가능성이 있다면, 응답이나 행동 전에 먼저 스킬을 호출합니다.
질문에 답하기 전, 코드 읽기 전, 구현 시작 전, 명확화 질문을 하기 전에도 먼저 검토합니다.
단 1%의 가능성이라도 있다면 먼저 확인하는 쪽이 기본값입니다.
## 우선순위
스킬 지시보다 사용자 지시가 항상 우선합니다.
1. 사용자 명시 지시
2. 스킬 지시
3. 시스템 기본 동작
즉, 스킬이 어떤 워크플로를 권장하더라도 사용자가 다른 방식을 명확히 요구하면 사용자 지시를 따릅니다.
## 기본 흐름
- 사용자 메시지를 받으면 먼저 관련 스킬 가능성을 판단합니다.
- 관련 가능성이 있으면 즉시 스킬을 호출합니다.
- 호출된 스킬에 체크리스트가 있으면 작업 목록을 만들고 순서대로 따릅니다.
- 그 다음에야 응답, 질문, 구현, 조사 같은 행동을 합니다.
중요한 점은, "먼저 조금만 확인하고 나서 스킬을 쓰자"가 아니라 "스킬을 먼저 확인하고 나서 어떻게 확인할지 결정한다"는 순서입니다.
## 스킬 우선 적용 순서
여러 스킬이 동시에 맞을 수 있다면 아래 순서를 기준으로 봅니다.
1. **프로세스 스킬** - 작업 방식을 정하는 스킬
2. **구현 스킬** - 실제 구현이나 산출물을 만드는 스킬
예:
- "무언가를 만들자" -> brainstorming 먼저, 그다음 구현 스킬
- "버그를 고치자" -> debugging 먼저, 그다음 도메인 스킬
즉, 프로세스를 정하는 스킬이 항상 구현 스킬보다 먼저입니다.
## 흔한 자기합리화 경고
다음 생각이 들면 흐름을 다시 점검합니다.
- 이건 간단하니까 스킬이 필요 없겠다
- 먼저 코드 좀 보고 나서 생각하자
- 빠르게 확인만 하고 나중에 스킬을 쓰자
- 이 정도는 기억으로 처리해도 되겠다
- 질문이니까 작업이 아니다
- 스킬이 너무 과한 것 같다
- 이건 그냥 간단한 확인이다
- 이전에 본 적 있는 스킬이라 다시 안 읽어도 된다
이런 생각은 대부분 스킬 적용을 건너뛰려는 신호입니다.
## 적용 절차
실제 적용 절차는 아래와 같습니다.
1. 사용자 메시지를 받습니다.
2. 관련 스킬 가능성을 먼저 판단합니다.
3. 조금이라도 관련 있다면 스킬을 호출합니다.
4. 스킬의 체크리스트나 절차를 작업 흐름에 반영합니다.
5. 그 다음 응답, 조사, 구현을 진행합니다.
## 원칙
- 스킬은 선택이 아니라 작업 방식의 일부로 본다
- 단순한 작업일수록 오히려 프로세스를 지켜 과잉 추정을 줄인다
- 기억에 의존하지 말고 현재 스킬 내용을 기준으로 판단한다
- 관련성이 아주 낮아 보여도, 가능성이 있으면 먼저 확인한다
## 기대 결과
이 스킬의 목적은 다음 상태를 만드는 것입니다.
- 관련 스킬이 빠지지 않는다
- 작업 접근 순서가 일관된다
- 응답 전에 방법론이 먼저 고정된다
- 임의 판단과 과잉 추정이 줄어든다
+109
View File
@@ -0,0 +1,109 @@
---
name: "webapp-testing"
description: "Playwright 기반으로 로컬 웹앱을 점검하고 테스트합니다. 프론트엔드 동작 검증, UI 디버깅, 스크린샷, 브라우저 로그 확인이 필요할 때 호출합니다."
---
# 웹앱 테스트
이 스킬은 로컬 웹 애플리케이션을 브라우저에서 실제로 검증하기 위한 Playwright 기반 테스트 가이드입니다.
## 기본 원칙
- 동적 웹앱은 렌더링이 끝나기 전에 DOM을 섣불리 읽지 않습니다.
- 브라우저 조작 전에 먼저 화면 상태를 관찰합니다.
- 가능하면 기본 제공 스크립트를 블랙박스로 활용합니다.
- 정적인 추측보다 브라우저에서 직접 확인한 셀렉터와 상태를 신뢰합니다.
## 사용 가능한 보조 스크립트
- `scripts/with_server.py` - 서버 실행과 종료를 관리합니다.
이 스크립트는 먼저 `--help`로 사용법을 확인한 뒤 사용합니다. 소스를 먼저 읽기보다, 가능한 한 도구처럼 호출하는 방식을 우선합니다.
## 언제 사용할지
- 로컬 웹앱의 실제 동작을 확인해야 할 때
- 버튼, 폼, 내비게이션, 모달 같은 UI 상호작용을 점검할 때
- 스크린샷이나 브라우저 로그가 필요할 때
- 동적 렌더링 이후의 DOM을 기준으로 문제를 확인해야 할 때
## 접근 방식 결정
### 정적 HTML인 경우
- 파일을 직접 읽어 셀렉터를 먼저 확인합니다.
- 그 셀렉터를 바탕으로 Playwright 스크립트를 작성합니다.
- 직접 확인이 부족하면 동적 앱처럼 취급합니다.
### 동적 웹앱인 경우
- 서버가 안 떠 있다면 `with_server.py`로 서버 라이프사이클을 관리합니다.
- 서버가 이미 떠 있다면 브라우저에서 먼저 정찰한 뒤 조작합니다.
## 정찰 후 행동 패턴
이 스킬의 기본 패턴은 "정찰 후 행동"입니다.
1. 페이지에 접속합니다.
2. `networkidle` 상태까지 기다립니다.
3. 스크린샷을 찍거나 렌더링된 DOM을 확인합니다.
4. 그 상태를 기준으로 셀렉터를 식별합니다.
5. 그 다음 클릭, 입력, 검증 같은 행동을 수행합니다.
정적 분석으로 셀렉터를 추측하는 대신, 실제 렌더링 결과를 기준으로 선택자를 확정합니다.
## 서버 관리 예시
단일 서버:
```bash
python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.py
```
복수 서버:
```bash
python scripts/with_server.py --server "cd backend && python server.py" --port 3000 --server "cd frontend && npm run dev" --port 5173 -- python your_automation.py
```
## 자동화 스크립트 원칙
- `sync_playwright()`를 기본으로 사용합니다.
- Chromium은 headless 모드로 실행합니다.
- 페이지 이동 후 `page.wait_for_load_state('networkidle')`를 호출합니다.
- 작업이 끝나면 브라우저를 닫습니다.
## with_server.py 사용 원칙
- 먼저 `python scripts/with_server.py --help`로 옵션을 확인합니다.
- 서버가 여러 개인 경우에도 이 스크립트로 생명주기를 한 번에 관리합니다.
- Playwright 스크립트 안에는 서버 시작 로직을 넣지 않습니다.
- 자동화 스크립트는 브라우저 조작에만 집중합니다.
## 좋은 습관
- 먼저 관찰하고 나중에 조작합니다.
- `text=`, `role=`, CSS 선택자, ID 등 설명력 있는 셀렉터를 씁니다.
- 필요한 경우 `wait_for_selector()` 같은 명시적 대기를 사용합니다.
- 스크린샷과 콘솔 로그 수집을 적극 활용합니다.
- 재현이 불안정하면 관찰 스텝을 늘리고, 행동 스텝은 줄여 원인을 좁힙니다.
## 흔한 실수
- JS가 끝나기 전에 DOM을 확인하는 것
- 서버 실행과 테스트 로직을 뒤섞는 것
- 셀렉터 확인 없이 곧바로 클릭부터 시도하는 것
- 렌더링 전 HTML만 보고 동적 UI 동작을 단정하는 것
## 기대 결과
이 스킬을 적용한 결과물은 다음을 만족해야 합니다.
- 서버 실행과 테스트 로직이 분리되어 있어야 합니다.
- 브라우저에서 실제 보이는 상태를 기준으로 상호작용이 설계되어야 합니다.
- 셀렉터와 검증 조건이 관찰 결과를 기반으로 정해져야 합니다.
- 필요 시 스크린샷, 콘솔 로그, DOM 확인 결과를 남길 수 있어야 합니다.
## 목표
이 스킬의 목적은 브라우저에서 실제 사용자 흐름을 검증하고, 화면 기준으로 문제를 발견하며, 재현 가능한 자동화 스크립트를 만드는 것입니다.
+139
View File
@@ -0,0 +1,139 @@
---
name: "writing-plans"
description: "명세가 정해진 다단계 작업을 실행 계획으로 바꿉니다. 코드를 건드리기 전에 구체적인 구현 계획과 작업 순서를 작성해야 할 때 호출합니다."
---
# 구현 계획 작성
이 스킬은 명세나 요구사항이 있는 작업을, 실제 엔지니어가 바로 수행할 수 있는 상세 구현 계획으로 바꾸기 위한 가이드입니다.
## 개요
계획은 코드베이스 맥락이 거의 없는 개발자도 이해할 수 있도록 충분히 구체적이어야 합니다. 어떤 파일을 수정할지, 어떤 테스트를 작성할지, 무엇을 어떤 순서로 검증할지까지 모두 포함해야 합니다.
핵심 원칙은 다음과 같습니다.
- DRY
- YAGNI
- TDD
- 잦은 커밋
- 작은 단계
계획 문서는 기본적으로 `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md` 에 저장합니다.
시작할 때는 현재 구현 계획 작성 단계에 들어왔음을 명확히 선언합니다.
## 범위 점검
- 명세가 여러 독립 하위 시스템을 포함한다면 계획도 분리합니다.
- 하나의 계획은 자체적으로 구현, 테스트, 검증 가능한 범위를 가져야 합니다.
- 하나의 계획만으로 독립적으로 완료 가능한 단위를 만드는 것이 목표입니다.
## 파일 구조 먼저 정의
작업을 나누기 전에 어떤 파일을 만들고 수정할지 먼저 정리합니다.
- 각 파일은 하나의 명확한 책임만 가지게 설계합니다.
- 함께 바뀌는 파일은 가까이 두고, 책임 기준으로 나눕니다.
- 기존 코드베이스의 패턴을 따릅니다.
- 지나치게 커진 파일을 다뤄야 한다면 계획 안에 분리 작업을 포함할 수 있습니다.
- 분해 결정은 이 단계에서 고정하는 것이 좋습니다. 계획 후반에 파일 책임이 바뀌면 전체 작업이 흔들립니다.
## 작업 단위 규칙
각 단계는 2~5분 안에 수행 가능한 하나의 행동이어야 합니다.
- 실패 테스트 작성
- 테스트를 실행해 실패 확인
- 최소 구현 작성
- 테스트를 실행해 통과 확인
- 커밋
이처럼 한 단계에는 한 행동만 담습니다.
좋은 계획은 "무엇을 할지"만 적지 않고, "어떻게 검증할지"까지 함께 적습니다.
## 계획 문서 헤더
모든 계획 문서는 다음 구조로 시작합니다.
```markdown
# [기능명] 구현 계획
> **에이전트 작업자용:** 각 작업은 체크박스(`- [ ]`)로 추적합니다.
**목표:** [이 기능이 무엇을 만드는지 한 문장]
**아키텍처:** [접근 방식 2~3문장]
**기술 스택:** [핵심 기술]
---
```
## 작업 구조
각 작업은 아래 내용을 포함해야 합니다.
- 대상 파일 경로
- 생성/수정/테스트 파일 구분
- 실제 테스트 코드 예시
- 실행 명령과 기대 결과
- 최소 구현 코드 예시
- 커밋 명령 예시
가능하다면 각 작업은 독립적으로 읽혀야 합니다. 작업을 순서대로 읽지 않아도 필요한 정보가 빠지지 않아야 합니다.
## 금지 사항
다음과 같은 placeholder는 허용하지 않습니다.
- TBD
- TODO
- 나중에 구현
- 적절한 에러 처리 추가
- 위 내용을 테스트 작성
- Task N과 유사
- 방법 설명만 있고 실제 코드나 명령이 없는 단계
모든 단계는 실행에 필요한 실제 내용을 포함해야 합니다.
다음 표현도 피합니다.
- 적당히 구현
- 필요하면 보완
- 상황에 맞게 처리
- 일반적인 에러 처리 추가
- 위 단계 참고
이런 표현은 실행 정보를 숨기기 때문에 계획 품질을 떨어뜨립니다.
## 자체 검토
계획 작성 후 아래를 스스로 점검합니다.
1. 명세의 모든 요구사항이 작업에 반영됐는가
2. placeholder나 빈칸이 남지 않았는가
3. 함수명, 타입, 시그니처, 속성명이 작업 간 일관적인가
빠진 요구사항이 있으면 즉시 작업을 추가합니다.
추가로 아래도 확인합니다.
- 각 작업이 실제로 끝나는 단위인지
- 테스트나 검증 단계가 빠지지 않았는지
- 파일 경로가 모호하지 않은지
- 한 작업에 여러 행동이 뭉쳐 있지 않은지
## 완료 후 인계
계획 저장 후에는 실행 방식을 사용자에게 선택하게 합니다.
- 서브에이전트 기반 실행
- 현재 세션에서 인라인 실행
핵심은, 구현 전에 계획이 먼저 완성되고 검토 가능해야 한다는 점입니다.
## 기대 결과
이 스킬의 결과물은 다음을 만족해야 합니다.
- 구현자가 문맥 없이도 작업을 시작할 수 있어야 합니다.
- 각 작업은 체크리스트처럼 따라갈 수 있어야 합니다.
- 테스트와 검증 명령이 포함되어 있어야 합니다.
- 문서 안에 실행 가능한 수준의 구체성이 있어야 합니다.
+165
View File
@@ -0,0 +1,165 @@
# skillDesk
TRAE에서 바로 사용할 수 있도록 정리한 에이전트 스킬 모음 저장소입니다.
`skillText.md`에 정리된 인기 스킬 10개를 현재 프로젝트의 `.trae/skills` 구조로 옮기고, 한국어로 확장 설명을 추가했습니다.
## 프로젝트 목적
이 저장소는 다음 목적을 가집니다.
- 자주 쓰이는 에이전트 스킬 10개를 현재 프로젝트 안에서 바로 참조 가능하게 정리
- 원문에 가까운 규칙, 사용 시점, 워크플로를 한국어로 복원
- TRAE에서 실제로 검증할 수 있는 프롬프트형 테스트 시나리오 제공
## 포함된 스킬
- [brainstorming](./.trae/skills/brainstorming/SKILL.md)
- [frontend-design](./.trae/skills/frontend-design/SKILL.md)
- [ui-ux-pro-max](./.trae/skills/ui-ux-pro-max/SKILL.md)
- [systematic-debugging](./.trae/skills/systematic-debugging/SKILL.md)
- [writing-plans](./.trae/skills/writing-plans/SKILL.md)
- [find-skills](./.trae/skills/find-skills/SKILL.md)
- [using-superpowers](./.trae/skills/using-superpowers/SKILL.md)
- [karpathy-guidelines](./.trae/skills/karpathy-guidelines/SKILL.md)
- [webapp-testing](./.trae/skills/webapp-testing/SKILL.md)
- [agent-browser](./.trae/skills/agent-browser/SKILL.md)
## 디렉터리 구조
```text
skillDesk/
├── .trae/
│ └── skills/
│ ├── brainstorming/
│ ├── frontend-design/
│ ├── ui-ux-pro-max/
│ ├── systematic-debugging/
│ ├── writing-plans/
│ ├── find-skills/
│ ├── using-superpowers/
│ ├── karpathy-guidelines/
│ ├── webapp-testing/
│ └── agent-browser/
├── docs/
│ ├── superpowers/
│ │ ├── specs/
│ │ └── plans/
│ └── test-scenarios.md
├── README.md
└── skillText.md
```
## 문서 구성
- [skillText.md](./skillText.md): 10개 인기 스킬 소개 번역본
-`SKILL.md`: 실제 프로젝트용 스킬 설명과 사용 규칙
- [테스트 시나리오](./docs/test-scenarios.md): TRAE에서 바로 실행해 볼 수 있는 검증 프롬프트 모음
- [설계 문서](./docs/superpowers/specs/2026-06-09-skill-docs-design.md): 문서 확장 설계
- [구현 계획](./docs/superpowers/plans/2026-06-09-skill-docs-expansion.md): 실행 계획 기록
## TRAE에서 사용하는 방법
1. 이 프로젝트를 TRAE에서 엽니다.
2. `.trae/skills/` 아래 스킬들이 인식되는 환경에서 작업합니다.
3. 작업 요청을 입력하면, 적절한 스킬이 먼저 호출되는지 확인합니다.
4. 스킬별 동작을 검증하려면 [테스트 시나리오](./docs/test-scenarios.md)의 프롬프트를 그대로 사용합니다.
## 추천 사용 흐름
작업 성격에 따라 아래 순서를 추천합니다.
- 신규 기능/설계: `brainstorming` -> `writing-plans` -> 구현 스킬
- UI 작업: `brainstorming` -> `frontend-design` 또는 `ui-ux-pro-max`
- 버그 수정: `systematic-debugging` -> 도메인 스킬
- 브라우저 검증: `webapp-testing` 또는 `agent-browser`
- 스킬 탐색: `find-skills`
- 전반 운영 규칙: `using-superpowers`, `karpathy-guidelines`
## 문서 확장 기준
이번 저장소의 스킬 문서는 다음 기준으로 정리했습니다.
- 원문 핵심 규칙, 단계, 금지 사항은 최대한 유지
- 한국어 가독성을 위해 구조와 문장을 재편집
- 단순 번역보다 실제 프로젝트에서 바로 읽히는 운영 문서 형태로 정리
- frontmatter `description`은 짧고 실사용 판단에 유리하게 유지
## 빠른 확인 포인트
- 설계 없이 구현으로 바로 가는가 -> `brainstorming`
- 계획 없이 바로 코드를 바꾸려는가 -> `writing-plans`
- 버그를 감으로 고치려는가 -> `systematic-debugging`
- UI가 평범하고 맥락이 약한가 -> `frontend-design`, `ui-ux-pro-max`
- 적절한 스킬이 있는지부터 모르겠는가 -> `find-skills`
## 테스트 시나리오
실제 TRAE 검증용 프롬프트는 아래 문서에 정리되어 있습니다.
- [docs/test-scenarios.md](./docs/test-scenarios.md)
## SQLite + FastAPI + Vue CRUD 예제 실행
현재 저장소에는 SQLite의 `messages` 테이블 데이터를 FastAPI가 읽고 쓰며, Vue 화면에서 조회, 추가, 수정, 삭제할 수 있는 최소 CRUD 예제가 포함되어 있습니다.
### 1. 백엔드 실행
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements.txt
python backend/init_db.py
uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload
```
### 2. 프론트엔드 실행
새 터미널에서 아래 명령을 실행합니다.
```bash
python3 -m http.server 5173 -d frontend
```
### 3. 확인
- 백엔드 API 목록 조회: `http://127.0.0.1:8000/api/messages`
- 프론트엔드 화면: `http://127.0.0.1:5173`
- 기존 단일 조회 호환 API: `http://127.0.0.1:8000/api/message`
정상 동작 시 Vue 화면에서 초기 데이터 `hello world`를 포함한 메시지 목록이 보이고, 새 메시지 추가, 기존 메시지 수정, 기존 메시지 삭제가 모두 가능합니다.
### 4. 포트 충돌 시 대체 실행
이미 `8000` 또는 `5173` 포트를 다른 프로그램이 사용 중이면 아래처럼 대체 포트를 사용합니다.
#### 백엔드 대체 포트 예시
```bash
uvicorn backend.main:app --host 127.0.0.1 --port 8001 --reload
```
#### 프론트엔드 대체 포트 예시
```bash
python3 -m http.server 5174 -d frontend
```
#### 프론트 API 포트 맞추기
프론트가 다른 백엔드 포트를 보도록 하려면 [index.html](file:///Users/woozooni/Documents/trae_projects/skillDesk/frontend/index.html#L8-L15) 의 `window.APP_CONFIG`에서 `apiPort` 값을 백엔드 실행 포트와 동일하게 수정합니다.
예를 들어 백엔드를 `8001`로 실행했다면 아래처럼 맞춥니다.
```html
<script>
window.APP_CONFIG = {
apiHost: 'http://127.0.0.1',
apiPort: '8001',
}
</script>
```
이 경우 접속 주소는 아래와 같습니다.
- 백엔드 API 목록 조회: `http://127.0.0.1:8001/api/messages`
- 프론트엔드 화면: `http://127.0.0.1:5174`
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+19
View File
@@ -0,0 +1,19 @@
import sqlite3 # SQLite 데이터베이스를 다루기 위한 모듈을 가져온다.
from pathlib import Path # 파일 경로를 안전하게 계산하기 위한 모듈을 가져온다.
DB_PATH = Path(__file__).resolve().parent / "app.db" # 현재 파일 기준으로 데이터베이스 파일 경로를 정한다.
def main() -> None: # 데이터베이스를 초기화하는 메인 함수를 정의한다.
connection = sqlite3.connect(DB_PATH) # SQLite 데이터베이스에 연결한다.
cursor = connection.cursor() # SQL 실행을 위한 커서를 만든다.
cursor.execute("CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL)") # 메시지 테이블이 없으면 생성한다.
cursor.execute("DELETE FROM messages") # 예제를 단순하게 유지하기 위해 기존 메시지를 모두 지운다.
cursor.execute("INSERT INTO messages (content) VALUES (?)", ("hello world",)) # hello world 예제 데이터를 한 건 추가한다.
connection.commit() # 변경 내용을 데이터베이스에 저장한다.
connection.close() # 데이터베이스 연결을 닫는다.
print(f"Database initialized at: {DB_PATH}") # 초기화된 데이터베이스 경로를 출력한다.
if __name__ == "__main__": # 현재 파일을 직접 실행했을 때만 초기화 함수를 호출한다.
main() # 데이터베이스 초기화를 수행한다.
+87
View File
@@ -0,0 +1,87 @@
import sqlite3 # SQLite 데이터베이스를 읽고 쓰기 위한 모듈을 가져온다.
from pathlib import Path # 데이터베이스 파일 경로를 계산하기 위한 모듈을 가져온다.
from fastapi import FastAPI, HTTPException # FastAPI 앱과 예외 응답 도구를 가져온다.
from fastapi.middleware.cors import CORSMiddleware # 프론트엔드 연동을 위한 CORS 미들웨어를 가져온다.
from pydantic import BaseModel # 요청 본문을 검증하기 위한 기본 모델 클래스를 가져온다.
DB_PATH = Path(__file__).resolve().parent / "app.db" # 현재 파일 기준으로 데이터베이스 파일 경로를 정한다.
app = FastAPI(title="SQLite CRUD API") # FastAPI 애플리케이션 인스턴스를 만든다.
app.add_middleware(CORSMiddleware, allow_origins=["http://127.0.0.1:5173", "http://localhost:5173"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"]) # Vue 개발 서버에서 API를 호출할 수 있도록 CORS를 허용한다.
class MessagePayload(BaseModel): # 메시지 생성과 수정을 위한 요청 모델을 정의한다.
content: str # 요청 본문에서 메시지 내용을 문자열로 받는다.
def ensure_database_exists() -> None: # 데이터베이스 파일 존재 여부를 확인하는 함수를 정의한다.
if not DB_PATH.exists(): # 데이터베이스 파일이 아직 생성되지 않았는지 확인한다.
raise HTTPException(status_code=500, detail="Database file does not exist. Run backend/init_db.py first.") # 초기화 스크립트 실행이 필요하다는 오류를 반환한다.
def get_connection() -> sqlite3.Connection: # SQLite 연결 객체를 공통으로 만드는 함수를 정의한다.
ensure_database_exists() # 데이터베이스 파일이 존재하는지 먼저 확인한다.
connection = sqlite3.connect(DB_PATH) # SQLite 데이터베이스에 연결한다.
connection.row_factory = sqlite3.Row # 컬럼 이름으로 접근할 수 있도록 Row 팩토리를 지정한다.
return connection # 설정이 끝난 연결 객체를 반환한다.
def normalize_content(content: str) -> str: # 메시지 내용을 공통 규칙으로 정리하는 함수를 정의한다.
normalized_content = content.strip() # 앞뒤 공백을 제거해 실제 입력값만 남긴다.
if not normalized_content: # 공백만 있거나 빈 문자열인 경우를 확인한다.
raise HTTPException(status_code=400, detail="Content must not be empty") # 빈 메시지는 허용하지 않는다는 오류를 반환한다.
return normalized_content # 검증을 통과한 메시지 내용을 반환한다.
def serialize_message(row: sqlite3.Row) -> dict[str, int | str]: # SQLite 행 데이터를 JSON 응답용 딕셔너리로 바꾸는 함수를 정의한다.
return {"id": row["id"], "content": row["content"]} # id와 content만 꺼내서 반환한다.
def read_first_message() -> str: # 데이터베이스에서 첫 번째 메시지를 읽는 함수를 정의한다.
with get_connection() as connection: # 데이터베이스 연결을 열고 자동으로 닫히게 한다.
row = connection.execute("SELECT content FROM messages ORDER BY id ASC LIMIT 1").fetchone() # 가장 먼저 저장된 메시지 한 건을 조회한다.
if row is None: # 조회된 메시지가 없는 경우를 확인한다.
raise HTTPException(status_code=404, detail="Message not found") # 메시지가 없다는 404 오류를 반환한다.
return row["content"] # 조회한 메시지 내용을 반환한다.
@app.get("/api/message") # 기존 예제와 호환되도록 첫 번째 메시지를 반환하는 GET 엔드포인트를 유지한다.
def get_message() -> dict[str, str]: # JSON 응답 형태의 딕셔너리를 반환하는 함수를 정의한다.
return {"message": read_first_message()} # 데이터베이스에서 읽은 첫 번째 메시지를 JSON으로 반환한다.
@app.get("/api/messages") # 전체 메시지 목록을 반환하는 GET 엔드포인트를 정의한다.
def list_messages() -> list[dict[str, int | str]]: # 메시지 목록을 JSON 배열 형태로 반환하는 함수를 정의한다.
with get_connection() as connection: # 데이터베이스 연결을 열고 자동으로 닫히게 한다.
rows = connection.execute("SELECT id, content FROM messages ORDER BY id ASC").fetchall() # 저장된 메시지를 id 오름차순으로 모두 조회한다.
return [serialize_message(row) for row in rows] # 조회된 모든 행을 직렬화해 반환한다.
@app.post("/api/messages", status_code=201) # 새 메시지를 저장하는 POST 엔드포인트를 정의한다.
def create_message(payload: MessagePayload) -> dict[str, int | str]: # 생성된 메시지 정보를 반환하는 함수를 정의한다.
normalized_content = normalize_content(payload.content) # 요청 본문의 메시지 내용을 공통 규칙으로 정리한다.
with get_connection() as connection: # 데이터베이스 연결을 열고 자동으로 닫히게 한다.
cursor = connection.execute("INSERT INTO messages (content) VALUES (?)", (normalized_content,)) # 정리된 메시지 내용을 테이블에 저장한다.
connection.commit() # INSERT 결과를 데이터베이스에 반영한다.
return {"id": int(cursor.lastrowid), "content": normalized_content} # 생성된 id와 메시지 내용을 응답으로 반환한다.
@app.put("/api/messages/{message_id}") # 기존 메시지를 수정하는 PUT 엔드포인트를 정의한다.
def update_message(message_id: int, payload: MessagePayload) -> dict[str, int | str]: # 수정된 메시지 정보를 반환하는 함수를 정의한다.
normalized_content = normalize_content(payload.content) # 요청 본문의 메시지 내용을 공통 규칙으로 정리한다.
with get_connection() as connection: # 데이터베이스 연결을 열고 자동으로 닫히게 한다.
cursor = connection.execute("UPDATE messages SET content = ? WHERE id = ?", (normalized_content, message_id)) # 지정한 id의 메시지 내용을 새 값으로 수정한다.
connection.commit() # UPDATE 결과를 데이터베이스에 반영한다.
if cursor.rowcount == 0: # 실제로 수정된 행이 없는 경우를 확인한다.
raise HTTPException(status_code=404, detail="Message not found") # 없는 메시지라는 404 오류를 반환한다.
return {"id": message_id, "content": normalized_content} # 수정된 id와 메시지 내용을 응답으로 반환한다.
@app.delete("/api/messages/{message_id}") # 기존 메시지를 삭제하는 DELETE 엔드포인트를 정의한다.
def delete_message(message_id: int) -> dict[str, bool]: # 삭제 성공 여부를 반환하는 함수를 정의한다.
with get_connection() as connection: # 데이터베이스 연결을 열고 자동으로 닫히게 한다.
cursor = connection.execute("DELETE FROM messages WHERE id = ?", (message_id,)) # 지정한 id의 메시지를 테이블에서 삭제한다.
connection.commit() # DELETE 결과를 데이터베이스에 반영한다.
if cursor.rowcount == 0: # 실제로 삭제된 행이 없는 경우를 확인한다.
raise HTTPException(status_code=404, detail="Message not found") # 없는 메시지라는 404 오류를 반환한다.
return {"success": True} # 삭제가 성공했음을 JSON으로 반환한다.
+2
View File
@@ -0,0 +1,2 @@
fastapi
uvicorn
@@ -0,0 +1,73 @@
# SQLite + FastAPI + Vue 전역 설정 분리 구현 계획
> **에이전트 작업자용:** 각 작업은 체크박스(`- [ ]`)로 추적합니다.
**목표:** 프론트엔드가 `index.html`의 전역 설정 객체에서 API 호스트와 포트를 읽어 오도록 바꿔, 포트 변경 시 `main.js`를 수정하지 않아도 되게 만든다.
**아키텍처:** `frontend/index.html``window.APP_CONFIG`를 정의하고, `frontend/src/main.js`는 이 전역 객체를 읽어 기본값과 함께 `API_BASE_URL`을 조합한다. README는 설정 위치와 포트 충돌 대응 절차를 `index.html` 기준으로 다시 설명한다.
**기술 스택:** HTML, Vue 3 ESM, JavaScript, Markdown
---
- [ ] **작업 1: HTML 전역 설정 객체 추가**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/index.html` (수정)
- **할 일:** Vue 앱 스크립트가 실행되기 전에 `window.APP_CONFIG` 객체를 선언하고, 기본 `apiHost``apiPort`를 넣는다.
- **최소 구현 예시:**
```html
<script>
window.APP_CONFIG = {
apiHost: 'http://127.0.0.1',
apiPort: '8000',
}
</script>
```
- **검증 명령:** `python3 -m http.server 5173 -d frontend`
- **기대 결과:** 브라우저가 `index.html`을 로드하면 Vue 앱 시작 전 전역 설정 객체가 준비된다.
- [ ] **작업 2: main.js가 전역 설정과 기본값을 읽도록 변경**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정)
- **할 일:** 기존 `API_HOST`, `API_PORT` 상수를 `window.APP_CONFIG` 기반으로 바꾸고, 설정이 없을 때 기본값 `127.0.0.1:8000`이 유지되게 한다.
- **최소 구현 예시:**
```javascript
const appConfig = window.APP_CONFIG ?? {}
const apiHost = appConfig.apiHost || 'http://127.0.0.1'
const apiPort = appConfig.apiPort || '8000'
const API_BASE_URL = `${apiHost}:${apiPort}/api`
```
- **검증 명령:** `python3 -m py_compile backend/main.py`
- **기대 결과:** `main.js`를 수정하지 않고 `index.html` 값만 바꿔 다른 백엔드 포트로 연결할 수 있다.
- [ ] **작업 3: 기존 CRUD fetch 흐름 유지 확인**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (검토)
- **할 일:** 생성, 조회, 수정, 삭제 fetch 호출이 모두 새 `API_BASE_URL`을 그대로 사용하도록 유지한다.
- **최소 구현 예시:**
```javascript
const response = await fetch(`${API_BASE_URL}/messages`)
```
- **검증 명령:** `python3 -m py_compile backend/main.py`
- **기대 결과:** 설정 방식만 바뀌고 CRUD 기능 경로는 그대로 유지된다.
- [ ] **작업 4: README 설정 위치 설명 갱신**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (수정)
- **할 일:** 기존 `main.js`의 `API_PORT` 수정 안내를 `index.html`의 `window.APP_CONFIG.apiPort` 수정 안내로 바꾼다.
- **최소 구현 예시:**
```markdown
`frontend/index.html`의 `window.APP_CONFIG`에서 `apiPort` 값을 백엔드 실행 포트와 맞춥니다.
```
- **검증 명령:** `python3 -m py_compile backend/init_db.py backend/main.py`
- **기대 결과:** README만 읽어도 설정 수정 위치가 `index.html`이라는 점을 알 수 있다.
- [ ] **작업 5: 포트 충돌 대응 예시를 전역 설정 방식으로 보강**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (수정)
- **할 일:** 백엔드를 `8001`, 프론트를 `5174`로 실행할 때 `apiPort: '8001'` 예시를 함께 적는다.
- **최소 구현 예시:**
```html
window.APP_CONFIG = {
apiHost: 'http://127.0.0.1',
apiPort: '8001',
}
```
- **검증 명령:** `python3 -m py_compile backend/init_db.py backend/main.py`
- **기대 결과:** 사용자가 포트 충돌 시 실행 명령과 전역 설정 값을 한 번에 맞출 수 있다.
- [ ] **작업 6: 진단 및 수동 검증**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/index.html` (진단), `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (진단), `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (진단)
- **할 일:** IDE 진단을 확인하고, 필요 시 즉시 수정한다. 가능하면 프론트 정적 서버를 열어 설정 객체가 페이지 로드 전에 선언되는 구조도 점검한다.
- **검증 도구:** IDE 진단 확인
- **기대 결과:** 새 오류 없이 전역 설정 분리 구조가 문서와 코드에 모두 반영된다.
@@ -0,0 +1,69 @@
# SQLite + FastAPI + Vue 포트 설정 분리 구현 계획
> **에이전트 작업자용:** 각 작업은 체크박스(`- [ ]`)로 추적합니다.
**목표:** CRUD 예제의 프론트 API 주소와 실행 포트 안내를 분리해 포트 충돌 시 최소 수정으로 다시 실행할 수 있게 만든다.
**아키텍처:** 프론트엔드는 `frontend/src/main.js`에서 API 주소를 `API_HOST`, `API_PORT`, `API_BASE_URL` 상수로 나누어 관리한다. 실행 포트 선택은 백엔드와 프론트 모두 명령줄에서 유지하고, README에 기본 포트와 대체 포트 예시를 함께 적어 사용자가 충돌 상황에서 바로 대응할 수 있게 한다.
**기술 스택:** Vue 3 ESM, FastAPI, Python http.server, Markdown
---
- [ ] **작업 1: 프론트 API 주소 상수 구조 변경**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정)
- **할 일:** 현재 하나의 문자열로 선언된 `API_BASE_URL``API_HOST`, `API_PORT`, `API_BASE_URL`로 분리한다.
- **최소 구현 예시:**
```javascript
const API_HOST = 'http://127.0.0.1'
const API_PORT = '8000'
const API_BASE_URL = `${API_HOST}:${API_PORT}/api`
```
- **검증 명령:** `python3 -m py_compile backend/main.py`
- **기대 결과:** 프론트 코드에서 백엔드 포트를 한 줄만 수정해 다른 포트로 연결할 수 있다.
- [ ] **작업 2: 프론트 주석과 설정 의도 정리**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정)
- **할 일:** 사용자 규칙에 맞춰 각 상수와 조합 이유를 한글 주석으로 설명하고, 기존 fetch 호출이 새 상수를 그대로 사용하도록 유지한다.
- **최소 구현 예시:**
```javascript
const API_HOST = 'http://127.0.0.1' // 백엔드 API 호스트 주소를 별도 상수로 분리한다.
const API_PORT = '8000' // 백엔드 포트 충돌 시 이 값만 바꾸면 되도록 한다.
const API_BASE_URL = `${API_HOST}:${API_PORT}/api` // 실제 fetch 요청에 사용할 기본 API 주소를 조합한다.
```
- **검증 명령:** `python3 -m py_compile backend/main.py`
- **기대 결과:** 프론트 상수 구조만 읽어도 포트 변경 지점을 쉽게 찾을 수 있다.
- [ ] **작업 3: README 기본 실행 예시를 명시적 포트 기준으로 보강**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (수정)
- **할 일:** 기존 실행 안내에 기본 백엔드 포트 `8000`, 프론트 포트 `5173`을 명령 예시로 명확히 적는다.
- **최소 구현 예시:**
```markdown
uvicorn backend.main:app --host 127.0.0.1 --port 8000
python3 -m http.server 5173 -d frontend
```
- **검증 명령:** `python3 -m py_compile backend/init_db.py backend/main.py`
- **기대 결과:** README만 보고 기본 실행 주소를 바로 이해할 수 있다.
- [ ] **작업 4: README에 포트 충돌 대응 섹션 추가**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (수정)
- **할 일:** `8001`, `5174` 같은 대체 포트 예시와 함께, 프론트에서 `API_PORT`를 어디서 바꾸는지 안내한다.
- **최소 구현 예시:**
```markdown
uvicorn backend.main:app --host 127.0.0.1 --port 8001
python3 -m http.server 5174 -d frontend
`frontend/src/main.js`의 `API_PORT`도 `8001`로 맞춥니다.
```
- **검증 명령:** `python3 -m py_compile backend/init_db.py backend/main.py`
- **기대 결과:** 포트 충돌 시 사용자가 다음 명령과 코드 수정 위치를 바로 알 수 있다.
- [ ] **작업 5: 문법 및 진단 확인**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (진단), `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (진단)
- **할 일:** IDE 진단으로 새 오류를 확인하고, 필요 시 즉시 수정한다.
- **검증 도구:** IDE 진단 확인
- **기대 결과:** 수정 파일에 새 오류가 없다.
- [ ] **작업 6: 수동 확인 절차 정리**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (검토)
- **할 일:** 사용자가 직접 확인할 수 있도록 기본 포트 실행과 대체 포트 실행 시 어떤 주소를 열어야 하는지 최종 점검한다.
- **실행 명령:**
```bash
uvicorn backend.main:app --host 127.0.0.1 --port 8001
python3 -m http.server 5174 -d frontend
```
- **기대 결과:** `frontend/src/main.js`의 `API_PORT`를 `8001`로 맞추면 `http://127.0.0.1:5174`에서 정상 동작해야 한다는 실행 흐름이 README에 반영된다.
@@ -0,0 +1,207 @@
# Skill 문서 확장 구현 계획
> **에이전트 작업자용:** REQUIRED SUB-SKILL: 현재 세션에서는 인라인으로 실행한다. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 10개 스킬 문서를 원문에 더 가깝게 확장하고, README와 TRAE 테스트 시나리오 문서를 추가한다.
**Architecture:** 기존 `.trae/skills/*/SKILL.md`를 스킬 성격별로 확장하고, 저장소 루트에는 탐색용 README를, `docs/`에는 실행 가능한 테스트 시나리오 문서를 둔다. 검증은 Markdown 진단과 문서 간 링크/명칭 일관성 확인으로 마무리한다.
**Tech Stack:** Markdown, Trae skill frontmatter, VS Code diagnostics
---
### Task 1: 프로세스 스킬 문서 확장
**Files:**
- Modify: `.trae/skills/brainstorming/SKILL.md`
- Modify: `.trae/skills/systematic-debugging/SKILL.md`
- Modify: `.trae/skills/writing-plans/SKILL.md`
- Modify: `.trae/skills/using-superpowers/SKILL.md`
- Modify: `.trae/skills/karpathy-guidelines/SKILL.md`
- Test: 문서 진단 확인
- [ ] **Step 1: 현재 프로세스 스킬 문서를 다시 읽어 섹션 공통 틀을 고정**
Read:
```text
.trae/skills/brainstorming/SKILL.md
.trae/skills/systematic-debugging/SKILL.md
.trae/skills/writing-plans/SKILL.md
.trae/skills/using-superpowers/SKILL.md
.trae/skills/karpathy-guidelines/SKILL.md
```
Expected: 각 문서에 공통으로 들어갈 섹션(개요, 적용 시점, 워크플로, 금지 사항, 기대 결과)을 정할 수 있다.
- [ ] **Step 2: brainstorming 문서를 원문 흐름에 가깝게 확장**
Include:
```markdown
## 체크리스트
## 프로세스 흐름
## 설계 제시 규칙
## 문서화와 사용자 검토 게이트
## 시각 보조 도구 사용 기준
```
Expected: 설계 전 구현 금지, 한 번에 한 질문, 2~3개 접근법 제안, writing-plans로 전환 규칙이 모두 드러난다.
- [ ] **Step 3: systematic-debugging 문서를 4단계 절차 중심으로 확장**
Include:
```markdown
## 철칙
## 1단계: 근본 원인 조사
## 2단계: 패턴 분석
## 3단계: 가설과 검증
## 4단계: 구현
## 중단 신호
```
Expected: 수정 전에 조사, 증거 기반 추적, 최소 변경 검증, 3회 이상 실패 시 구조 재검토가 명확해진다.
- [ ] **Step 4: writing-plans 문서를 계획 품질 기준 중심으로 확장**
Include:
```markdown
## 파일 구조 먼저 정의
## 작업 단위 규칙
## 계획 문서 헤더
## 금지 사항
## 자체 검토
## 완료 후 인계
```
Expected: placeholder 금지, 작은 단계, 명확한 파일 경로, 검증 가능한 명령이 강조된다.
- [ ] **Step 5: using-superpowers와 karpathy-guidelines를 운영 규칙 중심으로 확장**
Include:
```markdown
## 최우선 규칙
## 스킬 우선 적용 순서
## 흔한 자기합리화 경고
## 코딩 전에 먼저 생각하기
## 단순함 우선
## 수술하듯 수정하기
## 목표 기반 실행
```
Expected: 스킬 선적용 원칙과 과설계 방지 원칙이 각각 독립적으로 읽혀야 한다.
- [ ] **Step 6: 진단 확인**
Run: Markdown diagnostics for the five edited files
Expected: 진단 오류 없음
### Task 2: UI/구현/탐색 스킬 문서 확장
**Files:**
- Modify: `.trae/skills/frontend-design/SKILL.md`
- Modify: `.trae/skills/ui-ux-pro-max/SKILL.md`
- Modify: `.trae/skills/find-skills/SKILL.md`
- Modify: `.trae/skills/webapp-testing/SKILL.md`
- Modify: `.trae/skills/agent-browser/SKILL.md`
- Test: 문서 진단 확인
- [ ] **Step 1: 현재 다섯 문서를 다시 읽고 성격별 확장 포인트 정리**
Read:
```text
.trae/skills/frontend-design/SKILL.md
.trae/skills/ui-ux-pro-max/SKILL.md
.trae/skills/find-skills/SKILL.md
.trae/skills/webapp-testing/SKILL.md
.trae/skills/agent-browser/SKILL.md
```
Expected: 디자인형, 탐색형, 테스트형, 자동화형 문서에 필요한 추가 섹션이 정리된다.
- [ ] **Step 2: frontend-design 문서를 미학 방향성과 금지 패턴 중심으로 확장**
Include:
```markdown
## 디자인 사고
## 미학 가이드라인
## 반드시 피할 것
## 구현 복잡도와 미학의 일치
## 산출물 기대치
```
Expected: 흔한 AI 스타일 회피, 타이포그래피/색상/모션/공간 구성 원칙이 상세해진다.
- [ ] **Step 3: ui-ux-pro-max 문서를 적용 조건과 우선순위 점검 기준 중심으로 확장**
Include:
```markdown
## 언제 적용할지
## 반드시 사용할 상황
## 권장 상황
## 불필요한 상황
## 우선순위별 검토 항목
## 산출물 기준
```
Expected: 웹/모바일 UI 품질 관리용 종합 규칙처럼 읽힌다.
- [ ] **Step 4: find-skills, webapp-testing, agent-browser 문서를 실행 절차 중심으로 확장**
Include:
```markdown
## 검색 절차
## 품질 검증
## 정찰 후 행동 패턴
## with_server.py 사용 원칙
## agent-browser skills get core
## 특수 가이드
```
Expected: 사용자가 바로 명령과 판단 기준을 가져다 쓸 수 있다.
- [ ] **Step 5: 진단 확인**
Run: Markdown diagnostics for the five edited files
Expected: 진단 오류 없음
### Task 3: README와 테스트 시나리오 문서 작성
**Files:**
- Create: `README.md`
- Create: `docs/test-scenarios.md`
- Test: 문서 진단 확인
- [ ] **Step 1: README 초안 작성**
Include:
```markdown
# skillDesk
## 프로젝트 소개
## 포함된 스킬
## 디렉터리 구조
## TRAE에서 사용하는 방법
## 추천 사용 흐름
## 테스트 시나리오
```
Expected: 저장소 목적, 10개 스킬, 사용 흐름을 처음 보는 사람도 이해할 수 있다.
- [ ] **Step 2: 테스트 시나리오 문서 작성**
Include:
```markdown
# TRAE 테스트 시나리오
## 공통 사용법
## brainstorming 시나리오
## frontend-design 시나리오
## ...
## agent-browser 시나리오
```
Expected: 각 스킬당 최소 1개 프롬프트, 기대 동작, 확인 포인트가 담긴다.
- [ ] **Step 3: README와 테스트 문서 간 링크 연결**
Add:
```markdown
[테스트 시나리오](./docs/test-scenarios.md)
[brainstorming](./.trae/skills/brainstorming/SKILL.md)
```
Expected: README에서 주요 문서로 빠르게 이동할 수 있다.
- [ ] **Step 4: 진단 확인**
Run: Markdown diagnostics for `README.md` and `docs/test-scenarios.md`
Expected: 진단 오류 없음
### Task 4: 최종 검증과 정리
**Files:**
- Modify: 전체 문서 일관성 점검 결과에 따라 필요한 파일
- Test: 전체 신규/수정 Markdown 파일 진단 확인
- [ ] **Step 1: 문서 명칭과 링크 일관성 점검**
Check:
```text
README.md
docs/test-scenarios.md
.trae/skills/*/SKILL.md
```
Expected: 스킬 이름, 링크 경로, 설명 용어가 서로 충돌하지 않는다.
- [ ] **Step 2: Markdown 진단 일괄 확인**
Run: diagnostics for all touched markdown files
Expected: 진단 오류 없음
- [ ] **Step 3: 결과 요약 작성**
Include:
```text
확장한 스킬 목록
추가한 문서 목록
검증 결과
```
Expected: 사용자가 바로 산출물을 훑어볼 수 있다.
@@ -0,0 +1,198 @@
# SQLite + FastAPI + Vue CRUD 구현 계획
> **에이전트 작업자용:** 각 작업은 체크박스(`- [ ]`)로 추적합니다.
**목표:** SQLite의 `messages` 테이블 데이터를 FastAPI CRUD API로 조작하고 Vue 화면에서 생성, 조회, 수정, 삭제할 수 있게 만든다.
**아키텍처:** 백엔드는 `sqlite3`와 FastAPI로 단순 CRUD 엔드포인트를 제공하고, 프론트엔드는 브라우저용 Vue ESM 번들로 목록형 CRUD UI를 구현한다. 구현은 기존 파일 구조를 유지하면서 최소한의 상태만 추가하고, 마지막에 API와 화면 흐름을 직접 검증한다.
**기술 스택:** Python 3, FastAPI, sqlite3, Vue 3 ESM, 정적 HTML
---
- [ ] **작업 1: DB 초기화 스크립트 유지 여부 점검**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/init_db.py` (수정)
- **할 일:** `messages` 테이블 구조가 CRUD 요구사항에 충분한지 확인하고, 초기 데이터 `hello world` 1건을 유지하는 방식으로 정리한다.
- **최소 구현 예시:**
```python
cursor.execute(
"CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL)"
)
cursor.execute("DELETE FROM messages")
cursor.execute("INSERT INTO messages (content) VALUES (?)", ("hello world",))
```
- **검증 명령:** `python3 backend/init_db.py`
- **기대 결과:** `backend/app.db`가 다시 생성되거나 갱신되고, `messages` 테이블에 `hello world` 1건이 들어간다.
- [ ] **작업 2: FastAPI용 요청 모델과 DB 헬퍼 추가**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정)
- **할 일:** SQLite 연결 헬퍼, 메시지 직렬화 헬퍼, 입력 검증용 Pydantic 모델을 추가한다.
- **최소 구현 예시:**
```python
class MessagePayload(BaseModel):
content: str
@field_validator("content")
@classmethod
def validate_content(cls, value: str) -> str:
stripped_value = value.strip()
if not stripped_value:
raise ValueError("Content must not be empty")
return stripped_value
```
- **검증 명령:** `python3 -m py_compile backend/main.py`
- **기대 결과:** API 함수들이 공통 검증 로직과 연결 헬퍼를 재사용할 준비가 된다.
- [ ] **작업 3: 메시지 목록 조회 API 구현**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정)
- **할 일:** `GET /api/messages` 엔드포인트를 추가해 전체 메시지 목록을 `id` 오름차순으로 반환한다.
- **최소 구현 예시:**
```python
@app.get("/api/messages")
def list_messages() -> list[dict[str, object]]:
with get_connection() as connection:
rows = connection.execute(
"SELECT id, content FROM messages ORDER BY id ASC"
).fetchall()
return [serialize_message(row) for row in rows]
```
- **검증 명령:** `python3 -c "from backend.main import list_messages; print(list_messages())"`
- **기대 결과:** `hello world`가 포함된 리스트가 출력된다.
- [ ] **작업 4: 메시지 생성 API 구현**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정)
- **할 일:** `POST /api/messages` 엔드포인트를 추가해 메시지를 저장하고 생성된 `id`와 `content`를 반환한다.
- **최소 구현 예시:**
```python
@app.post("/api/messages", status_code=201)
def create_message(payload: MessagePayload) -> dict[str, object]:
with get_connection() as connection:
cursor = connection.execute(
"INSERT INTO messages (content) VALUES (?)",
(payload.content,),
)
connection.commit()
return {"id": cursor.lastrowid, "content": payload.content}
```
- **검증 명령:** `python3 - <<'PY'\nfrom backend.main import create_message, MessagePayload\nprint(create_message(MessagePayload(content='created from plan')))\nPY`
- **기대 결과:** 새 `id`와 저장된 `content`가 출력된다.
- [ ] **작업 5: 메시지 수정 API 구현**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정)
- **할 일:** `PUT /api/messages/{id}` 엔드포인트를 추가해 해당 메시지를 수정하고, 없는 `id`는 404를 반환한다.
- **최소 구현 예시:**
```python
@app.put("/api/messages/{message_id}")
def update_message(message_id: int, payload: MessagePayload) -> dict[str, object]:
with get_connection() as connection:
cursor = connection.execute(
"UPDATE messages SET content = ? WHERE id = ?",
(payload.content, message_id),
)
connection.commit()
if cursor.rowcount == 0:
raise HTTPException(status_code=404, detail="Message not found")
return {"id": message_id, "content": payload.content}
```
- **검증 명령:** `python3 - <<'PY'\nfrom backend.main import update_message, MessagePayload\nprint(update_message(1, MessagePayload(content='updated hello world')))\nPY`
- **기대 결과:** 수정된 메시지 객체가 출력된다.
- [ ] **작업 6: 메시지 삭제 API 구현**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정)
- **할 일:** `DELETE /api/messages/{id}` 엔드포인트를 추가해 해당 메시지를 삭제하고 성공 여부를 반환한다.
- **최소 구현 예시:**
```python
@app.delete("/api/messages/{message_id}")
def delete_message(message_id: int) -> dict[str, bool]:
with get_connection() as connection:
cursor = connection.execute(
"DELETE FROM messages WHERE id = ?",
(message_id,),
)
connection.commit()
if cursor.rowcount == 0:
raise HTTPException(status_code=404, detail="Message not found")
return {"success": True}
```
- **검증 명령:** `python3 - <<'PY'\nfrom backend.main import delete_message\nprint(delete_message(1))\nPY`
- **기대 결과:** `{'success': True}`가 출력된다.
- [ ] **작업 7: Vue 상태를 목록형 CRUD 구조로 변경**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정)
- **할 일:** 단일 `message` 상태를 `messages`, `newContent`, `editingId`, `editingContent` 상태로 교체하고 목록 조회 함수를 만든다.
- **최소 구현 예시:**
```javascript
const messages = ref([])
const newContent = ref('')
const editingId = ref(null)
const editingContent = ref('')
```
- **검증 명령:** `python3 -m py_compile backend/main.py`
- **기대 결과:** 프론트 로직이 CRUD API 구조와 맞는 상태 이름으로 정리된다.
- [ ] **작업 8: Vue 생성/수정/삭제 액션 구현**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정)
- **할 일:** `fetch`를 사용해 생성, 수정, 삭제 요청을 보내고 성공 후 목록을 다시 불러오거나 상태를 갱신한다.
- **최소 구현 예시:**
```javascript
const createMessage = async () => {
await fetch(`${API_BASE_URL}/messages`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: newContent.value.trim() }),
})
await loadMessages()
}
```
- **검증 명령:** `python3 backend/init_db.py`
- **기대 결과:** 프론트에서 각 버튼이 API 호출 함수와 연결된다.
- [ ] **작업 9: Vue 템플릿을 목록형 CRUD UI로 교체**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정)
- **할 일:** 입력 폼, 목록, 인라인 편집, 빈 상태, 에러 상태를 모두 표시하는 템플릿으로 교체한다.
- **최소 구현 예시:**
```html
<form @submit.prevent="createMessage">
<input v-model="newContent" />
<button type="submit">추가</button>
</form>
<li v-for="message in messages" :key="message.id">
<span>{{ message.content }}</span>
</li>
```
- **검증 명령:** `python3 -m http.server 5173 -d frontend`
- **기대 결과:** 브라우저에서 목록형 CRUD 화면이 렌더링된다.
- [ ] **작업 10: README 실행/검증 문구를 CRUD 기준으로 갱신**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (수정)
- **할 일:** 단일 조회 설명을 목록형 CRUD 예제 설명으로 바꾸고, 확인 포인트를 CRUD 흐름에 맞게 수정한다.
- **최소 구현 예시:**
```markdown
- 백엔드 API: `http://127.0.0.1:8000/api/messages`
- 프론트엔드 화면: `http://127.0.0.1:5173`
- 정상 동작 시 메시지 추가, 수정, 삭제가 모두 가능하다.
```
- **검증 명령:** `python3 -m py_compile backend/init_db.py backend/main.py`
- **기대 결과:** README만 읽어도 CRUD 예제 실행과 확인 방법을 이해할 수 있다.
- [ ] **작업 11: 백엔드 문법과 API 흐름 검증**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/init_db.py` (검증), `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (검증)
- **할 일:** DB를 초기화하고, Python에서 API 함수를 직접 호출해 생성, 조회, 수정, 삭제 흐름이 모두 동작하는지 확인한다.
- **실행 명령:**
```bash
python3 backend/init_db.py
python3 - <<'PY'
from backend.main import MessagePayload, create_message, delete_message, list_messages, update_message
print("LIST-1", list_messages())
created = create_message(MessagePayload(content="plan create"))
print("CREATED", created)
print("LIST-2", list_messages())
updated = update_message(created["id"], MessagePayload(content="plan update"))
print("UPDATED", updated)
print("LIST-3", list_messages())
print("DELETED", delete_message(created["id"]))
print("LIST-4", list_messages())
PY
```
- **기대 결과:** 각 단계 출력에 따라 CRUD가 순서대로 성공한다.
- [ ] **작업 12: 진단 점검 및 인라인 실행 정리**
- **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (진단), `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (진단), `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (진단)
- **할 일:** 진단 도구로 오류를 확인하고 바로 수정한 뒤, 변경 파일과 실행 방법을 사용자에게 인계한다.
- **검증 도구:** IDE 진단 확인
- **기대 결과:** 새 오류 없이 CRUD 예제를 실행할 수 있는 상태로 마무리된다.
@@ -0,0 +1,155 @@
# SQLite + FastAPI + Vue Hello World 구현 계획
> **에이전트 작업자용:** 현재 세션에서 인라인으로 실행한다. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** SQLite에 저장된 `'hello world'` 값을 FastAPI API를 통해 Vue 화면에 표시하는 최소 실행 예제를 만든다.
**Architecture:** `backend/`에는 SQLite 초기화 스크립트와 FastAPI API를 두고, `frontend/`에는 Vite 기반 Vue 앱을 둔다. Vue는 `/api/message`를 호출해 DB 값을 받아 렌더링한다.
**Tech Stack:** Python, FastAPI, sqlite3, uvicorn, Vue 3, Vite
---
### Task 1: 백엔드 기본 구조 만들기
**Files:**
- Create: `backend/requirements.txt`
- Create: `backend/init_db.py`
- Create: `backend/main.py`
- Test: `python3 -m py_compile backend/init_db.py backend/main.py`
- [ ] **Step 1: requirements 파일 작성**
Content:
```text
fastapi
uvicorn
```
Expected: 백엔드 설치 의존성이 명확해진다.
- [ ] **Step 2: SQLite 초기화 스크립트 작성**
Code should:
```python
import sqlite3
from pathlib import Path
```
Behavior:
- `app.db` 생성
- `messages` 테이블 생성
- 기존 데이터 삭제 후 `'hello world'` 삽입
Expected: `python3 backend/init_db.py` 실행 시 DB 파일과 샘플 데이터가 생성된다.
- [ ] **Step 3: FastAPI 앱 작성**
Code should:
```python
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
```
Behavior:
- `GET /api/message`
- SQLite에서 첫 메시지 조회
- 없으면 404 반환
Expected: 앱이 JSON으로 `{ "message": "hello world" }`를 반환할 수 있다.
- [ ] **Step 4: Python 문법 확인**
Run:
```bash
python3 -m py_compile backend/init_db.py backend/main.py
```
Expected: 출력 없이 종료
### Task 2: 프론트엔드 기본 구조 만들기
**Files:**
- Create: `frontend/package.json`
- Create: `frontend/vite.config.js`
- Create: `frontend/index.html`
- Create: `frontend/src/main.js`
- Test: `npm run build`
- [ ] **Step 1: package.json 작성**
Content should include:
```json
{
"scripts": {
"dev": "vite",
"build": "vite build"
}
}
```
Expected: Vue/Vite 개발 및 빌드 명령이 준비된다.
- [ ] **Step 2: Vite 프록시 설정 작성**
Behavior:
- `/api` 요청을 `http://127.0.0.1:8000`으로 프록시
Expected: 프론트엔드에서 상대 경로로 API 호출 가능
- [ ] **Step 3: index.html 작성**
Behavior:
- `#app` 마운트 포인트 제공
Expected: Vue 앱이 정상적으로 마운트 가능
- [ ] **Step 4: Vue 메인 앱 작성**
Behavior:
- 로딩 상태 표시
- `/api/message` fetch
- 성공 시 메시지 표시
- 실패 시 에러 문구 표시
Expected: 브라우저에서 `'hello world'`를 볼 수 있는 최소 화면이 구성된다.
- [ ] **Step 5: 프론트엔드 빌드 확인**
Run:
```bash
npm install
npm run build
```
Expected: 빌드 성공
### Task 3: 실행 문서 정리
**Files:**
- Modify: `README.md`
- Test: 문서 진단 확인
- [ ] **Step 1: README에 예제 실행 섹션 추가**
Include:
```markdown
## SQLite + FastAPI + Vue 예제 실행
```
Details:
- Python 가상환경 생성
- 백엔드 의존성 설치
- DB 초기화
- FastAPI 실행
- 프론트엔드 설치/실행
- 접속 URL 안내
Expected: 처음 보는 사용자도 따라 실행 가능
### Task 4: 기본 동작 검증
**Files:**
- Modify: 필요 시 문제 있는 파일
- Test: DB 초기화, Python 문법, 프론트엔드 빌드
- [ ] **Step 1: DB 초기화 실행**
Run:
```bash
python3 backend/init_db.py
```
Expected: `backend/app.db` 생성
- [ ] **Step 2: FastAPI 의존성 설치 후 앱 import 확인**
Run:
```bash
python3 -m venv .venv
.venv/bin/pip install -r backend/requirements.txt
.venv/bin/python -c "from backend.main import app; print(app.title)"
```
Expected: 앱 타이틀 출력
- [ ] **Step 3: 프론트엔드 설치 및 빌드**
Run:
```bash
npm install
npm run build
```
Expected: 빌드 성공
- [ ] **Step 4: 결과 요약 정리**
Include:
```text
생성 파일
실행 방법
검증 결과
```
Expected: 사용자가 바로 실행을 이어갈 수 있다.
@@ -0,0 +1,108 @@
# SQLite + FastAPI + Vue 전역 설정 분리 설계
## 목표
프론트엔드가 백엔드 API 주소를 코드 내부 상수에 직접 고정하지 않고, `index.html`의 전역 설정 객체를 통해 읽도록 바꿔서 포트 변경 시 자바스크립트 로직을 수정하지 않아도 되게 만든다.
## 배경
현재 예제는 `frontend/src/main.js``API_HOST`, `API_PORT`, `API_BASE_URL` 상수가 직접 선언되어 있다.
이 구조는 이전보다 단순하지만, 포트를 바꿀 때 여전히 `main.js`를 수정해야 한다. 예제 사용성 관점에서는 HTML 설정만 바꾸고 Vue 로직은 그대로 두는 쪽이 더 이해하기 쉽다.
## 범위
이번 작업은 다음을 포함한다.
- `frontend/index.html`에 전역 설정 객체 추가
- `frontend/src/main.js`가 전역 설정 객체를 읽도록 변경
- 설정이 없을 때 기본값 `127.0.0.1:8000` 사용
- README에 설정 위치를 `index.html` 기준으로 설명
이번 작업은 다음을 포함하지 않는다.
- 별도 `config.js` 파일 추가
- `.env` 기반 설정 시스템 도입
- URL 쿼리 파라미터 기반 포트 주입
- 백엔드 설정 시스템 변경
## 구조
### 1. HTML 전역 설정
`frontend/index.html`에 아래 형태의 전역 객체를 둔다.
```html
<script>
window.APP_CONFIG = {
apiHost: 'http://127.0.0.1',
apiPort: '8000',
}
</script>
```
이 값은 프론트엔드 애플리케이션이 시작되기 전에 정의되어야 한다.
### 2. 프론트엔드 설정 읽기
`frontend/src/main.js``window.APP_CONFIG`를 읽어 아래 값을 만든다.
- `apiHost`
- `apiPort`
- `API_BASE_URL`
설정이 없거나 일부 속성이 빠져 있으면 기본값을 사용한다.
예시 구조:
```javascript
const appConfig = window.APP_CONFIG ?? {}
const apiHost = appConfig.apiHost || 'http://127.0.0.1'
const apiPort = appConfig.apiPort || '8000'
const API_BASE_URL = `${apiHost}:${apiPort}/api`
```
## 데이터 흐름
1. 브라우저가 `index.html`을 먼저 읽는다.
2. `window.APP_CONFIG`가 전역으로 설정된다.
3. `main.js`가 이 값을 읽어 실제 API 주소를 조합한다.
4. Vue 애플리케이션은 조합된 API 주소로 CRUD 요청을 보낸다.
## 기본값 처리
전역 설정 객체가 없더라도 예제가 깨지지 않도록 기본값을 유지한다.
- 기본 호스트: `http://127.0.0.1`
- 기본 포트: `8000`
즉, 설정 객체는 선택 사항이지만 존재하면 우선 적용된다.
## README 문서화 방식
README에는 아래 내용을 포함한다.
- 기본 실행 예시
- `index.html``window.APP_CONFIG` 위치 설명
- 포트 충돌 시 `apiPort`를 어떻게 바꾸는지 설명
- 프론트 정적 서버 포트는 여전히 실행 명령에서 따로 바꾼다는 점
## 오류 처리
- 전역 설정이 없으면 기본값으로 동작한다.
- 전역 설정의 값이 잘못되어 연결에 실패하면 기존 fetch 에러 문구를 보여준다.
- README에 백엔드 포트와 `apiPort`가 같아야 한다는 점을 분명히 적는다.
## 검증 기준
다음 조건을 만족하면 성공이다.
- `main.js`를 수정하지 않고 `index.html``apiPort` 값만 바꿔 다른 백엔드 포트로 연결할 수 있다.
- 전역 설정이 없어도 기본값으로 기존 CRUD 기능이 유지된다.
- README만 읽어도 설정 위치와 수정 방법을 이해할 수 있다.
## 구현 원칙
- 기존 CRUD 기능은 그대로 유지한다.
- 설정 시스템은 예제 규모에 맞게 가장 단순한 수준으로 둔다.
- 포트 변경 지점은 한 곳으로 모은다.
@@ -0,0 +1,118 @@
# SQLite + FastAPI + Vue 포트 설정 분리 설계
## 목표
현재 CRUD 예제의 백엔드와 프론트 실행 포트를 문서와 코드에서 더 분리해, 로컬 포트 충돌이 있어도 최소 수정으로 다시 실행할 수 있게 만든다.
## 배경
기존 예제는 아래 주소를 기본값으로 사용한다.
- 백엔드 API: `http://127.0.0.1:8000`
- 프론트 정적 서버: `http://127.0.0.1:5173`
실행 중 실제로 `8000`, `5173` 포트가 이미 사용 중이어서 새 서버를 같은 포트에 띄우지 못했다. 따라서 포트를 바꾸는 방법이 코드와 문서에 더 명확히 드러나야 한다.
## 범위
이번 작업은 다음을 포함한다.
- 프론트엔드의 API 주소 상수 구조를 분리
- 백엔드 포트 변경 방법을 README에 명시
- 프론트 정적 서버 포트 변경 방법을 README에 명시
- 기본 포트와 대체 포트 예시를 함께 제공
이번 작업은 다음을 포함하지 않는다.
- 별도 설정 파일 도입
- `.env` 기반 환경변수 시스템 추가
- 프론트 번들러 도입
- 런타임 자동 포트 탐지
## 접근 방식
### 1. 프론트 상수 분리
`frontend/src/main.js`의 API 주소를 하나의 긴 문자열 대신 아래 상수로 분리한다.
- `API_HOST`
- `API_PORT`
- `API_BASE_URL`
예시 구조:
```javascript
const API_HOST = 'http://127.0.0.1'
const API_PORT = '8000'
const API_BASE_URL = `${API_HOST}:${API_PORT}/api`
```
이렇게 하면 백엔드 포트를 `8001` 같은 값으로 바꿀 때 한 줄만 수정하면 된다.
### 2. 백엔드 실행 포트는 명령에서 제어
백엔드는 FastAPI 코드 내부에서 포트를 고정하지 않는다. 실행 포트는 `uvicorn` 명령의 `--port` 옵션으로 제어한다.
기본 실행:
```bash
uvicorn backend.main:app --host 127.0.0.1 --port 8000
```
대체 실행:
```bash
uvicorn backend.main:app --host 127.0.0.1 --port 8001
```
### 3. 프론트 정적 서버 포트는 명령에서 제어
프론트 정적 서버도 코드가 아니라 실행 명령에서 포트를 선택한다.
기본 실행:
```bash
python3 -m http.server 5173 -d frontend
```
대체 실행:
```bash
python3 -m http.server 5174 -d frontend
```
## README 문서화 방식
README에는 아래 내용을 포함한다.
- 기본 포트 실행 예시
- 포트 충돌 시 대체 실행 예시
- 프론트에서 `API_PORT` 값을 어디서 바꾸는지 설명
- 백엔드와 프론트 포트는 서로 독립적으로 바꿀 수 있다는 점
## 데이터 흐름
1. 사용자가 백엔드를 원하는 포트로 실행한다.
2. 프론트는 `API_HOST``API_PORT`를 조합해 API 주소를 만든다.
3. 프론트 정적 서버는 별도 포트에서 독립적으로 제공된다.
4. 포트 충돌 시 백엔드와 프론트 포트를 각각 따로 변경할 수 있다.
## 오류 처리
- 프론트가 잘못된 백엔드 포트를 가리키면 기존처럼 fetch 에러 문구를 보여준다.
- README에 포트 불일치 점검 순서를 넣어 사용자가 원인을 쉽게 찾을 수 있게 한다.
## 검증 기준
다음 조건을 만족하면 성공이다.
- 프론트 코드에서 백엔드 포트를 한 곳만 바꿔도 API 주소가 함께 변경된다.
- README만 읽어도 기본 포트와 대체 포트 실행 방법을 이해할 수 있다.
- 기존 CRUD 기능은 변경 없이 유지된다.
- 포트 충돌 상황에서 사용자가 다음 행동을 바로 선택할 수 있다.
## 구현 원칙
- 기존 CRUD 구조를 유지한다.
- 설정 분리를 위해 새 시스템을 과하게 도입하지 않는다.
- 실행 문서는 실제 충돌 상황을 해결하는 데 바로 도움이 되도록 쓴다.
@@ -0,0 +1,190 @@
# skillDesk 문서 확장 설계
## 목표
현재 프로젝트의 10개 스킬 문서를 원문에 더 가깝게 확장하고, 사용자가 바로 이해하고 검증할 수 있도록 루트 README와 TRAE 실사용 테스트 시나리오 문서를 추가한다.
## 범위
이번 작업은 다음 세 가지를 포함한다.
1. `.trae/skills/*/SKILL.md` 10개 문서 확장
2. 루트 `README.md` 신규 작성
3. `docs/test-scenarios.md` 신규 작성
이번 작업은 다음을 포함하지 않는다.
- 실제 스킬 실행 엔진 개발
- 자동 테스트 실행 스크립트 작성
- 외부 설치 자동화
- Git 커밋 자동 생성
## 현재 상태
- 루트에는 [skillText.md](file:///Users/woozooni/Documents/trae_projects/skillDesk/skillText.md) 가 있고, 10개 스킬 목록의 한국어 번역이 있다.
- `.trae/skills/` 아래에 10개 스킬 디렉터리와 `SKILL.md`가 생성되어 있다.
- 현재 스킬 문서는 핵심 요약형에 가깝고, 원문 세부 규칙과 절차 복원 수준은 낮다.
- 루트 `README.md`는 아직 없다.
- 테스트 시나리오 문서도 아직 없다.
## 설계 방향
### 1. 스킬 문서 확장
`SKILL.md`는 현재의 짧은 요약형에서 벗어나, 원문에 더 가까운 아래 구조를 갖는다.
- 언제 사용하는지
- 반드시 지켜야 하는 규칙
- 단계별 작업 흐름
- 권장/비권장 행동
- 결과물 기대치
- 필요 시 예시 프롬프트 또는 운영 팁
모든 스킬을 원문 그대로 기계 번역하는 방식은 피한다. 대신 다음 원칙을 따른다.
- 원문 핵심 규칙, 체크리스트, 금지 사항은 최대한 보존한다.
- 한국어 사용성과 현재 프로젝트 맥락을 고려해 불필요한 외부 의존 서술은 줄인다.
- 지나치게 긴 원문은 구조화해서 읽기 쉽게 재편집한다.
- frontmatter `description`은 짧고 명확하게 유지한다.
### 2. README 구조
루트 `README.md`는 프로젝트 안내문 역할을 하며 아래 내용을 포함한다.
- 프로젝트 소개
- 포함된 10개 스킬 목록
- 디렉터리 구조 설명
- TRAE에서 사용하는 방법
- 추천 사용 흐름
- 문서 확장 기준 설명
- 테스트 시나리오 문서 위치 안내
README는 "이 저장소가 무엇인지, 어떻게 써야 하는지"를 처음 보는 사람도 바로 이해할 수 있게 작성한다.
### 3. 테스트 시나리오 문서
`docs/test-scenarios.md`는 실제 TRAE에서 복붙 가능한 검증 시나리오 모음으로 작성한다.
각 시나리오는 아래 형식을 따른다.
- 시나리오 목적
- 사전 조건
- 입력 프롬프트
- 기대 동작
- 확인 포인트
10개 스킬 각각 최소 1개 이상의 대표 시나리오를 둔다. 필요하면 공통 시나리오도 추가한다.
## 정보 구조
### 스킬 문서 일관성 규칙
모든 `SKILL.md`는 아래 섹션 순서를 가능한 한 맞춘다.
1. 개요
2. 언제 사용할지
3. 핵심 규칙
4. 단계 또는 워크플로
5. 금지 사항 또는 안티 패턴
6. 기대 결과
7. 예시 또는 운영 팁
스킬마다 성격이 다르므로 완전히 동일한 틀을 강제하지는 않지만, 사용자 관점에서 탐색성이 유지되도록 한다.
### README와 테스트 문서 연결
- README에서 테스트 시나리오 문서를 직접 링크한다.
- README에서 스킬별 문서 위치도 빠르게 찾을 수 있게 정리한다.
- 테스트 문서에서는 각 스킬 파일명을 명시해 사용자가 대응 관계를 이해할 수 있게 한다.
## 구현 단위
### 단위 A: 기존 스킬 문서 확장
대상 파일:
- `.trae/skills/brainstorming/SKILL.md`
- `.trae/skills/frontend-design/SKILL.md`
- `.trae/skills/ui-ux-pro-max/SKILL.md`
- `.trae/skills/systematic-debugging/SKILL.md`
- `.trae/skills/writing-plans/SKILL.md`
- `.trae/skills/find-skills/SKILL.md`
- `.trae/skills/using-superpowers/SKILL.md`
- `.trae/skills/karpathy-guidelines/SKILL.md`
- `.trae/skills/webapp-testing/SKILL.md`
- `.trae/skills/agent-browser/SKILL.md`
접근 방식:
- 이미 있는 한국어 문서를 기반으로 구조를 넓힌다.
- 원문에서 확인한 사용 시점, 워크플로, 금지 사항을 최대한 반영한다.
- 서로 중복되는 규칙은 표현은 달리하되 의미를 맞춘다.
### 단위 B: README 작성
대상 파일:
- `README.md`
접근 방식:
- 저장소 소개에서 시작해 사용 흐름으로 내려가는 구조를 사용한다.
- 표 또는 목록으로 10개 스킬을 빠르게 훑을 수 있게 한다.
- 문서 탐색 링크를 충분히 제공한다.
### 단위 C: 테스트 시나리오 작성
대상 파일:
- `docs/test-scenarios.md`
접근 방식:
- 각 스킬당 1개 이상 총 10개 이상의 대표 프롬프트를 작성한다.
- 실제 TRAE 사용자가 바로 실행할 수 있는 형태로 구체화한다.
- 기대 결과를 너무 추상적으로 쓰지 않고, 어떤 종류의 응답이 나와야 하는지 명시한다.
## 품질 기준
완료 판단 기준은 다음과 같다.
- 10개 스킬 문서가 현재보다 명확히 더 상세해진다.
- README만 읽어도 프로젝트 구조와 사용법을 이해할 수 있다.
- 테스트 시나리오 문서만으로 실제 검증을 시작할 수 있다.
- 문서 간 링크와 역할 분담이 자연스럽다.
- Markdown 진단 오류가 없다.
## 리스크와 대응
### 리스크 1: 문서가 과도하게 길어짐
대응:
- 핵심 규칙은 유지하되, 반복 표현은 줄인다.
- 표와 목록을 적극 사용한다.
### 리스크 2: 원문 충실도와 한국어 가독성 충돌
대응:
- 규칙과 단계는 원문에 가깝게 유지한다.
- 설명 문장은 한국어 사용성을 우선해 재구성한다.
### 리스크 3: 테스트 시나리오가 추상적이 됨
대응:
- 실제 입력 프롬프트를 그대로 넣는다.
- 기대 응답의 구조와 체크 포인트를 함께 적는다.
## 검증 계획
- 수정 후 각 Markdown 파일에 대해 진단을 확인한다.
- README, 테스트 문서, 스킬 문서 간 링크와 명칭 일관성을 점검한다.
- 시나리오가 실제 스킬 설명과 어긋나지 않는지 교차 검토한다.
## 최종 산출물
- 확장된 10개 `SKILL.md`
- 루트 `README.md`
- `docs/test-scenarios.md`
@@ -0,0 +1,192 @@
# SQLite + FastAPI + Vue CRUD 예제 설계
## 목표
기존의 단일 `'hello world'` 조회 예제를 확장해, SQLite에 저장된 메시지를 Vue 화면에서 생성(Create), 조회(Read), 수정(Update), 삭제(Delete)할 수 있는 목록형 CRUD 예제로 만든다.
## 범위
이번 작업은 다음을 포함한다.
- SQLite `messages` 테이블 유지
- 메시지 목록 조회 API 추가
- 메시지 생성 API 추가
- 메시지 수정 API 추가
- 메시지 삭제 API 추가
- Vue 화면에서 목록형 CRUD UI 구현
- 초기 데이터로 `hello world` 1건 유지
- 실행 문서 업데이트
이번 작업은 다음을 포함하지 않는다.
- 인증/권한
- 검색/정렬/페이지네이션
- 다중 테이블 관계
- 복잡한 폼 검증
- 배포 설정
## 구조
기존 분리형 구조를 그대로 유지한다.
```text
skillDesk/
├── backend/
│ ├── init_db.py
│ ├── main.py
│ ├── requirements.txt
│ └── app.db
├── frontend/
│ ├── index.html
│ └── src/
│ └── main.js
└── README.md
```
## 데이터 모델
테이블명: `messages`
컬럼:
- `id` INTEGER PRIMARY KEY AUTOINCREMENT
- `content` TEXT NOT NULL
메시지 단위는 매우 단순하게 유지한다. 별도 제목, 작성일, 상태 컬럼은 추가하지 않는다.
## API 설계
### 1. 목록 조회
`GET /api/messages`
응답 예시:
```json
[
{ "id": 1, "content": "hello world" }
]
```
### 2. 생성
`POST /api/messages`
요청 예시:
```json
{
"content": "new message"
}
```
응답 예시:
```json
{
"id": 2,
"content": "new message"
}
```
### 3. 수정
`PUT /api/messages/{id}`
요청 예시:
```json
{
"content": "updated message"
}
```
응답 예시:
```json
{
"id": 1,
"content": "updated message"
}
```
### 4. 삭제
`DELETE /api/messages/{id}`
응답 예시:
```json
{
"success": true
}
```
## 백엔드 설계
- FastAPI는 기존 CORS 설정을 유지한다.
- sqlite3 표준 라이브러리를 사용한다.
- 입력 모델은 최소한으로 `content` 문자열만 받는다.
- 빈 문자열은 거부한다.
- 존재하지 않는 id에 대한 수정/삭제는 404로 반환한다.
## 프론트엔드 설계
### 화면 구성
- 상단 제목과 설명
- 새 메시지 입력 폼
- 메시지 목록 영역
- 각 항목의 수정 / 삭제 버튼
- 수정 모드일 때 인라인 입력창과 저장 / 취소 버튼
- 로딩 / 에러 / 빈 목록 상태 표시
### 사용자 흐름
1. 페이지 진입 시 목록을 불러온다.
2. 입력창에 값을 넣고 생성 버튼을 누르면 메시지가 추가된다.
3. 각 항목의 수정 버튼을 누르면 해당 줄이 편집 모드로 바뀐다.
4. 저장 시 수정 API를 호출하고 목록을 갱신한다.
5. 삭제 시 삭제 API를 호출하고 목록을 갱신한다.
### 상태
다음 상태를 최소로 둔다.
- 전체 목록
- 새 메시지 입력값
- 현재 편집 중인 메시지 id
- 편집 중 입력값
- 로딩 상태
- 에러 상태
## 데이터 흐름
1. `init_db.py`가 DB를 만들고 `hello world`를 기본 데이터로 넣는다.
2. Vue는 페이지 로드 시 `GET /api/messages`를 호출한다.
3. 사용자가 생성/수정/삭제를 수행하면 해당 API를 호출한다.
4. 요청 성공 후 목록을 다시 불러오거나 로컬 상태를 갱신한다.
## 오류 처리
- 빈 메시지 생성/수정은 프론트엔드와 백엔드 모두에서 막는다.
- 없는 메시지 수정/삭제는 404로 처리한다.
- API 실패 시 화면에 간단한 오류 문구를 표시한다.
## 검증 기준
다음 조건을 만족하면 성공이다.
- 초기 화면에 `hello world`가 포함된 목록이 표시된다.
- 새 메시지를 추가할 수 있다.
- 기존 메시지를 수정할 수 있다.
- 기존 메시지를 삭제할 수 있다.
- 삭제 후 목록이 즉시 반영된다.
- README 실행 방법이 최신 흐름에 맞게 정리된다.
## 구현 원칙
- 기존 예제 구조를 최대한 유지한다.
- 불필요한 라이브러리는 추가하지 않는다.
- CRUD 흐름이 한눈에 보이는 최소 UI를 만든다.
- 과도한 추상화보다 이해하기 쉬운 코드를 우선한다.
@@ -0,0 +1,140 @@
# SQLite + FastAPI + Vue Hello World 예제 설계
## 목표
SQLite 데이터베이스에 저장된 문자열 `'hello world'`를 Python FastAPI 백엔드가 읽고, Vue 프론트엔드가 API를 호출해 화면에 표시하는 최소 동작 예제를 만든다.
## 범위
이번 예제는 다음 범위를 포함한다.
- SQLite DB 파일 생성
- 메시지 테이블 생성과 샘플 데이터 삽입
- FastAPI에서 SQLite 데이터를 읽는 API 구현
- Vue에서 API를 호출해 화면에 문자열 출력
- 실행 방법 문서화
이번 예제는 다음 범위를 포함하지 않는다.
- 사용자 입력 폼
- CRUD 전체 기능
- 인증/권한
- 상태관리 라이브러리
- 배포 구성
## 구조
예제는 프론트엔드와 백엔드를 분리한 최소 구조로 만든다.
```text
skillDesk/
├── backend/
│ ├── main.py
│ ├── init_db.py
│ ├── requirements.txt
│ └── app.db
├── frontend/
│ ├── package.json
│ ├── vite.config.js
│ └── src/
│ ├── App.vue
│ └── main.js
└── README.md
```
## 데이터 흐름
1. `backend/init_db.py`가 SQLite 데이터베이스 파일을 만들고 `messages` 테이블을 생성한다.
2. 초기 데이터로 `'hello world'` 한 건을 삽입한다.
3. `backend/main.py``GET /api/message` 엔드포인트가 SQLite에서 첫 메시지를 읽는다.
4. Vue 앱이 페이지 로드 시 `/api/message`를 호출한다.
5. 응답 JSON의 메시지를 화면에 렌더링한다.
## 백엔드 설계
### 기술 선택
- Python
- FastAPI
- sqlite3 표준 라이브러리
- uvicorn
### 엔드포인트
`GET /api/message`
응답 예시:
```json
{
"message": "hello world"
}
```
### DB 스키마
테이블명: `messages`
컬럼:
- `id` INTEGER PRIMARY KEY AUTOINCREMENT
- `content` TEXT NOT NULL
### CORS
개발 중 Vue dev server에서 FastAPI API를 호출할 수 있도록 최소 CORS 설정을 추가한다.
## 프론트엔드 설계
### 기술 선택
- Vue 3
- Vite
### 동작
- 앱이 마운트되면 FastAPI API를 호출한다.
- 로딩 중에는 간단한 로딩 문구를 표시한다.
- 성공하면 DB에서 받은 `'hello world'`를 표시한다.
- 실패하면 간단한 에러 문구를 표시한다.
### 화면 구성
예제는 최소 화면만 구성한다.
- 제목
- API에서 받은 메시지 출력 영역
- 로딩/에러 상태 문구
## 실행 흐름
1. Python 가상환경 생성 및 의존성 설치
2. SQLite 초기화 스크립트 실행
3. FastAPI 서버 실행
4. Vue 의존성 설치
5. Vue 개발 서버 실행
6. 브라우저에서 메시지 표시 확인
## 검증 기준
다음 조건을 만족하면 예제가 성공이다.
- SQLite DB 파일이 생성된다.
- `messages` 테이블에 `'hello world'`가 저장된다.
- `GET /api/message` 호출 시 JSON 응답이 반환된다.
- Vue 화면에서 `'hello world'`가 보인다.
- 백엔드와 프론트엔드 실행 방법이 README에 정리된다.
## 오류 처리
최소 예제이므로 복잡한 예외 처리 대신 아래 수준만 포함한다.
- DB에 메시지가 없으면 기본 에러 응답 반환
- 프론트엔드 fetch 실패 시 에러 문구 표시
## 구현 원칙
- 예제는 최대한 짧고 이해하기 쉬워야 한다.
- 구조는 실제 앱 구조와 유사하게 분리한다.
- 과도한 추상화는 하지 않는다.
- 의존성은 최소화한다.
+114
View File
@@ -0,0 +1,114 @@
# TRAE 테스트 시나리오
이 문서는 현재 저장소에 포함된 10개 스킬을 실제 TRAE에서 바로 검증해 볼 수 있도록 만든 프롬프트형 시나리오 모음입니다.
## 공통 사용법
- 각 시나리오의 **입력 프롬프트**를 그대로 복사해서 TRAE에 넣습니다.
- 기대 동작은 "정답 문장"이 아니라 "어떤 종류의 흐름이 나와야 하는지"를 의미합니다.
- 결과가 다소 다르더라도, 핵심 스킬 호출과 절차가 맞으면 통과로 봅니다.
---
## 1. brainstorming
- **목적:** 구현 전에 설계 중심 흐름으로 들어가는지 확인
- **사전 조건:** 현재 프로젝트가 열려 있어야 함
- **입력 프롬프트:** `간단한 할일 관리 위젯을 추가하고 싶은데 바로 구현하지 말고 먼저 어떻게 설계할지 같이 정리해줘`
- **기대 동작:** 바로 코드 작성으로 들어가지 않고, 질문 또는 설계 흐름으로 진입해야 함
- **확인 포인트:** 한 번에 한 질문, 설계 승인 전 구현 금지, 이후 `writing-plans`로 이어질 여지가 보여야 함
## 2. frontend-design
- **목적:** 평범한 UI 생성이 아니라 강한 미학 방향을 먼저 잡는지 확인
- **사전 조건:** 프론트엔드 결과물을 요청할 수 있는 문맥
- **입력 프롬프트:** `패션 브랜드용 랜딩페이지 히어로 섹션을 만들어줘. 흔한 AI 스타일 말고 강한 개성이 있었으면 좋겠어`
- **기대 동작:** 톤, 타이포그래피, 색상, 레이아웃 같은 미학 방향을 언급해야 함
- **확인 포인트:** "AI 티 나는 화면" 회피, 대담한 스타일 방향, 실제 구현 코드 의도 설명
## 3. ui-ux-pro-max
- **목적:** UI 미감뿐 아니라 UX 품질 기준까지 함께 다루는지 확인
- **사전 조건:** UI 구조 개선 요청 가능
- **입력 프롬프트:** `관리자 대시보드가 뭔가 덜 프로페셔널해 보여. 정보 위계, 접근성, 상호작용 품질 관점에서 개선 방향을 제안해줘`
- **기대 동작:** 접근성, 위계, 상태 표현, 레이아웃, 상호작용 품질을 우선순위 있게 다뤄야 함
- **확인 포인트:** 단순 색상 추천이 아니라 시스템 수준의 개선 기준 제시
## 4. systematic-debugging
- **목적:** 버그 수정 전에 근본 원인 조사 흐름을 밟는지 확인
- **사전 조건:** 버그 상황을 설명할 수 있어야 함
- **입력 프롬프트:** `로그인 후 가끔 대시보드가 빈 화면으로 떠. 일단 추측하지 말고 체계적으로 원인부터 찾는 방식으로 진행해줘`
- **기대 동작:** 재현, 최근 변경, 로그/증거 수집, 가설 검증 순서를 제시해야 함
- **확인 포인트:** 즉시 수정안부터 제안하지 않는지, 원인 조사 단계가 분리되는지
## 5. writing-plans
- **목적:** 구현 전에 체크리스트형 계획을 만드는지 확인
- **사전 조건:** 간단한 요구사항 또는 명세가 있어야 함
- **입력 프롬프트:** `사용자 프로필 편집 기능을 추가해야 해. 코드는 아직 건드리지 말고 파일 단위와 테스트 단위까지 포함한 구현 계획만 작성해줘`
- **기대 동작:** 파일 경로, 작업 순서, 검증 기준, 테스트 단계가 포함된 계획을 작성해야 함
- **확인 포인트:** TODO 수준이 아니라 실행 가능한 단계인지, 작은 단계로 분해되는지
## 6. find-skills
- **목적:** 바로 구현보다 적절한 커뮤니티 스킬 탐색 흐름을 타는지 확인
- **사전 조건:** 특정 작업용 스킬을 찾는 상황
- **입력 프롬프트:** `PR 리뷰를 더 체계적으로 해주는 스킬이 있는지 찾아줘`
- **기대 동작:** 필요한 도메인을 파악하고, 인기/품질 기준을 거쳐 후보를 제시해야 함
- **확인 포인트:** 검색만이 아니라 설치 수, 출처, 설치 명령까지 제공하는지
## 7. using-superpowers
- **목적:** 응답 전에 관련 스킬을 먼저 확인하는 운영 규칙이 작동하는지 확인
- **사전 조건:** 다른 스킬이 분명히 필요한 작업 요청
- **입력 프롬프트:** `새로운 대시보드 페이지를 설계하고 구현해줘`
- **기대 동작:** 바로 구현하기보다 먼저 관련 스킬을 확인하고 적용해야 함
- **확인 포인트:** 프로세스 스킬 우선, 구현 스킬 후순위 원칙이 드러나는지
## 8. karpathy-guidelines
- **목적:** 과설계와 과추정을 줄이는 행동 원칙이 반영되는지 확인
- **사전 조건:** 코드 변경 또는 리팩터링 맥락
- **입력 프롬프트:** `이 기능 리팩터링하되 너무 크게 뜯어고치지 말고 필요한 최소 변경만으로 접근해줘`
- **기대 동작:** 가정 명시, 최소 변경, 검증 기준 중심으로 접근해야 함
- **확인 포인트:** 주변 코드까지 과하게 손대지 않는지, 목표 기반으로 설명하는지
## 9. webapp-testing
- **목적:** 로컬 웹앱 테스트에서 정찰 후 행동 패턴을 따르는지 확인
- **사전 조건:** 로컬 웹앱 또는 정적 HTML을 테스트할 수 있는 상황
- **입력 프롬프트:** `이 로컬 웹앱의 회원가입 폼을 Playwright 방식으로 점검해줘. 바로 클릭하지 말고 먼저 화면 상태부터 확인해줘`
- **기대 동작:** `networkidle` 대기, 스크린샷 또는 DOM 확인, 셀렉터 파악 후 행동 순서를 보여야 함
- **확인 포인트:** 먼저 관찰하고 나중에 상호작용하는지
## 10. agent-browser
- **목적:** 일반 브라우저 도구보다 agent-browser 흐름이 필요한 상황을 인식하는지 확인
- **사전 조건:** 브라우저 자동화 요청
- **입력 프롬프트:** `특정 사이트에 로그인해서 여러 페이지를 돌아다니며 상태를 확인하고 스크린샷도 남겨줘`
- **기대 동작:** `agent-browser skills get core` 같은 시작 절차를 우선 언급해야 함
- **확인 포인트:** 설치된 버전 기준 가이드를 먼저 확인하는지, 특수 가이드 가능성도 보는지
---
## 교차 시나리오 1: 설계 -> 계획
- **목적:** `brainstorming`에서 `writing-plans`로 자연스럽게 이어지는지 확인
- **입력 프롬프트:** `알림 센터 기능을 추가하고 싶어. 먼저 설계부터 하고, 내가 승인하면 계획까지 이어가자`
- **기대 동작:** 처음에는 설계 흐름, 승인 후에는 계획 문서 흐름으로 전환
- **확인 포인트:** 설계와 구현 계획 단계가 섞이지 않는지
## 교차 시나리오 2: 디버깅 -> 검증
- **목적:** 버그 분석 이후 실제 검증 단계로 이어질 수 있는지 확인
- **입력 프롬프트:** `폼 제출 버그를 먼저 근본 원인부터 찾고, 수정 전후 동작을 브라우저에서 검증할 수 있게 정리해줘`
- **기대 동작:** `systematic-debugging` 중심으로 조사하고, 필요 시 `webapp-testing` 또는 브라우저 검증 흐름으로 이어짐
- **확인 포인트:** 원인 분석과 검증이 분리되면서도 연결되는지
## 교차 시나리오 3: UI 설계 -> 품질 향상
- **목적:** `frontend-design``ui-ux-pro-max`가 역할을 나눠 쓰이는지 확인
- **입력 프롬프트:** `이 SaaS 설정 페이지를 더 개성 있게 만들고 싶어. 동시에 접근성과 정보 위계도 챙겨줘`
- **기대 동작:** 미학 방향과 UX 품질 기준을 함께 다루되, 역할이 구분되어야 함
- **확인 포인트:** 스타일 강화와 UX 품질 점검이 모두 보이는지
+18
View File
@@ -0,0 +1,18 @@
<!doctype html> <!-- 문서 타입을 HTML5로 선언한다. -->
<html lang="ko"> <!-- 문서 기본 언어를 한국어로 설정한다. -->
<head> <!-- 문서 메타데이터 영역을 시작한다. -->
<meta charset="UTF-8" /> <!-- 문자 인코딩을 UTF-8로 지정한다. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <!-- 모바일 화면 크기에 맞춰 레이아웃이 동작하도록 설정한다. -->
<title>SQLite + FastAPI + Vue Hello World</title> <!-- 브라우저 탭 제목을 지정한다. -->
</head> <!-- 문서 메타데이터 영역을 닫는다. -->
<body> <!-- 사용자에게 보이는 본문 영역을 시작한다. -->
<div id="app"></div> <!-- Vue 애플리케이션이 마운트될 루트 요소를 배치한다. -->
<script> <!-- Vue 앱이 읽을 전역 설정 객체를 먼저 선언한다. -->
window.APP_CONFIG = { // 백엔드 API 연결 정보를 전역 설정 객체로 저장한다.
apiHost: 'http://127.0.0.1', // 기본 백엔드 호스트 주소를 설정한다.
apiPort: '8000', // 기본 백엔드 포트 번호를 설정한다.
} // 전역 설정 객체 정의를 마무리한다.
</script> <!-- 전역 설정 객체 선언 스크립트를 닫는다. -->
<script type="module" src="/src/main.js"></script> <!-- Vue 진입 스크립트를 불러온다. -->
</body> <!-- 사용자에게 보이는 본문 영역을 닫는다. -->
</html> <!-- HTML 문서를 마무리한다. -->
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../esbuild/bin/esbuild
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../nanoid/bin/nanoid.cjs
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../@babel/parser/bin/babel-parser.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../rollup/dist/bin/rollup
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../vite/bin/vite.js
+443
View File
@@ -0,0 +1,443 @@
{
"name": "sqlite-fastapi-vue-hello",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@babel/helper-string-parser": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
"license": "MIT",
"dependencies": {
"@babel/types": "^7.29.7"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/types": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.29.7",
"@babel/helper-validator-identifier": "^7.29.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
"integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
"dev": true,
"license": "MIT"
},
"node_modules/@vue/compiler-core": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz",
"integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.3",
"@vue/shared": "3.5.35",
"entities": "^7.0.1",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz",
"integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==",
"license": "MIT",
"dependencies": {
"@vue/compiler-core": "3.5.35",
"@vue/shared": "3.5.35"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz",
"integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.3",
"@vue/compiler-core": "3.5.35",
"@vue/compiler-dom": "3.5.35",
"@vue/compiler-ssr": "3.5.35",
"@vue/shared": "3.5.35",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.21",
"postcss": "^8.5.15",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz",
"integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==",
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.35",
"@vue/shared": "3.5.35"
}
},
"node_modules/@vue/reactivity": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.35.tgz",
"integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==",
"license": "MIT",
"dependencies": {
"@vue/shared": "3.5.35"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.35.tgz",
"integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.35",
"@vue/shared": "3.5.35"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz",
"integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.35",
"@vue/runtime-core": "3.5.35",
"@vue/shared": "3.5.35",
"csstype": "^3.2.3"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.35.tgz",
"integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==",
"license": "MIT",
"dependencies": {
"@vue/compiler-ssr": "3.5.35",
"@vue/shared": "3.5.35"
},
"peerDependencies": {
"vue": "3.5.35"
}
},
"node_modules/@vue/shared": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz",
"integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==",
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"license": "MIT"
},
"node_modules/entities": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/esbuild": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.21.5",
"@esbuild/android-arm": "0.21.5",
"@esbuild/android-arm64": "0.21.5",
"@esbuild/android-x64": "0.21.5",
"@esbuild/darwin-arm64": "0.21.5",
"@esbuild/darwin-x64": "0.21.5",
"@esbuild/freebsd-arm64": "0.21.5",
"@esbuild/freebsd-x64": "0.21.5",
"@esbuild/linux-arm": "0.21.5",
"@esbuild/linux-arm64": "0.21.5",
"@esbuild/linux-ia32": "0.21.5",
"@esbuild/linux-loong64": "0.21.5",
"@esbuild/linux-mips64el": "0.21.5",
"@esbuild/linux-ppc64": "0.21.5",
"@esbuild/linux-riscv64": "0.21.5",
"@esbuild/linux-s390x": "0.21.5",
"@esbuild/linux-x64": "0.21.5",
"@esbuild/netbsd-x64": "0.21.5",
"@esbuild/openbsd-x64": "0.21.5",
"@esbuild/sunos-x64": "0.21.5",
"@esbuild/win32-arm64": "0.21.5",
"@esbuild/win32-ia32": "0.21.5",
"@esbuild/win32-x64": "0.21.5"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"license": "MIT"
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/nanoid": {
"version": "3.3.12",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"license": "ISC"
},
"node_modules/postcss": {
"version": "8.5.15",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.12",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/rollup": {
"version": "4.61.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz",
"integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.9"
},
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.61.1",
"@rollup/rollup-android-arm64": "4.61.1",
"@rollup/rollup-darwin-arm64": "4.61.1",
"@rollup/rollup-darwin-x64": "4.61.1",
"@rollup/rollup-freebsd-arm64": "4.61.1",
"@rollup/rollup-freebsd-x64": "4.61.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.61.1",
"@rollup/rollup-linux-arm-musleabihf": "4.61.1",
"@rollup/rollup-linux-arm64-gnu": "4.61.1",
"@rollup/rollup-linux-arm64-musl": "4.61.1",
"@rollup/rollup-linux-loong64-gnu": "4.61.1",
"@rollup/rollup-linux-loong64-musl": "4.61.1",
"@rollup/rollup-linux-ppc64-gnu": "4.61.1",
"@rollup/rollup-linux-ppc64-musl": "4.61.1",
"@rollup/rollup-linux-riscv64-gnu": "4.61.1",
"@rollup/rollup-linux-riscv64-musl": "4.61.1",
"@rollup/rollup-linux-s390x-gnu": "4.61.1",
"@rollup/rollup-linux-x64-gnu": "4.61.1",
"@rollup/rollup-linux-x64-musl": "4.61.1",
"@rollup/rollup-openbsd-x64": "4.61.1",
"@rollup/rollup-openharmony-arm64": "4.61.1",
"@rollup/rollup-win32-arm64-msvc": "4.61.1",
"@rollup/rollup-win32-ia32-msvc": "4.61.1",
"@rollup/rollup-win32-x64-gnu": "4.61.1",
"@rollup/rollup-win32-x64-msvc": "4.61.1",
"fsevents": "~2.3.2"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/vite": {
"version": "5.4.21",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
"rollup": "^4.20.0"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
},
"peerDependencies": {
"@types/node": "^18.0.0 || >=20.0.0",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"lightningcss": {
"optional": true
},
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
},
"node_modules/vue": {
"version": "3.5.35",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.35.tgz",
"integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==",
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.35",
"@vue/compiler-sfc": "3.5.35",
"@vue/runtime-dom": "3.5.35",
"@vue/server-renderer": "3.5.35",
"@vue/shared": "3.5.35"
},
"peerDependencies": {
"typescript": "*"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
}
}
}
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+19
View File
@@ -0,0 +1,19 @@
# @babel/helper-string-parser
> A utility package to parse strings
See our website [@babel/helper-string-parser](https://babeljs.io/docs/babel-helper-string-parser) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-string-parser
```
or using yarn:
```sh
yarn add @babel/helper-string-parser
```
+295
View File
@@ -0,0 +1,295 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.readCodePoint = readCodePoint;
exports.readInt = readInt;
exports.readStringContents = readStringContents;
var _isDigit = function isDigit(code) {
return code >= 48 && code <= 57;
};
const forbiddenNumericSeparatorSiblings = {
decBinOct: new Set([46, 66, 69, 79, 95, 98, 101, 111]),
hex: new Set([46, 88, 95, 120])
};
const isAllowedNumericSeparatorSibling = {
bin: ch => ch === 48 || ch === 49,
oct: ch => ch >= 48 && ch <= 55,
dec: ch => ch >= 48 && ch <= 57,
hex: ch => ch >= 48 && ch <= 57 || ch >= 65 && ch <= 70 || ch >= 97 && ch <= 102
};
function readStringContents(type, input, pos, lineStart, curLine, errors) {
const initialPos = pos;
const initialLineStart = lineStart;
const initialCurLine = curLine;
let out = "";
let firstInvalidLoc = null;
let chunkStart = pos;
const {
length
} = input;
for (;;) {
if (pos >= length) {
errors.unterminated(initialPos, initialLineStart, initialCurLine);
out += input.slice(chunkStart, pos);
break;
}
const ch = input.charCodeAt(pos);
if (isStringEnd(type, ch, input, pos)) {
out += input.slice(chunkStart, pos);
break;
}
if (ch === 92) {
out += input.slice(chunkStart, pos);
const res = readEscapedChar(input, pos, lineStart, curLine, type === "template", errors);
if (res.ch === null && !firstInvalidLoc) {
firstInvalidLoc = {
pos,
lineStart,
curLine
};
} else {
out += res.ch;
}
({
pos,
lineStart,
curLine
} = res);
chunkStart = pos;
} else if (ch === 8232 || ch === 8233) {
++pos;
++curLine;
lineStart = pos;
} else if (ch === 10 || ch === 13) {
if (type === "template") {
out += input.slice(chunkStart, pos) + "\n";
++pos;
if (ch === 13 && input.charCodeAt(pos) === 10) {
++pos;
}
++curLine;
chunkStart = lineStart = pos;
} else {
errors.unterminated(initialPos, initialLineStart, initialCurLine);
}
} else {
++pos;
}
}
return {
pos,
str: out,
firstInvalidLoc,
lineStart,
curLine,
containsInvalid: !!firstInvalidLoc
};
}
function isStringEnd(type, ch, input, pos) {
if (type === "template") {
return ch === 96 || ch === 36 && input.charCodeAt(pos + 1) === 123;
}
return ch === (type === "double" ? 34 : 39);
}
function readEscapedChar(input, pos, lineStart, curLine, inTemplate, errors) {
const throwOnInvalid = !inTemplate;
pos++;
const res = ch => ({
pos,
ch,
lineStart,
curLine
});
const ch = input.charCodeAt(pos++);
switch (ch) {
case 110:
return res("\n");
case 114:
return res("\r");
case 120:
{
let code;
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, 2, false, throwOnInvalid, errors));
return res(code === null ? null : String.fromCharCode(code));
}
case 117:
{
let code;
({
code,
pos
} = readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors));
return res(code === null ? null : String.fromCodePoint(code));
}
case 116:
return res("\t");
case 98:
return res("\b");
case 118:
return res("\u000b");
case 102:
return res("\f");
case 13:
if (input.charCodeAt(pos) === 10) {
++pos;
}
case 10:
lineStart = pos;
++curLine;
case 8232:
case 8233:
return res("");
case 56:
case 57:
if (inTemplate) {
return res(null);
} else {
errors.strictNumericEscape(pos - 1, lineStart, curLine);
}
default:
if (ch >= 48 && ch <= 55) {
const startPos = pos - 1;
const match = /^[0-7]+/.exec(input.slice(startPos, pos + 2));
let octalStr = match[0];
let octal = parseInt(octalStr, 8);
if (octal > 255) {
octalStr = octalStr.slice(0, -1);
octal = parseInt(octalStr, 8);
}
pos += octalStr.length - 1;
const next = input.charCodeAt(pos);
if (octalStr !== "0" || next === 56 || next === 57) {
if (inTemplate) {
return res(null);
} else {
errors.strictNumericEscape(startPos, lineStart, curLine);
}
}
return res(String.fromCharCode(octal));
}
return res(String.fromCharCode(ch));
}
}
function readHexChar(input, pos, lineStart, curLine, len, forceLen, throwOnInvalid, errors) {
const initialPos = pos;
let n;
({
n,
pos
} = readInt(input, pos, lineStart, curLine, 16, len, forceLen, false, errors, !throwOnInvalid));
if (n === null) {
if (throwOnInvalid) {
errors.invalidEscapeSequence(initialPos, lineStart, curLine);
} else {
pos = initialPos - 1;
}
}
return {
code: n,
pos
};
}
function readInt(input, pos, lineStart, curLine, radix, len, forceLen, allowNumSeparator, errors, bailOnError) {
const start = pos;
const forbiddenSiblings = radix === 16 ? forbiddenNumericSeparatorSiblings.hex : forbiddenNumericSeparatorSiblings.decBinOct;
const isAllowedSibling = radix === 16 ? isAllowedNumericSeparatorSibling.hex : radix === 10 ? isAllowedNumericSeparatorSibling.dec : radix === 8 ? isAllowedNumericSeparatorSibling.oct : isAllowedNumericSeparatorSibling.bin;
let invalid = false;
let total = 0;
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
const code = input.charCodeAt(pos);
let val;
if (code === 95 && allowNumSeparator !== "bail") {
const prev = input.charCodeAt(pos - 1);
const next = input.charCodeAt(pos + 1);
if (!allowNumSeparator) {
if (bailOnError) return {
n: null,
pos
};
errors.numericSeparatorInEscapeSequence(pos, lineStart, curLine);
} else if (Number.isNaN(next) || !isAllowedSibling(next) || forbiddenSiblings.has(prev) || forbiddenSiblings.has(next)) {
if (bailOnError) return {
n: null,
pos
};
errors.unexpectedNumericSeparator(pos, lineStart, curLine);
}
++pos;
continue;
}
if (code >= 97) {
val = code - 97 + 10;
} else if (code >= 65) {
val = code - 65 + 10;
} else if (_isDigit(code)) {
val = code - 48;
} else {
val = Infinity;
}
if (val >= radix) {
if (val <= 9 && bailOnError) {
return {
n: null,
pos
};
} else if (val <= 9 && errors.invalidDigit(pos, lineStart, curLine, radix)) {
val = 0;
} else if (forceLen) {
val = 0;
invalid = true;
} else {
break;
}
}
++pos;
total = total * radix + val;
}
if (pos === start || len != null && pos - start !== len || invalid) {
return {
n: null,
pos
};
}
return {
n: total,
pos
};
}
function readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors) {
const ch = input.charCodeAt(pos);
let code;
if (ch === 123) {
++pos;
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, input.indexOf("}", pos) - pos, true, throwOnInvalid, errors));
++pos;
if (code !== null && code > 0x10ffff) {
if (throwOnInvalid) {
errors.invalidCodePoint(pos, lineStart, curLine);
} else {
return {
code: null,
pos
};
}
}
} else {
({
code,
pos
} = readHexChar(input, pos, lineStart, curLine, 4, false, throwOnInvalid, errors));
}
return {
code,
pos
};
}
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+31
View File
@@ -0,0 +1,31 @@
{
"name": "@babel/helper-string-parser",
"version": "7.29.7",
"description": "A utility package to parse strings",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-helper-string-parser"
},
"homepage": "https://babel.dev/docs/en/next/babel-helper-string-parser",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "./lib/index.js",
"devDependencies": {
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"author": "The Babel Team (https://babel.dev/team)",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"type": "commonjs"
}
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+19
View File
@@ -0,0 +1,19 @@
# @babel/helper-validator-identifier
> Validate identifier/keywords name
See our website [@babel/helper-validator-identifier](https://babeljs.io/docs/babel-helper-validator-identifier) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-validator-identifier
```
or using yarn:
```sh
yarn add @babel/helper-validator-identifier
```
@@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isIdentifierChar = isIdentifierChar;
exports.isIdentifierName = isIdentifierName;
exports.isIdentifierStart = isIdentifierStart;
let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088f\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5c\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdc-\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7dc\ua7f1-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
let nonASCIIidentifierChars = "\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0897-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0cf3\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ece\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1add\u1ae0-\u1aeb\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f\uff65";
const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
const astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 7, 25, 39, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 39, 27, 10, 22, 251, 41, 7, 1, 17, 5, 57, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 44, 33, 24, 27, 35, 30, 0, 3, 0, 9, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 20, 1, 64, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 52, 19, 3, 21, 2, 31, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 38, 6, 186, 43, 117, 63, 32, 7, 3, 0, 3, 7, 2, 1, 2, 23, 16, 0, 2, 0, 95, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 19, 72, 200, 32, 32, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 24, 43, 261, 18, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 33, 24, 3, 24, 45, 74, 6, 0, 67, 12, 65, 1, 2, 0, 15, 4, 10, 7381, 42, 31, 98, 114, 8702, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 208, 30, 2, 2, 2, 1, 2, 6, 3, 4, 10, 1, 225, 6, 2, 3, 2, 1, 2, 14, 2, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42719, 33, 4381, 3, 5773, 3, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 8489];
const astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 78, 5, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 14, 5, 9, 243, 14, 166, 9, 71, 5, 2, 1, 3, 3, 2, 0, 2, 1, 13, 9, 120, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 199, 7, 137, 9, 54, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 55, 9, 266, 3, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 233, 0, 3, 0, 8, 1, 6, 0, 475, 6, 110, 6, 6, 9, 4759, 9, 787719, 239];
function isInAstralSet(code, set) {
let pos = 0x10000;
for (let i = 0, length = set.length; i < length; i += 2) {
pos += set[i];
if (pos > code) return false;
pos += set[i + 1];
if (pos >= code) return true;
}
return false;
}
function isIdentifierStart(code) {
if (code < 65) return code === 36;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes);
}
function isIdentifierChar(code) {
if (code < 48) return code === 36;
if (code < 58) return true;
if (code < 65) return false;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
}
function isIdentifierName(name) {
let isFirst = true;
for (let i = 0; i < name.length; i++) {
let cp = name.charCodeAt(i);
if ((cp & 0xfc00) === 0xd800 && i + 1 < name.length) {
const trail = name.charCodeAt(++i);
if ((trail & 0xfc00) === 0xdc00) {
cp = 0x10000 + ((cp & 0x3ff) << 10) + (trail & 0x3ff);
}
}
if (isFirst) {
isFirst = false;
if (!isIdentifierStart(cp)) {
return false;
}
} else if (!isIdentifierChar(cp)) {
return false;
}
}
return !isFirst;
}
//# sourceMappingURL=identifier.js.map
File diff suppressed because one or more lines are too long
+57
View File
@@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "isIdentifierChar", {
enumerable: true,
get: function () {
return _identifier.isIdentifierChar;
}
});
Object.defineProperty(exports, "isIdentifierName", {
enumerable: true,
get: function () {
return _identifier.isIdentifierName;
}
});
Object.defineProperty(exports, "isIdentifierStart", {
enumerable: true,
get: function () {
return _identifier.isIdentifierStart;
}
});
Object.defineProperty(exports, "isKeyword", {
enumerable: true,
get: function () {
return _keyword.isKeyword;
}
});
Object.defineProperty(exports, "isReservedWord", {
enumerable: true,
get: function () {
return _keyword.isReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindOnlyReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindOnlyReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindReservedWord;
}
});
Object.defineProperty(exports, "isStrictReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictReservedWord;
}
});
var _identifier = require("./identifier.js");
var _keyword = require("./keyword.js");
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"names":["_identifier","require","_keyword"],"sources":["../src/index.ts"],"sourcesContent":["export {\n isIdentifierName,\n isIdentifierChar,\n isIdentifierStart,\n} from \"./identifier.ts\";\nexport {\n isReservedWord,\n isStrictBindOnlyReservedWord,\n isStrictBindReservedWord,\n isStrictReservedWord,\n isKeyword,\n} from \"./keyword.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAKA,IAAAC,QAAA,GAAAD,OAAA","ignoreList":[]}
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isKeyword = isKeyword;
exports.isReservedWord = isReservedWord;
exports.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
exports.isStrictBindReservedWord = isStrictBindReservedWord;
exports.isStrictReservedWord = isStrictReservedWord;
const reservedWords = {
keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
strictBind: ["eval", "arguments"]
};
const keywords = new Set(reservedWords.keyword);
const reservedWordsStrictSet = new Set(reservedWords.strict);
const reservedWordsStrictBindSet = new Set(reservedWords.strictBind);
function isReservedWord(word, inModule) {
return inModule && word === "await" || word === "enum";
}
function isStrictReservedWord(word, inModule) {
return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
}
function isStrictBindOnlyReservedWord(word) {
return reservedWordsStrictBindSet.has(word);
}
function isStrictBindReservedWord(word, inModule) {
return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word);
}
function isKeyword(word) {
return keywords.has(word);
}
//# sourceMappingURL=keyword.js.map
@@ -0,0 +1 @@
{"version":3,"names":["reservedWords","keyword","strict","strictBind","keywords","Set","reservedWordsStrictSet","reservedWordsStrictBindSet","isReservedWord","word","inModule","isStrictReservedWord","has","isStrictBindOnlyReservedWord","isStrictBindReservedWord","isKeyword"],"sources":["../src/keyword.ts"],"sourcesContent":["const reservedWords = {\n keyword: [\n \"break\",\n \"case\",\n \"catch\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"do\",\n \"else\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"return\",\n \"switch\",\n \"throw\",\n \"try\",\n \"var\",\n \"const\",\n \"while\",\n \"with\",\n \"new\",\n \"this\",\n \"super\",\n \"class\",\n \"extends\",\n \"export\",\n \"import\",\n \"null\",\n \"true\",\n \"false\",\n \"in\",\n \"instanceof\",\n \"typeof\",\n \"void\",\n \"delete\",\n ],\n strict: [\n \"implements\",\n \"interface\",\n \"let\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"static\",\n \"yield\",\n ],\n strictBind: [\"eval\", \"arguments\"],\n};\nconst keywords = new Set(reservedWords.keyword);\nconst reservedWordsStrictSet = new Set(reservedWords.strict);\nconst reservedWordsStrictBindSet = new Set(reservedWords.strictBind);\n\n/**\n * Checks if word is a reserved word in non-strict mode\n */\nexport function isReservedWord(word: string, inModule: boolean): boolean {\n return (inModule && word === \"await\") || word === \"enum\";\n}\n\n/**\n * Checks if word is a reserved word in non-binding strict mode\n *\n * Includes non-strict reserved words\n */\nexport function isStrictReservedWord(word: string, inModule: boolean): boolean {\n return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode, but it is allowed as\n * a normal identifier.\n */\nexport function isStrictBindOnlyReservedWord(word: string): boolean {\n return reservedWordsStrictBindSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode\n *\n * Includes non-strict reserved words and non-binding strict reserved words\n */\nexport function isStrictBindReservedWord(\n word: string,\n inModule: boolean,\n): boolean {\n return (\n isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word)\n );\n}\n\nexport function isKeyword(word: string): boolean {\n return keywords.has(word);\n}\n"],"mappings":";;;;;;;;;;AAAA,MAAMA,aAAa,GAAG;EACpBC,OAAO,EAAE,CACP,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,UAAU,EACV,SAAS,EACT,IAAI,EACJ,MAAM,EACN,SAAS,EACT,KAAK,EACL,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,QAAQ,CACT;EACDC,MAAM,EAAE,CACN,YAAY,EACZ,WAAW,EACX,KAAK,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,OAAO,CACR;EACDC,UAAU,EAAE,CAAC,MAAM,EAAE,WAAW;AAClC,CAAC;AACD,MAAMC,QAAQ,GAAG,IAAIC,GAAG,CAACL,aAAa,CAACC,OAAO,CAAC;AAC/C,MAAMK,sBAAsB,GAAG,IAAID,GAAG,CAACL,aAAa,CAACE,MAAM,CAAC;AAC5D,MAAMK,0BAA0B,GAAG,IAAIF,GAAG,CAACL,aAAa,CAACG,UAAU,CAAC;AAK7D,SAASK,cAAcA,CAACC,IAAY,EAAEC,QAAiB,EAAW;EACvE,OAAQA,QAAQ,IAAID,IAAI,KAAK,OAAO,IAAKA,IAAI,KAAK,MAAM;AAC1D;AAOO,SAASE,oBAAoBA,CAACF,IAAY,EAAEC,QAAiB,EAAW;EAC7E,OAAOF,cAAc,CAACC,IAAI,EAAEC,QAAQ,CAAC,IAAIJ,sBAAsB,CAACM,GAAG,CAACH,IAAI,CAAC;AAC3E;AAMO,SAASI,4BAA4BA,CAACJ,IAAY,EAAW;EAClE,OAAOF,0BAA0B,CAACK,GAAG,CAACH,IAAI,CAAC;AAC7C;AAOO,SAASK,wBAAwBA,CACtCL,IAAY,EACZC,QAAiB,EACR;EACT,OACEC,oBAAoB,CAACF,IAAI,EAAEC,QAAQ,CAAC,IAAIG,4BAA4B,CAACJ,IAAI,CAAC;AAE9E;AAEO,SAASM,SAASA,CAACN,IAAY,EAAW;EAC/C,OAAOL,QAAQ,CAACQ,GAAG,CAACH,IAAI,CAAC;AAC3B","ignoreList":[]}
+31
View File
@@ -0,0 +1,31 @@
{
"name": "@babel/helper-validator-identifier",
"version": "7.29.7",
"description": "Validate identifier/keywords name",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-helper-validator-identifier"
},
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "./lib/index.js",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"devDependencies": {
"@unicode/unicode-17.0.0": "^1.6.10",
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"author": "The Babel Team (https://babel.dev/team)",
"type": "commonjs"
}
+1073
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
Copyright (C) 2012-2014 by various contributors (see AUTHORS)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+19
View File
@@ -0,0 +1,19 @@
# @babel/parser
> A JavaScript parser
See our website [@babel/parser](https://babeljs.io/docs/babel-parser) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20parser%22+is%3Aopen) associated with this package.
## Install
Using npm:
```sh
npm install --save-dev @babel/parser
```
or using yarn:
```sh
yarn add @babel/parser --dev
```
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env node
/* eslint-disable no-var, unicorn/prefer-node-protocol */
var parser = require("..");
var fs = require("fs");
var filename = process.argv[2];
if (!filename) {
console.error("no filename specified");
} else {
var file = fs.readFileSync(filename, "utf8");
var ast = parser.parse(file);
console.log(JSON.stringify(ast, null, " "));
}
+14599
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+50
View File
@@ -0,0 +1,50 @@
{
"name": "@babel/parser",
"version": "7.29.7",
"description": "A JavaScript parser",
"author": "The Babel Team (https://babel.dev/team)",
"homepage": "https://babel.dev/docs/en/next/babel-parser",
"bugs": "https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A+parser+%28babylon%29%22+is%3Aopen",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"keywords": [
"babel",
"javascript",
"parser",
"tc39",
"ecmascript",
"@babel/parser"
],
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-parser"
},
"main": "./lib/index.js",
"types": "./typings/babel-parser.d.ts",
"files": [
"bin",
"lib",
"typings/babel-parser.d.ts",
"index.cjs"
],
"engines": {
"node": ">=6.0.0"
},
"# dependencies": "This package doesn't actually have runtime dependencies. @babel/types is only needed for type definitions.",
"dependencies": {
"@babel/types": "^7.29.7"
},
"devDependencies": {
"@babel/code-frame": "^7.29.7",
"@babel/helper-check-duplicate-nodes": "^7.29.7",
"@babel/helper-fixtures": "^7.29.7",
"@babel/helper-string-parser": "^7.29.7",
"@babel/helper-validator-identifier": "^7.29.7",
"charcodes": "^0.2.0"
},
"bin": "./bin/babel-parser.js",
"type": "commonjs"
}
+262
View File
@@ -0,0 +1,262 @@
// This file is auto-generated! Do not modify it directly.
// Run `yarn gulp bundle-dts` to re-generate it.
/* eslint-disable @typescript-eslint/consistent-type-imports, @typescript-eslint/no-redundant-type-constituents */
import { File, Expression } from '@babel/types';
declare class Position {
line: number;
column: number;
index: number;
constructor(line: number, col: number, index: number);
}
type SyntaxPlugin = "flow" | "typescript" | "jsx" | "pipelineOperator" | "placeholders";
type ParseErrorCode = "BABEL_PARSER_SYNTAX_ERROR" | "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED";
interface ParseErrorSpecification<ErrorDetails> {
code: ParseErrorCode;
reasonCode: string;
syntaxPlugin?: SyntaxPlugin;
missingPlugin?: string | string[];
loc: Position;
details: ErrorDetails;
pos: number;
}
type ParseError$1<ErrorDetails> = SyntaxError & ParseErrorSpecification<ErrorDetails>;
type BABEL_8_BREAKING = false;
type IF_BABEL_7<V> = false extends BABEL_8_BREAKING ? V : never;
type Plugin$1 =
| "asyncDoExpressions"
| IF_BABEL_7<"asyncGenerators">
| IF_BABEL_7<"bigInt">
| IF_BABEL_7<"classPrivateMethods">
| IF_BABEL_7<"classPrivateProperties">
| IF_BABEL_7<"classProperties">
| IF_BABEL_7<"classStaticBlock">
| IF_BABEL_7<"decimal">
| "decorators-legacy"
| "deferredImportEvaluation"
| "decoratorAutoAccessors"
| "destructuringPrivate"
| IF_BABEL_7<"deprecatedImportAssert">
| "doExpressions"
| IF_BABEL_7<"dynamicImport">
| IF_BABEL_7<"explicitResourceManagement">
| "exportDefaultFrom"
| IF_BABEL_7<"exportNamespaceFrom">
| "flow"
| "flowComments"
| "functionBind"
| "functionSent"
| "importMeta"
| "jsx"
| IF_BABEL_7<"jsonStrings">
| IF_BABEL_7<"logicalAssignment">
| IF_BABEL_7<"importAssertions">
| IF_BABEL_7<"importReflection">
| "moduleBlocks"
| IF_BABEL_7<"moduleStringNames">
| IF_BABEL_7<"nullishCoalescingOperator">
| IF_BABEL_7<"numericSeparator">
| IF_BABEL_7<"objectRestSpread">
| IF_BABEL_7<"optionalCatchBinding">
| IF_BABEL_7<"optionalChaining">
| "partialApplication"
| "placeholders"
| IF_BABEL_7<"privateIn">
| IF_BABEL_7<"regexpUnicodeSets">
| "sourcePhaseImports"
| "throwExpressions"
| IF_BABEL_7<"topLevelAwait">
| "v8intrinsic"
| ParserPluginWithOptions[0];
type ParserPluginWithOptions =
| ["decorators", DecoratorsPluginOptions]
| ["discardBinding", { syntaxType: "void" }]
| ["estree", { classFeatures?: boolean }]
| IF_BABEL_7<["importAttributes", { deprecatedAssertSyntax: boolean }]>
| IF_BABEL_7<["moduleAttributes", { version: "may-2020" }]>
| ["optionalChainingAssign", { version: "2023-07" }]
| ["pipelineOperator", PipelineOperatorPluginOptions]
| ["recordAndTuple", RecordAndTuplePluginOptions]
| ["flow", FlowPluginOptions]
| ["typescript", TypeScriptPluginOptions];
type PluginConfig = Plugin$1 | ParserPluginWithOptions;
interface DecoratorsPluginOptions {
decoratorsBeforeExport?: boolean;
allowCallParenthesized?: boolean;
}
interface PipelineOperatorPluginOptions {
proposal: BABEL_8_BREAKING extends false
? "minimal" | "fsharp" | "hack" | "smart"
: "fsharp" | "hack";
topicToken?: "%" | "#" | "@@" | "^^" | "^";
}
interface RecordAndTuplePluginOptions {
syntaxType: "bar" | "hash";
}
type FlowPluginOptions = BABEL_8_BREAKING extends true
? {
all?: boolean;
enums?: boolean;
}
: {
all?: boolean;
};
interface TypeScriptPluginOptions {
dts?: boolean;
disallowAmbiguousJSXLike?: boolean;
}
type Plugin = PluginConfig;
type SourceType = "script" | "commonjs" | "module" | "unambiguous";
interface Options {
/**
* By default, import and export declarations can only appear at a program's top level.
* Setting this option to true allows them anywhere where a statement is allowed.
*/
allowImportExportEverywhere?: boolean;
/**
* By default, await use is not allowed outside of an async function.
* Set this to true to accept such code.
*/
allowAwaitOutsideFunction?: boolean;
/**
* By default, a return statement at the top level raises an error.
* Set this to true to accept such code.
*/
allowReturnOutsideFunction?: boolean;
/**
* By default, new.target use is not allowed outside of a function or class.
* Set this to true to accept such code.
*/
allowNewTargetOutsideFunction?: boolean;
/**
* By default, super calls are not allowed outside of a method.
* Set this to true to accept such code.
*/
allowSuperOutsideMethod?: boolean;
/**
* By default, exported identifiers must refer to a declared variable.
* Set this to true to allow export statements to reference undeclared variables.
*/
allowUndeclaredExports?: boolean;
/**
* By default, yield use is not allowed outside of a generator function.
* Set this to true to accept such code.
*/
allowYieldOutsideFunction?: boolean;
/**
* By default, Babel parser JavaScript code according to Annex B syntax.
* Set this to `false` to disable such behavior.
*/
annexB?: boolean;
/**
* By default, Babel attaches comments to adjacent AST nodes.
* When this option is set to false, comments are not attached.
* It can provide up to 30% performance improvement when the input code has many comments.
* @babel/eslint-parser will set it for you.
* It is not recommended to use attachComment: false with Babel transform,
* as doing so removes all the comments in output code, and renders annotations such as
* /* istanbul ignore next *\/ nonfunctional.
*/
attachComment?: boolean;
/**
* By default, Babel always throws an error when it finds some invalid code.
* When this option is set to true, it will store the parsing error and
* try to continue parsing the invalid input file.
*/
errorRecovery?: boolean;
/**
* Indicate the mode the code should be parsed in.
* Can be one of "script", "commonjs", "module", or "unambiguous". Defaults to "script".
* "unambiguous" will make @babel/parser attempt to guess, based on the presence
* of ES6 import or export statements.
* Files with ES6 imports and exports are considered "module" and are otherwise "script".
*
* Use "commonjs" to parse code that is intended to be run in a CommonJS environment such as Node.js.
*/
sourceType?: SourceType;
/**
* Correlate output AST nodes with their source filename.
* Useful when generating code and source maps from the ASTs of multiple input files.
*/
sourceFilename?: string;
/**
* By default, all source indexes start from 0.
* You can provide a start index to alternatively start with.
* Useful for integration with other source tools.
*/
startIndex?: number;
/**
* By default, the first line of code parsed is treated as line 1.
* You can provide a line number to alternatively start with.
* Useful for integration with other source tools.
*/
startLine?: number;
/**
* By default, the parsed code is treated as if it starts from line 1, column 0.
* You can provide a column number to alternatively start with.
* Useful for integration with other source tools.
*/
startColumn?: number;
/**
* Array containing the plugins that you want to enable.
*/
plugins?: Plugin[];
/**
* Should the parser work in strict mode.
* Defaults to true if sourceType === 'module'. Otherwise, false.
*/
strictMode?: boolean;
/**
* Adds a ranges property to each node: [node.start, node.end]
*/
ranges?: boolean;
/**
* Adds all parsed tokens to a tokens property on the File node.
*/
tokens?: boolean;
/**
* By default, the parser adds information about parentheses by setting
* `extra.parenthesized` to `true` as needed.
* When this option is `true` the parser creates `ParenthesizedExpression`
* AST nodes instead of using the `extra` property.
*/
createParenthesizedExpressions?: boolean;
/**
* The default is false in Babel 7 and true in Babel 8
* Set this to true to parse it as an `ImportExpression` node.
* Otherwise `import(foo)` is parsed as `CallExpression(Import, [Identifier(foo)])`.
*/
createImportExpressions?: boolean;
}
type ParserOptions = Partial<Options>;
type ParseError = ParseError$1<object>;
type ParseResult<Result extends File | Expression = File> = Result & {
comments: File["comments"];
errors: null | ParseError[];
tokens?: File["tokens"];
};
/**
* Parse the provided code as an entire ECMAScript program.
*/
declare function parse(input: string, options?: ParserOptions): ParseResult<File>;
declare function parseExpression(input: string, options?: ParserOptions): ParseResult<Expression>;
declare const tokTypes: {
// todo(flow->ts) real token type
[name: string]: any;
};
export { DecoratorsPluginOptions, FlowPluginOptions, ParseError, ParseResult, ParserOptions, PluginConfig as ParserPlugin, ParserPluginWithOptions, PipelineOperatorPluginOptions, RecordAndTuplePluginOptions, TypeScriptPluginOptions, parse, parseExpression, tokTypes };
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+19
View File
@@ -0,0 +1,19 @@
# @babel/types
> Babel Types is a Lodash-esque utility library for AST nodes
See our website [@babel/types](https://babeljs.io/docs/babel-types) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20types%22+is%3Aopen) associated with this package.
## Install
Using npm:
```sh
npm install --save-dev @babel/types
```
or using yarn:
```sh
yarn add @babel/types --dev
```
+16
View File
@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = assertNode;
var _isNode = require("../validators/isNode.js");
function assertNode(node) {
if (!(0, _isNode.default)(node)) {
var _node$type;
const type = (_node$type = node == null ? void 0 : node.type) != null ? _node$type : JSON.stringify(node);
throw new TypeError(`Not a valid node of type "${type}"`);
}
}
//# sourceMappingURL=assertNode.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["_isNode","require","assertNode","node","isNode","_node$type","type","JSON","stringify","TypeError"],"sources":["../../src/asserts/assertNode.ts"],"sourcesContent":["import isNode from \"../validators/isNode.ts\";\nimport type * as t from \"../index.ts\";\n\nexport default function assertNode(node?: any): asserts node is t.Node {\n if (!isNode(node)) {\n const type = node?.type ?? JSON.stringify(node);\n throw new TypeError(`Not a valid node of type \"${type}\"`);\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAGe,SAASC,UAAUA,CAACC,IAAU,EAA0B;EACrE,IAAI,CAAC,IAAAC,eAAM,EAACD,IAAI,CAAC,EAAE;IAAA,IAAAE,UAAA;IACjB,MAAMC,IAAI,IAAAD,UAAA,GAAGF,IAAI,oBAAJA,IAAI,CAAEG,IAAI,YAAAD,UAAA,GAAIE,IAAI,CAACC,SAAS,CAACL,IAAI,CAAC;IAC/C,MAAM,IAAIM,SAAS,CAAC,6BAA6BH,IAAI,GAAG,CAAC;EAC3D;AACF","ignoreList":[]}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
"use strict";
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createFlowUnionType;
var _index = require("../generated/index.js");
var _removeTypeDuplicates = require("../../modifications/flow/removeTypeDuplicates.js");
function createFlowUnionType(types) {
const flattened = (0, _removeTypeDuplicates.default)(types);
if (flattened.length === 1) {
return flattened[0];
} else {
return (0, _index.unionTypeAnnotation)(flattened);
}
}
//# sourceMappingURL=createFlowUnionType.js.map
@@ -0,0 +1 @@
{"version":3,"names":["_index","require","_removeTypeDuplicates","createFlowUnionType","types","flattened","removeTypeDuplicates","length","unionTypeAnnotation"],"sources":["../../../src/builders/flow/createFlowUnionType.ts"],"sourcesContent":["import { unionTypeAnnotation } from \"../generated/index.ts\";\nimport removeTypeDuplicates from \"../../modifications/flow/removeTypeDuplicates.ts\";\nimport type * as t from \"../../index.ts\";\n\n/**\n * Takes an array of `types` and flattens them, removing duplicates and\n * returns a `UnionTypeAnnotation` node containing them.\n */\nexport default function createFlowUnionType<T extends t.FlowType>(\n types: [T] | T[],\n): T | t.UnionTypeAnnotation {\n const flattened = removeTypeDuplicates(types);\n\n if (flattened.length === 1) {\n return flattened[0] as T;\n } else {\n return unionTypeAnnotation(flattened);\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AAOe,SAASE,mBAAmBA,CACzCC,KAAgB,EACW;EAC3B,MAAMC,SAAS,GAAG,IAAAC,6BAAoB,EAACF,KAAK,CAAC;EAE7C,IAAIC,SAAS,CAACE,MAAM,KAAK,CAAC,EAAE;IAC1B,OAAOF,SAAS,CAAC,CAAC,CAAC;EACrB,CAAC,MAAM;IACL,OAAO,IAAAG,0BAAmB,EAACH,SAAS,CAAC;EACvC;AACF","ignoreList":[]}
@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = require("../generated/index.js");
var _default = exports.default = createTypeAnnotationBasedOnTypeof;
function createTypeAnnotationBasedOnTypeof(type) {
switch (type) {
case "string":
return (0, _index.stringTypeAnnotation)();
case "number":
return (0, _index.numberTypeAnnotation)();
case "undefined":
return (0, _index.voidTypeAnnotation)();
case "boolean":
return (0, _index.booleanTypeAnnotation)();
case "function":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Function"));
case "object":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Object"));
case "symbol":
return (0, _index.genericTypeAnnotation)((0, _index.identifier)("Symbol"));
case "bigint":
return (0, _index.anyTypeAnnotation)();
}
throw new Error("Invalid typeof value: " + type);
}
//# sourceMappingURL=createTypeAnnotationBasedOnTypeof.js.map
@@ -0,0 +1 @@
{"version":3,"names":["_index","require","_default","exports","default","createTypeAnnotationBasedOnTypeof","type","stringTypeAnnotation","numberTypeAnnotation","voidTypeAnnotation","booleanTypeAnnotation","genericTypeAnnotation","identifier","anyTypeAnnotation","Error"],"sources":["../../../src/builders/flow/createTypeAnnotationBasedOnTypeof.ts"],"sourcesContent":["import {\n anyTypeAnnotation,\n stringTypeAnnotation,\n numberTypeAnnotation,\n voidTypeAnnotation,\n booleanTypeAnnotation,\n genericTypeAnnotation,\n identifier,\n} from \"../generated/index.ts\";\nimport type * as t from \"../../index.ts\";\n\nexport default createTypeAnnotationBasedOnTypeof as {\n (type: \"string\"): t.StringTypeAnnotation;\n (type: \"number\"): t.NumberTypeAnnotation;\n (type: \"undefined\"): t.VoidTypeAnnotation;\n (type: \"boolean\"): t.BooleanTypeAnnotation;\n (type: \"function\"): t.GenericTypeAnnotation;\n (type: \"object\"): t.GenericTypeAnnotation;\n (type: \"symbol\"): t.GenericTypeAnnotation;\n (type: \"bigint\"): t.AnyTypeAnnotation;\n};\n\n/**\n * Create a type annotation based on typeof expression.\n */\nfunction createTypeAnnotationBasedOnTypeof(type: string): t.FlowType {\n switch (type) {\n case \"string\":\n return stringTypeAnnotation();\n case \"number\":\n return numberTypeAnnotation();\n case \"undefined\":\n return voidTypeAnnotation();\n case \"boolean\":\n return booleanTypeAnnotation();\n case \"function\":\n return genericTypeAnnotation(identifier(\"Function\"));\n case \"object\":\n return genericTypeAnnotation(identifier(\"Object\"));\n case \"symbol\":\n return genericTypeAnnotation(identifier(\"Symbol\"));\n case \"bigint\":\n // todo: use BigInt annotation when Flow supports BigInt\n // https://github.com/facebook/flow/issues/6639\n return anyTypeAnnotation();\n }\n throw new Error(\"Invalid typeof value: \" + type);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAQ+B,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAGhBC,iCAAiC;AAchD,SAASA,iCAAiCA,CAACC,IAAY,EAAc;EACnE,QAAQA,IAAI;IACV,KAAK,QAAQ;MACX,OAAO,IAAAC,2BAAoB,EAAC,CAAC;IAC/B,KAAK,QAAQ;MACX,OAAO,IAAAC,2BAAoB,EAAC,CAAC;IAC/B,KAAK,WAAW;MACd,OAAO,IAAAC,yBAAkB,EAAC,CAAC;IAC7B,KAAK,SAAS;MACZ,OAAO,IAAAC,4BAAqB,EAAC,CAAC;IAChC,KAAK,UAAU;MACb,OAAO,IAAAC,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,UAAU,CAAC,CAAC;IACtD,KAAK,QAAQ;MACX,OAAO,IAAAD,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,QAAQ,CAAC,CAAC;IACpD,KAAK,QAAQ;MACX,OAAO,IAAAD,4BAAqB,EAAC,IAAAC,iBAAU,EAAC,QAAQ,CAAC,CAAC;IACpD,KAAK,QAAQ;MAGX,OAAO,IAAAC,wBAAiB,EAAC,CAAC;EAC9B;EACA,MAAM,IAAIC,KAAK,CAAC,wBAAwB,GAAGR,IAAI,CAAC;AAClD","ignoreList":[]}
+29
View File
@@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _lowercase = require("./lowercase.js");
Object.keys(_lowercase).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _lowercase[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _lowercase[key];
}
});
});
var _uppercase = require("./uppercase.js");
Object.keys(_uppercase).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _uppercase[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _uppercase[key];
}
});
});
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+272
View File
@@ -0,0 +1,272 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.JSXIdentifier = exports.JSXFragment = exports.JSXExpressionContainer = exports.JSXEmptyExpression = exports.JSXElement = exports.JSXClosingFragment = exports.JSXClosingElement = exports.JSXAttribute = exports.IntersectionTypeAnnotation = exports.InterpreterDirective = exports.InterfaceTypeAnnotation = exports.InterfaceExtends = exports.InterfaceDeclaration = exports.InferredPredicate = exports.IndexedAccessType = exports.ImportSpecifier = exports.ImportNamespaceSpecifier = exports.ImportExpression = exports.ImportDefaultSpecifier = exports.ImportDeclaration = exports.ImportAttribute = exports.Import = exports.IfStatement = exports.Identifier = exports.GenericTypeAnnotation = exports.FunctionTypeParam = exports.FunctionTypeAnnotation = exports.FunctionExpression = exports.FunctionDeclaration = exports.ForStatement = exports.ForOfStatement = exports.ForInStatement = exports.File = exports.ExpressionStatement = exports.ExportSpecifier = exports.ExportNamespaceSpecifier = exports.ExportNamedDeclaration = exports.ExportDefaultSpecifier = exports.ExportDefaultDeclaration = exports.ExportAllDeclaration = exports.ExistsTypeAnnotation = exports.EnumSymbolBody = exports.EnumStringMember = exports.EnumStringBody = exports.EnumNumberMember = exports.EnumNumberBody = exports.EnumDefaultedMember = exports.EnumDeclaration = exports.EnumBooleanMember = exports.EnumBooleanBody = exports.EmptyTypeAnnotation = exports.EmptyStatement = exports.DoWhileStatement = exports.DoExpression = exports.DirectiveLiteral = exports.Directive = exports.Decorator = exports.DeclaredPredicate = exports.DeclareVariable = exports.DeclareTypeAlias = exports.DeclareOpaqueType = exports.DeclareModuleExports = exports.DeclareModule = exports.DeclareInterface = exports.DeclareFunction = exports.DeclareExportDeclaration = exports.DeclareExportAllDeclaration = exports.DeclareClass = exports.DecimalLiteral = exports.DebuggerStatement = exports.ContinueStatement = exports.ConditionalExpression = exports.ClassProperty = exports.ClassPrivateProperty = exports.ClassPrivateMethod = exports.ClassMethod = exports.ClassImplements = exports.ClassExpression = exports.ClassDeclaration = exports.ClassBody = exports.ClassAccessorProperty = exports.CatchClause = exports.CallExpression = exports.BreakStatement = exports.BooleanTypeAnnotation = exports.BooleanLiteralTypeAnnotation = exports.BooleanLiteral = exports.BlockStatement = exports.BindExpression = exports.BinaryExpression = exports.BigIntLiteral = exports.AwaitExpression = exports.AssignmentPattern = exports.AssignmentExpression = exports.ArrowFunctionExpression = exports.ArrayTypeAnnotation = exports.ArrayPattern = exports.ArrayExpression = exports.ArgumentPlaceholder = exports.AnyTypeAnnotation = void 0;
exports.TSNumberKeyword = exports.TSNullKeyword = exports.TSNonNullExpression = exports.TSNeverKeyword = exports.TSNamespaceExportDeclaration = exports.TSNamedTupleMember = exports.TSModuleDeclaration = exports.TSModuleBlock = exports.TSMethodSignature = exports.TSMappedType = exports.TSLiteralType = exports.TSIntrinsicKeyword = exports.TSIntersectionType = exports.TSInterfaceDeclaration = exports.TSInterfaceBody = exports.TSInstantiationExpression = exports.TSInferType = exports.TSIndexedAccessType = exports.TSIndexSignature = exports.TSImportType = exports.TSImportEqualsDeclaration = exports.TSFunctionType = exports.TSExternalModuleReference = exports.TSExpressionWithTypeArguments = exports.TSExportAssignment = exports.TSEnumMember = exports.TSEnumDeclaration = exports.TSEnumBody = exports.TSDeclareMethod = exports.TSDeclareFunction = exports.TSConstructorType = exports.TSConstructSignatureDeclaration = exports.TSConditionalType = exports.TSCallSignatureDeclaration = exports.TSBooleanKeyword = exports.TSBigIntKeyword = exports.TSAsExpression = exports.TSArrayType = exports.TSAnyKeyword = exports.SymbolTypeAnnotation = exports.SwitchStatement = exports.SwitchCase = exports.Super = exports.StringTypeAnnotation = exports.StringLiteralTypeAnnotation = exports.StringLiteral = exports.StaticBlock = exports.SpreadProperty = exports.SpreadElement = exports.SequenceExpression = exports.ReturnStatement = exports.RestProperty = exports.RestElement = exports.RegexLiteral = exports.RegExpLiteral = exports.RecordExpression = exports.QualifiedTypeIdentifier = exports.Program = exports.PrivateName = exports.Placeholder = exports.PipelineTopicExpression = exports.PipelinePrimaryTopicReference = exports.PipelineBareFunction = exports.ParenthesizedExpression = exports.OptionalMemberExpression = exports.OptionalIndexedAccessType = exports.OptionalCallExpression = exports.OpaqueType = exports.ObjectTypeSpreadProperty = exports.ObjectTypeProperty = exports.ObjectTypeInternalSlot = exports.ObjectTypeIndexer = exports.ObjectTypeCallProperty = exports.ObjectTypeAnnotation = exports.ObjectProperty = exports.ObjectPattern = exports.ObjectMethod = exports.ObjectExpression = exports.NumericLiteral = exports.NumberTypeAnnotation = exports.NumberLiteralTypeAnnotation = exports.NumberLiteral = exports.NullableTypeAnnotation = exports.NullLiteralTypeAnnotation = exports.NullLiteral = exports.Noop = exports.NewExpression = exports.ModuleExpression = exports.MixedTypeAnnotation = exports.MetaProperty = exports.MemberExpression = exports.LogicalExpression = exports.LabeledStatement = exports.JSXText = exports.JSXSpreadChild = exports.JSXSpreadAttribute = exports.JSXOpeningFragment = exports.JSXOpeningElement = exports.JSXNamespacedName = exports.JSXMemberExpression = void 0;
exports.YieldExpression = exports.WithStatement = exports.WhileStatement = exports.VoidTypeAnnotation = exports.VoidPattern = exports.Variance = exports.VariableDeclarator = exports.VariableDeclaration = exports.V8IntrinsicIdentifier = exports.UpdateExpression = exports.UnionTypeAnnotation = exports.UnaryExpression = exports.TypeofTypeAnnotation = exports.TypeParameterInstantiation = exports.TypeParameterDeclaration = exports.TypeParameter = exports.TypeCastExpression = exports.TypeAnnotation = exports.TypeAlias = exports.TupleTypeAnnotation = exports.TupleExpression = exports.TryStatement = exports.TopicReference = exports.ThrowStatement = exports.ThisTypeAnnotation = exports.ThisExpression = exports.TemplateLiteral = exports.TemplateElement = exports.TaggedTemplateExpression = exports.TSVoidKeyword = exports.TSUnknownKeyword = exports.TSUnionType = exports.TSUndefinedKeyword = exports.TSTypeReference = exports.TSTypeQuery = exports.TSTypePredicate = exports.TSTypeParameterInstantiation = exports.TSTypeParameterDeclaration = exports.TSTypeParameter = exports.TSTypeOperator = exports.TSTypeLiteral = exports.TSTypeAssertion = exports.TSTypeAnnotation = exports.TSTypeAliasDeclaration = exports.TSTupleType = exports.TSThisType = exports.TSTemplateLiteralType = exports.TSSymbolKeyword = exports.TSStringKeyword = exports.TSSatisfiesExpression = exports.TSRestType = exports.TSQualifiedName = exports.TSPropertySignature = exports.TSParenthesizedType = exports.TSParameterProperty = exports.TSOptionalType = exports.TSObjectKeyword = void 0;
var b = require("./lowercase.js");
var _deprecationWarning = require("../../utils/deprecationWarning.js");
function alias(lowercase) {
return b[lowercase];
}
const ArrayExpression = exports.ArrayExpression = alias("arrayExpression"),
AssignmentExpression = exports.AssignmentExpression = alias("assignmentExpression"),
BinaryExpression = exports.BinaryExpression = alias("binaryExpression"),
InterpreterDirective = exports.InterpreterDirective = alias("interpreterDirective"),
Directive = exports.Directive = alias("directive"),
DirectiveLiteral = exports.DirectiveLiteral = alias("directiveLiteral"),
BlockStatement = exports.BlockStatement = alias("blockStatement"),
BreakStatement = exports.BreakStatement = alias("breakStatement"),
CallExpression = exports.CallExpression = alias("callExpression"),
CatchClause = exports.CatchClause = alias("catchClause"),
ConditionalExpression = exports.ConditionalExpression = alias("conditionalExpression"),
ContinueStatement = exports.ContinueStatement = alias("continueStatement"),
DebuggerStatement = exports.DebuggerStatement = alias("debuggerStatement"),
DoWhileStatement = exports.DoWhileStatement = alias("doWhileStatement"),
EmptyStatement = exports.EmptyStatement = alias("emptyStatement"),
ExpressionStatement = exports.ExpressionStatement = alias("expressionStatement"),
File = exports.File = alias("file"),
ForInStatement = exports.ForInStatement = alias("forInStatement"),
ForStatement = exports.ForStatement = alias("forStatement"),
FunctionDeclaration = exports.FunctionDeclaration = alias("functionDeclaration"),
FunctionExpression = exports.FunctionExpression = alias("functionExpression"),
Identifier = exports.Identifier = alias("identifier"),
IfStatement = exports.IfStatement = alias("ifStatement"),
LabeledStatement = exports.LabeledStatement = alias("labeledStatement"),
StringLiteral = exports.StringLiteral = alias("stringLiteral"),
NumericLiteral = exports.NumericLiteral = alias("numericLiteral"),
NullLiteral = exports.NullLiteral = alias("nullLiteral"),
BooleanLiteral = exports.BooleanLiteral = alias("booleanLiteral"),
RegExpLiteral = exports.RegExpLiteral = alias("regExpLiteral"),
LogicalExpression = exports.LogicalExpression = alias("logicalExpression"),
MemberExpression = exports.MemberExpression = alias("memberExpression"),
NewExpression = exports.NewExpression = alias("newExpression"),
Program = exports.Program = alias("program"),
ObjectExpression = exports.ObjectExpression = alias("objectExpression"),
ObjectMethod = exports.ObjectMethod = alias("objectMethod"),
ObjectProperty = exports.ObjectProperty = alias("objectProperty"),
RestElement = exports.RestElement = alias("restElement"),
ReturnStatement = exports.ReturnStatement = alias("returnStatement"),
SequenceExpression = exports.SequenceExpression = alias("sequenceExpression"),
ParenthesizedExpression = exports.ParenthesizedExpression = alias("parenthesizedExpression"),
SwitchCase = exports.SwitchCase = alias("switchCase"),
SwitchStatement = exports.SwitchStatement = alias("switchStatement"),
ThisExpression = exports.ThisExpression = alias("thisExpression"),
ThrowStatement = exports.ThrowStatement = alias("throwStatement"),
TryStatement = exports.TryStatement = alias("tryStatement"),
UnaryExpression = exports.UnaryExpression = alias("unaryExpression"),
UpdateExpression = exports.UpdateExpression = alias("updateExpression"),
VariableDeclaration = exports.VariableDeclaration = alias("variableDeclaration"),
VariableDeclarator = exports.VariableDeclarator = alias("variableDeclarator"),
WhileStatement = exports.WhileStatement = alias("whileStatement"),
WithStatement = exports.WithStatement = alias("withStatement"),
AssignmentPattern = exports.AssignmentPattern = alias("assignmentPattern"),
ArrayPattern = exports.ArrayPattern = alias("arrayPattern"),
ArrowFunctionExpression = exports.ArrowFunctionExpression = alias("arrowFunctionExpression"),
ClassBody = exports.ClassBody = alias("classBody"),
ClassExpression = exports.ClassExpression = alias("classExpression"),
ClassDeclaration = exports.ClassDeclaration = alias("classDeclaration"),
ExportAllDeclaration = exports.ExportAllDeclaration = alias("exportAllDeclaration"),
ExportDefaultDeclaration = exports.ExportDefaultDeclaration = alias("exportDefaultDeclaration"),
ExportNamedDeclaration = exports.ExportNamedDeclaration = alias("exportNamedDeclaration"),
ExportSpecifier = exports.ExportSpecifier = alias("exportSpecifier"),
ForOfStatement = exports.ForOfStatement = alias("forOfStatement"),
ImportDeclaration = exports.ImportDeclaration = alias("importDeclaration"),
ImportDefaultSpecifier = exports.ImportDefaultSpecifier = alias("importDefaultSpecifier"),
ImportNamespaceSpecifier = exports.ImportNamespaceSpecifier = alias("importNamespaceSpecifier"),
ImportSpecifier = exports.ImportSpecifier = alias("importSpecifier"),
ImportExpression = exports.ImportExpression = alias("importExpression"),
MetaProperty = exports.MetaProperty = alias("metaProperty"),
ClassMethod = exports.ClassMethod = alias("classMethod"),
ObjectPattern = exports.ObjectPattern = alias("objectPattern"),
SpreadElement = exports.SpreadElement = alias("spreadElement"),
Super = exports.Super = alias("super"),
TaggedTemplateExpression = exports.TaggedTemplateExpression = alias("taggedTemplateExpression"),
TemplateElement = exports.TemplateElement = alias("templateElement"),
TemplateLiteral = exports.TemplateLiteral = alias("templateLiteral"),
YieldExpression = exports.YieldExpression = alias("yieldExpression"),
AwaitExpression = exports.AwaitExpression = alias("awaitExpression"),
Import = exports.Import = alias("import"),
BigIntLiteral = exports.BigIntLiteral = alias("bigIntLiteral"),
ExportNamespaceSpecifier = exports.ExportNamespaceSpecifier = alias("exportNamespaceSpecifier"),
OptionalMemberExpression = exports.OptionalMemberExpression = alias("optionalMemberExpression"),
OptionalCallExpression = exports.OptionalCallExpression = alias("optionalCallExpression"),
ClassProperty = exports.ClassProperty = alias("classProperty"),
ClassAccessorProperty = exports.ClassAccessorProperty = alias("classAccessorProperty"),
ClassPrivateProperty = exports.ClassPrivateProperty = alias("classPrivateProperty"),
ClassPrivateMethod = exports.ClassPrivateMethod = alias("classPrivateMethod"),
PrivateName = exports.PrivateName = alias("privateName"),
StaticBlock = exports.StaticBlock = alias("staticBlock"),
ImportAttribute = exports.ImportAttribute = alias("importAttribute"),
AnyTypeAnnotation = exports.AnyTypeAnnotation = alias("anyTypeAnnotation"),
ArrayTypeAnnotation = exports.ArrayTypeAnnotation = alias("arrayTypeAnnotation"),
BooleanTypeAnnotation = exports.BooleanTypeAnnotation = alias("booleanTypeAnnotation"),
BooleanLiteralTypeAnnotation = exports.BooleanLiteralTypeAnnotation = alias("booleanLiteralTypeAnnotation"),
NullLiteralTypeAnnotation = exports.NullLiteralTypeAnnotation = alias("nullLiteralTypeAnnotation"),
ClassImplements = exports.ClassImplements = alias("classImplements"),
DeclareClass = exports.DeclareClass = alias("declareClass"),
DeclareFunction = exports.DeclareFunction = alias("declareFunction"),
DeclareInterface = exports.DeclareInterface = alias("declareInterface"),
DeclareModule = exports.DeclareModule = alias("declareModule"),
DeclareModuleExports = exports.DeclareModuleExports = alias("declareModuleExports"),
DeclareTypeAlias = exports.DeclareTypeAlias = alias("declareTypeAlias"),
DeclareOpaqueType = exports.DeclareOpaqueType = alias("declareOpaqueType"),
DeclareVariable = exports.DeclareVariable = alias("declareVariable"),
DeclareExportDeclaration = exports.DeclareExportDeclaration = alias("declareExportDeclaration"),
DeclareExportAllDeclaration = exports.DeclareExportAllDeclaration = alias("declareExportAllDeclaration"),
DeclaredPredicate = exports.DeclaredPredicate = alias("declaredPredicate"),
ExistsTypeAnnotation = exports.ExistsTypeAnnotation = alias("existsTypeAnnotation"),
FunctionTypeAnnotation = exports.FunctionTypeAnnotation = alias("functionTypeAnnotation"),
FunctionTypeParam = exports.FunctionTypeParam = alias("functionTypeParam"),
GenericTypeAnnotation = exports.GenericTypeAnnotation = alias("genericTypeAnnotation"),
InferredPredicate = exports.InferredPredicate = alias("inferredPredicate"),
InterfaceExtends = exports.InterfaceExtends = alias("interfaceExtends"),
InterfaceDeclaration = exports.InterfaceDeclaration = alias("interfaceDeclaration"),
InterfaceTypeAnnotation = exports.InterfaceTypeAnnotation = alias("interfaceTypeAnnotation"),
IntersectionTypeAnnotation = exports.IntersectionTypeAnnotation = alias("intersectionTypeAnnotation"),
MixedTypeAnnotation = exports.MixedTypeAnnotation = alias("mixedTypeAnnotation"),
EmptyTypeAnnotation = exports.EmptyTypeAnnotation = alias("emptyTypeAnnotation"),
NullableTypeAnnotation = exports.NullableTypeAnnotation = alias("nullableTypeAnnotation"),
NumberLiteralTypeAnnotation = exports.NumberLiteralTypeAnnotation = alias("numberLiteralTypeAnnotation"),
NumberTypeAnnotation = exports.NumberTypeAnnotation = alias("numberTypeAnnotation"),
ObjectTypeAnnotation = exports.ObjectTypeAnnotation = alias("objectTypeAnnotation"),
ObjectTypeInternalSlot = exports.ObjectTypeInternalSlot = alias("objectTypeInternalSlot"),
ObjectTypeCallProperty = exports.ObjectTypeCallProperty = alias("objectTypeCallProperty"),
ObjectTypeIndexer = exports.ObjectTypeIndexer = alias("objectTypeIndexer"),
ObjectTypeProperty = exports.ObjectTypeProperty = alias("objectTypeProperty"),
ObjectTypeSpreadProperty = exports.ObjectTypeSpreadProperty = alias("objectTypeSpreadProperty"),
OpaqueType = exports.OpaqueType = alias("opaqueType"),
QualifiedTypeIdentifier = exports.QualifiedTypeIdentifier = alias("qualifiedTypeIdentifier"),
StringLiteralTypeAnnotation = exports.StringLiteralTypeAnnotation = alias("stringLiteralTypeAnnotation"),
StringTypeAnnotation = exports.StringTypeAnnotation = alias("stringTypeAnnotation"),
SymbolTypeAnnotation = exports.SymbolTypeAnnotation = alias("symbolTypeAnnotation"),
ThisTypeAnnotation = exports.ThisTypeAnnotation = alias("thisTypeAnnotation"),
TupleTypeAnnotation = exports.TupleTypeAnnotation = alias("tupleTypeAnnotation"),
TypeofTypeAnnotation = exports.TypeofTypeAnnotation = alias("typeofTypeAnnotation"),
TypeAlias = exports.TypeAlias = alias("typeAlias"),
TypeAnnotation = exports.TypeAnnotation = alias("typeAnnotation"),
TypeCastExpression = exports.TypeCastExpression = alias("typeCastExpression"),
TypeParameter = exports.TypeParameter = alias("typeParameter"),
TypeParameterDeclaration = exports.TypeParameterDeclaration = alias("typeParameterDeclaration"),
TypeParameterInstantiation = exports.TypeParameterInstantiation = alias("typeParameterInstantiation"),
UnionTypeAnnotation = exports.UnionTypeAnnotation = alias("unionTypeAnnotation"),
Variance = exports.Variance = alias("variance"),
VoidTypeAnnotation = exports.VoidTypeAnnotation = alias("voidTypeAnnotation"),
EnumDeclaration = exports.EnumDeclaration = alias("enumDeclaration"),
EnumBooleanBody = exports.EnumBooleanBody = alias("enumBooleanBody"),
EnumNumberBody = exports.EnumNumberBody = alias("enumNumberBody"),
EnumStringBody = exports.EnumStringBody = alias("enumStringBody"),
EnumSymbolBody = exports.EnumSymbolBody = alias("enumSymbolBody"),
EnumBooleanMember = exports.EnumBooleanMember = alias("enumBooleanMember"),
EnumNumberMember = exports.EnumNumberMember = alias("enumNumberMember"),
EnumStringMember = exports.EnumStringMember = alias("enumStringMember"),
EnumDefaultedMember = exports.EnumDefaultedMember = alias("enumDefaultedMember"),
IndexedAccessType = exports.IndexedAccessType = alias("indexedAccessType"),
OptionalIndexedAccessType = exports.OptionalIndexedAccessType = alias("optionalIndexedAccessType"),
JSXAttribute = exports.JSXAttribute = alias("jsxAttribute"),
JSXClosingElement = exports.JSXClosingElement = alias("jsxClosingElement"),
JSXElement = exports.JSXElement = alias("jsxElement"),
JSXEmptyExpression = exports.JSXEmptyExpression = alias("jsxEmptyExpression"),
JSXExpressionContainer = exports.JSXExpressionContainer = alias("jsxExpressionContainer"),
JSXSpreadChild = exports.JSXSpreadChild = alias("jsxSpreadChild"),
JSXIdentifier = exports.JSXIdentifier = alias("jsxIdentifier"),
JSXMemberExpression = exports.JSXMemberExpression = alias("jsxMemberExpression"),
JSXNamespacedName = exports.JSXNamespacedName = alias("jsxNamespacedName"),
JSXOpeningElement = exports.JSXOpeningElement = alias("jsxOpeningElement"),
JSXSpreadAttribute = exports.JSXSpreadAttribute = alias("jsxSpreadAttribute"),
JSXText = exports.JSXText = alias("jsxText"),
JSXFragment = exports.JSXFragment = alias("jsxFragment"),
JSXOpeningFragment = exports.JSXOpeningFragment = alias("jsxOpeningFragment"),
JSXClosingFragment = exports.JSXClosingFragment = alias("jsxClosingFragment"),
Noop = exports.Noop = alias("noop"),
Placeholder = exports.Placeholder = alias("placeholder"),
V8IntrinsicIdentifier = exports.V8IntrinsicIdentifier = alias("v8IntrinsicIdentifier"),
ArgumentPlaceholder = exports.ArgumentPlaceholder = alias("argumentPlaceholder"),
BindExpression = exports.BindExpression = alias("bindExpression"),
Decorator = exports.Decorator = alias("decorator"),
DoExpression = exports.DoExpression = alias("doExpression"),
ExportDefaultSpecifier = exports.ExportDefaultSpecifier = alias("exportDefaultSpecifier"),
RecordExpression = exports.RecordExpression = alias("recordExpression"),
TupleExpression = exports.TupleExpression = alias("tupleExpression"),
DecimalLiteral = exports.DecimalLiteral = alias("decimalLiteral"),
ModuleExpression = exports.ModuleExpression = alias("moduleExpression"),
TopicReference = exports.TopicReference = alias("topicReference"),
PipelineTopicExpression = exports.PipelineTopicExpression = alias("pipelineTopicExpression"),
PipelineBareFunction = exports.PipelineBareFunction = alias("pipelineBareFunction"),
PipelinePrimaryTopicReference = exports.PipelinePrimaryTopicReference = alias("pipelinePrimaryTopicReference"),
VoidPattern = exports.VoidPattern = alias("voidPattern"),
TSParameterProperty = exports.TSParameterProperty = alias("tsParameterProperty"),
TSDeclareFunction = exports.TSDeclareFunction = alias("tsDeclareFunction"),
TSDeclareMethod = exports.TSDeclareMethod = alias("tsDeclareMethod"),
TSQualifiedName = exports.TSQualifiedName = alias("tsQualifiedName"),
TSCallSignatureDeclaration = exports.TSCallSignatureDeclaration = alias("tsCallSignatureDeclaration"),
TSConstructSignatureDeclaration = exports.TSConstructSignatureDeclaration = alias("tsConstructSignatureDeclaration"),
TSPropertySignature = exports.TSPropertySignature = alias("tsPropertySignature"),
TSMethodSignature = exports.TSMethodSignature = alias("tsMethodSignature"),
TSIndexSignature = exports.TSIndexSignature = alias("tsIndexSignature"),
TSAnyKeyword = exports.TSAnyKeyword = alias("tsAnyKeyword"),
TSBooleanKeyword = exports.TSBooleanKeyword = alias("tsBooleanKeyword"),
TSBigIntKeyword = exports.TSBigIntKeyword = alias("tsBigIntKeyword"),
TSIntrinsicKeyword = exports.TSIntrinsicKeyword = alias("tsIntrinsicKeyword"),
TSNeverKeyword = exports.TSNeverKeyword = alias("tsNeverKeyword"),
TSNullKeyword = exports.TSNullKeyword = alias("tsNullKeyword"),
TSNumberKeyword = exports.TSNumberKeyword = alias("tsNumberKeyword"),
TSObjectKeyword = exports.TSObjectKeyword = alias("tsObjectKeyword"),
TSStringKeyword = exports.TSStringKeyword = alias("tsStringKeyword"),
TSSymbolKeyword = exports.TSSymbolKeyword = alias("tsSymbolKeyword"),
TSUndefinedKeyword = exports.TSUndefinedKeyword = alias("tsUndefinedKeyword"),
TSUnknownKeyword = exports.TSUnknownKeyword = alias("tsUnknownKeyword"),
TSVoidKeyword = exports.TSVoidKeyword = alias("tsVoidKeyword"),
TSThisType = exports.TSThisType = alias("tsThisType"),
TSFunctionType = exports.TSFunctionType = alias("tsFunctionType"),
TSConstructorType = exports.TSConstructorType = alias("tsConstructorType"),
TSTypeReference = exports.TSTypeReference = alias("tsTypeReference"),
TSTypePredicate = exports.TSTypePredicate = alias("tsTypePredicate"),
TSTypeQuery = exports.TSTypeQuery = alias("tsTypeQuery"),
TSTypeLiteral = exports.TSTypeLiteral = alias("tsTypeLiteral"),
TSArrayType = exports.TSArrayType = alias("tsArrayType"),
TSTupleType = exports.TSTupleType = alias("tsTupleType"),
TSOptionalType = exports.TSOptionalType = alias("tsOptionalType"),
TSRestType = exports.TSRestType = alias("tsRestType"),
TSNamedTupleMember = exports.TSNamedTupleMember = alias("tsNamedTupleMember"),
TSUnionType = exports.TSUnionType = alias("tsUnionType"),
TSIntersectionType = exports.TSIntersectionType = alias("tsIntersectionType"),
TSConditionalType = exports.TSConditionalType = alias("tsConditionalType"),
TSInferType = exports.TSInferType = alias("tsInferType"),
TSParenthesizedType = exports.TSParenthesizedType = alias("tsParenthesizedType"),
TSTypeOperator = exports.TSTypeOperator = alias("tsTypeOperator"),
TSIndexedAccessType = exports.TSIndexedAccessType = alias("tsIndexedAccessType"),
TSMappedType = exports.TSMappedType = alias("tsMappedType"),
TSTemplateLiteralType = exports.TSTemplateLiteralType = alias("tsTemplateLiteralType"),
TSLiteralType = exports.TSLiteralType = alias("tsLiteralType"),
TSExpressionWithTypeArguments = exports.TSExpressionWithTypeArguments = alias("tsExpressionWithTypeArguments"),
TSInterfaceDeclaration = exports.TSInterfaceDeclaration = alias("tsInterfaceDeclaration"),
TSInterfaceBody = exports.TSInterfaceBody = alias("tsInterfaceBody"),
TSTypeAliasDeclaration = exports.TSTypeAliasDeclaration = alias("tsTypeAliasDeclaration"),
TSInstantiationExpression = exports.TSInstantiationExpression = alias("tsInstantiationExpression"),
TSAsExpression = exports.TSAsExpression = alias("tsAsExpression"),
TSSatisfiesExpression = exports.TSSatisfiesExpression = alias("tsSatisfiesExpression"),
TSTypeAssertion = exports.TSTypeAssertion = alias("tsTypeAssertion"),
TSEnumBody = exports.TSEnumBody = alias("tsEnumBody"),
TSEnumDeclaration = exports.TSEnumDeclaration = alias("tsEnumDeclaration"),
TSEnumMember = exports.TSEnumMember = alias("tsEnumMember"),
TSModuleDeclaration = exports.TSModuleDeclaration = alias("tsModuleDeclaration"),
TSModuleBlock = exports.TSModuleBlock = alias("tsModuleBlock"),
TSImportType = exports.TSImportType = alias("tsImportType"),
TSImportEqualsDeclaration = exports.TSImportEqualsDeclaration = alias("tsImportEqualsDeclaration"),
TSExternalModuleReference = exports.TSExternalModuleReference = alias("tsExternalModuleReference"),
TSNonNullExpression = exports.TSNonNullExpression = alias("tsNonNullExpression"),
TSExportAssignment = exports.TSExportAssignment = alias("tsExportAssignment"),
TSNamespaceExportDeclaration = exports.TSNamespaceExportDeclaration = alias("tsNamespaceExportDeclaration"),
TSTypeAnnotation = exports.TSTypeAnnotation = alias("tsTypeAnnotation"),
TSTypeParameterInstantiation = exports.TSTypeParameterInstantiation = alias("tsTypeParameterInstantiation"),
TSTypeParameterDeclaration = exports.TSTypeParameterDeclaration = alias("tsTypeParameterDeclaration"),
TSTypeParameter = exports.TSTypeParameter = alias("tsTypeParameter");
const NumberLiteral = exports.NumberLiteral = b.numberLiteral,
RegexLiteral = exports.RegexLiteral = b.regexLiteral,
RestProperty = exports.RestProperty = b.restProperty,
SpreadProperty = exports.SpreadProperty = b.spreadProperty;
//# sourceMappingURL=uppercase.js.map
File diff suppressed because one or more lines are too long
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildUndefinedNode = buildUndefinedNode;
var _index = require("./generated/index.js");
function buildUndefinedNode() {
return (0, _index.unaryExpression)("void", (0, _index.numericLiteral)(0), true);
}
//# sourceMappingURL=productions.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["_index","require","buildUndefinedNode","unaryExpression","numericLiteral"],"sources":["../../src/builders/productions.ts"],"sourcesContent":["import { numericLiteral, unaryExpression } from \"./generated/index.ts\";\n\nexport function buildUndefinedNode() {\n return unaryExpression(\"void\", numericLiteral(0), true);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAEO,SAASC,kBAAkBA,CAAA,EAAG;EACnC,OAAO,IAAAC,sBAAe,EAAC,MAAM,EAAE,IAAAC,qBAAc,EAAC,CAAC,CAAC,EAAE,IAAI,CAAC;AACzD","ignoreList":[]}
+24
View File
@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = buildChildren;
var _index = require("../../validators/generated/index.js");
var _cleanJSXElementLiteralChild = require("../../utils/react/cleanJSXElementLiteralChild.js");
function buildChildren(node) {
const elements = [];
for (let i = 0; i < node.children.length; i++) {
let child = node.children[i];
if ((0, _index.isJSXText)(child)) {
(0, _cleanJSXElementLiteralChild.default)(child, elements);
continue;
}
if ((0, _index.isJSXExpressionContainer)(child)) child = child.expression;
if ((0, _index.isJSXEmptyExpression)(child)) continue;
elements.push(child);
}
return elements;
}
//# sourceMappingURL=buildChildren.js.map
@@ -0,0 +1 @@
{"version":3,"names":["_index","require","_cleanJSXElementLiteralChild","buildChildren","node","elements","i","children","length","child","isJSXText","cleanJSXElementLiteralChild","isJSXExpressionContainer","expression","isJSXEmptyExpression","push"],"sources":["../../../src/builders/react/buildChildren.ts"],"sourcesContent":["import {\n isJSXText,\n isJSXExpressionContainer,\n isJSXEmptyExpression,\n} from \"../../validators/generated/index.ts\";\nimport cleanJSXElementLiteralChild from \"../../utils/react/cleanJSXElementLiteralChild.ts\";\nimport type * as t from \"../../index.ts\";\n\ntype ReturnedChild =\n | t.JSXSpreadChild\n | t.JSXElement\n | t.JSXFragment\n | t.Expression;\n\nexport default function buildChildren(\n node: t.JSXElement | t.JSXFragment,\n): ReturnedChild[] {\n const elements = [];\n\n for (let i = 0; i < node.children.length; i++) {\n let child: any = node.children[i];\n\n if (isJSXText(child)) {\n cleanJSXElementLiteralChild(child, elements);\n continue;\n }\n\n if (isJSXExpressionContainer(child)) child = child.expression;\n if (isJSXEmptyExpression(child)) continue;\n\n elements.push(child);\n }\n\n return elements;\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAKA,IAAAC,4BAAA,GAAAD,OAAA;AASe,SAASE,aAAaA,CACnCC,IAAkC,EACjB;EACjB,MAAMC,QAAQ,GAAG,EAAE;EAEnB,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGF,IAAI,CAACG,QAAQ,CAACC,MAAM,EAAEF,CAAC,EAAE,EAAE;IAC7C,IAAIG,KAAU,GAAGL,IAAI,CAACG,QAAQ,CAACD,CAAC,CAAC;IAEjC,IAAI,IAAAI,gBAAS,EAACD,KAAK,CAAC,EAAE;MACpB,IAAAE,oCAA2B,EAACF,KAAK,EAAEJ,QAAQ,CAAC;MAC5C;IACF;IAEA,IAAI,IAAAO,+BAAwB,EAACH,KAAK,CAAC,EAAEA,KAAK,GAAGA,KAAK,CAACI,UAAU;IAC7D,IAAI,IAAAC,2BAAoB,EAACL,KAAK,CAAC,EAAE;IAEjCJ,QAAQ,CAACU,IAAI,CAACN,KAAK,CAAC;EACtB;EAEA,OAAOJ,QAAQ;AACjB","ignoreList":[]}
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createTSUnionType;
var _index = require("../generated/index.js");
var _removeTypeDuplicates = require("../../modifications/typescript/removeTypeDuplicates.js");
var _index2 = require("../../validators/generated/index.js");
function createTSUnionType(typeAnnotations) {
const types = typeAnnotations.map(type => {
return (0, _index2.isTSTypeAnnotation)(type) ? type.typeAnnotation : type;
});
const flattened = (0, _removeTypeDuplicates.default)(types);
if (flattened.length === 1) {
return flattened[0];
} else {
return (0, _index.tsUnionType)(flattened);
}
}
//# sourceMappingURL=createTSUnionType.js.map
@@ -0,0 +1 @@
{"version":3,"names":["_index","require","_removeTypeDuplicates","_index2","createTSUnionType","typeAnnotations","types","map","type","isTSTypeAnnotation","typeAnnotation","flattened","removeTypeDuplicates","length","tsUnionType"],"sources":["../../../src/builders/typescript/createTSUnionType.ts"],"sourcesContent":["import { tsUnionType } from \"../generated/index.ts\";\nimport removeTypeDuplicates from \"../../modifications/typescript/removeTypeDuplicates.ts\";\nimport { isTSTypeAnnotation } from \"../../validators/generated/index.ts\";\nimport type * as t from \"../../index.ts\";\n\n/**\n * Takes an array of `types` and flattens them, removing duplicates and\n * returns a `UnionTypeAnnotation` node containing them.\n */\nexport default function createTSUnionType(\n typeAnnotations: (t.TSTypeAnnotation | t.TSType)[],\n): t.TSType {\n const types = typeAnnotations.map(type => {\n return isTSTypeAnnotation(type) ? type.typeAnnotation : type;\n });\n const flattened = removeTypeDuplicates(types);\n\n if (flattened.length === 1) {\n return flattened[0];\n } else {\n return tsUnionType(flattened);\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AAOe,SAASG,iBAAiBA,CACvCC,eAAkD,EACxC;EACV,MAAMC,KAAK,GAAGD,eAAe,CAACE,GAAG,CAACC,IAAI,IAAI;IACxC,OAAO,IAAAC,0BAAkB,EAACD,IAAI,CAAC,GAAGA,IAAI,CAACE,cAAc,GAAGF,IAAI;EAC9D,CAAC,CAAC;EACF,MAAMG,SAAS,GAAG,IAAAC,6BAAoB,EAACN,KAAK,CAAC;EAE7C,IAAIK,SAAS,CAACE,MAAM,KAAK,CAAC,EAAE;IAC1B,OAAOF,SAAS,CAAC,CAAC,CAAC;EACrB,CAAC,MAAM;IACL,OAAO,IAAAG,kBAAW,EAACH,SAAS,CAAC;EAC/B;AACF","ignoreList":[]}
+21
View File
@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = validateNode;
var _validate = require("../validators/validate.js");
var _index = require("../index.js");
function validateNode(node) {
if (node == null || typeof node !== "object") return;
const fields = _index.NODE_FIELDS[node.type];
if (!fields) return;
const keys = _index.BUILDER_KEYS[node.type];
for (const key of keys) {
const field = fields[key];
if (field != null) (0, _validate.validateInternal)(field, node, key, node[key]);
}
return node;
}
//# sourceMappingURL=validateNode.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["_validate","require","_index","validateNode","node","fields","NODE_FIELDS","type","keys","BUILDER_KEYS","key","field","validateInternal"],"sources":["../../src/builders/validateNode.ts"],"sourcesContent":["import { validateInternal } from \"../validators/validate.ts\";\nimport type * as t from \"../index.ts\";\nimport { BUILDER_KEYS, NODE_FIELDS } from \"../index.ts\";\n\nexport default function validateNode<N extends t.Node>(node: N) {\n if (node == null || typeof node !== \"object\") return;\n const fields = NODE_FIELDS[node.type];\n if (!fields) return;\n\n // todo: because keys not in BUILDER_KEYS are not validated - this actually allows invalid nodes in some cases\n const keys = BUILDER_KEYS[node.type] as (keyof N & string)[];\n for (const key of keys) {\n const field = fields[key];\n if (field != null) validateInternal(field, node, key, node[key]);\n }\n return node;\n}\n"],"mappings":";;;;;;AAAA,IAAAA,SAAA,GAAAC,OAAA;AAEA,IAAAC,MAAA,GAAAD,OAAA;AAEe,SAASE,YAAYA,CAAmBC,IAAO,EAAE;EAC9D,IAAIA,IAAI,IAAI,IAAI,IAAI,OAAOA,IAAI,KAAK,QAAQ,EAAE;EAC9C,MAAMC,MAAM,GAAGC,kBAAW,CAACF,IAAI,CAACG,IAAI,CAAC;EACrC,IAAI,CAACF,MAAM,EAAE;EAGb,MAAMG,IAAI,GAAGC,mBAAY,CAACL,IAAI,CAACG,IAAI,CAAyB;EAC5D,KAAK,MAAMG,GAAG,IAAIF,IAAI,EAAE;IACtB,MAAMG,KAAK,GAAGN,MAAM,CAACK,GAAG,CAAC;IACzB,IAAIC,KAAK,IAAI,IAAI,EAAE,IAAAC,0BAAgB,EAACD,KAAK,EAAEP,IAAI,EAAEM,GAAG,EAAEN,IAAI,CAACM,GAAG,CAAC,CAAC;EAClE;EACA,OAAON,IAAI;AACb","ignoreList":[]}
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = clone;
var _cloneNode = require("./cloneNode.js");
function clone(node) {
return (0, _cloneNode.default)(node, false);
}
//# sourceMappingURL=clone.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["_cloneNode","require","clone","node","cloneNode"],"sources":["../../src/clone/clone.ts"],"sourcesContent":["import cloneNode from \"./cloneNode.ts\";\nimport type * as t from \"../index.ts\";\n\n/**\n * Create a shallow clone of a `node`, including only\n * properties belonging to the node.\n * @deprecated Use t.cloneNode instead.\n */\nexport default function clone<T extends t.Node>(node: T): T {\n return cloneNode(node, /* deep */ false);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA;AAQe,SAASC,KAAKA,CAAmBC,IAAO,EAAK;EAC1D,OAAO,IAAAC,kBAAS,EAACD,IAAI,EAAa,KAAK,CAAC;AAC1C","ignoreList":[]}
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = cloneDeep;
var _cloneNode = require("./cloneNode.js");
function cloneDeep(node) {
return (0, _cloneNode.default)(node);
}
//# sourceMappingURL=cloneDeep.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["_cloneNode","require","cloneDeep","node","cloneNode"],"sources":["../../src/clone/cloneDeep.ts"],"sourcesContent":["import cloneNode from \"./cloneNode.ts\";\nimport type * as t from \"../index.ts\";\n\n/**\n * Create a deep clone of a `node` and all of it's child nodes\n * including only properties belonging to the node.\n * @deprecated Use t.cloneNode instead.\n */\nexport default function cloneDeep<T extends t.Node>(node: T): T {\n return cloneNode(node);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA;AAQe,SAASC,SAASA,CAAmBC,IAAO,EAAK;EAC9D,OAAO,IAAAC,kBAAS,EAACD,IAAI,CAAC;AACxB","ignoreList":[]}
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = cloneDeepWithoutLoc;
var _cloneNode = require("./cloneNode.js");
function cloneDeepWithoutLoc(node) {
return (0, _cloneNode.default)(node, true, true);
}
//# sourceMappingURL=cloneDeepWithoutLoc.js.map
@@ -0,0 +1 @@
{"version":3,"names":["_cloneNode","require","cloneDeepWithoutLoc","node","cloneNode"],"sources":["../../src/clone/cloneDeepWithoutLoc.ts"],"sourcesContent":["import cloneNode from \"./cloneNode.ts\";\nimport type * as t from \"../index.ts\";\n/**\n * Create a deep clone of a `node` and all of it's child nodes\n * including only properties belonging to the node.\n * excluding `_private` and location properties.\n */\nexport default function cloneDeepWithoutLoc<T extends t.Node>(node: T): T {\n return cloneNode(node, /* deep */ true, /* withoutLoc */ true);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA;AAOe,SAASC,mBAAmBA,CAAmBC,IAAO,EAAK;EACxE,OAAO,IAAAC,kBAAS,EAACD,IAAI,EAAa,IAAI,EAAmB,IAAI,CAAC;AAChE","ignoreList":[]}
+107
View File
@@ -0,0 +1,107 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = cloneNode;
var _index = require("../definitions/index.js");
var _index2 = require("../validators/generated/index.js");
const {
hasOwn
} = {
hasOwn: Function.call.bind(Object.prototype.hasOwnProperty)
};
function cloneIfNode(obj, deep, withoutLoc, commentsCache) {
if (obj && typeof obj.type === "string") {
return cloneNodeInternal(obj, deep, withoutLoc, commentsCache);
}
return obj;
}
function cloneIfNodeOrArray(obj, deep, withoutLoc, commentsCache) {
if (Array.isArray(obj)) {
return obj.map(node => cloneIfNode(node, deep, withoutLoc, commentsCache));
}
return cloneIfNode(obj, deep, withoutLoc, commentsCache);
}
function cloneNode(node, deep = true, withoutLoc = false) {
return cloneNodeInternal(node, deep, withoutLoc, new Map());
}
function cloneNodeInternal(node, deep = true, withoutLoc = false, commentsCache) {
if (!node) return node;
const {
type
} = node;
const newNode = {
type: node.type
};
if ((0, _index2.isIdentifier)(node)) {
newNode.name = node.name;
if (hasOwn(node, "optional") && typeof node.optional === "boolean") {
newNode.optional = node.optional;
}
if (hasOwn(node, "typeAnnotation")) {
newNode.typeAnnotation = deep ? cloneIfNodeOrArray(node.typeAnnotation, true, withoutLoc, commentsCache) : node.typeAnnotation;
}
if (hasOwn(node, "decorators")) {
newNode.decorators = deep ? cloneIfNodeOrArray(node.decorators, true, withoutLoc, commentsCache) : node.decorators;
}
} else if (!hasOwn(_index.NODE_FIELDS, type)) {
throw new Error(`Unknown node type: "${type}"`);
} else {
for (const field of Object.keys(_index.NODE_FIELDS[type])) {
if (hasOwn(node, field)) {
if (deep) {
newNode[field] = (0, _index2.isFile)(node) && field === "comments" ? maybeCloneComments(node.comments, deep, withoutLoc, commentsCache) : cloneIfNodeOrArray(node[field], true, withoutLoc, commentsCache);
} else {
newNode[field] = node[field];
}
}
}
}
if (hasOwn(node, "loc")) {
if (withoutLoc) {
newNode.loc = null;
} else {
newNode.loc = node.loc;
}
}
if (hasOwn(node, "leadingComments")) {
newNode.leadingComments = maybeCloneComments(node.leadingComments, deep, withoutLoc, commentsCache);
}
if (hasOwn(node, "innerComments")) {
newNode.innerComments = maybeCloneComments(node.innerComments, deep, withoutLoc, commentsCache);
}
if (hasOwn(node, "trailingComments")) {
newNode.trailingComments = maybeCloneComments(node.trailingComments, deep, withoutLoc, commentsCache);
}
if (hasOwn(node, "extra")) {
newNode.extra = Object.assign({}, node.extra);
}
return newNode;
}
function maybeCloneComments(comments, deep, withoutLoc, commentsCache) {
if (!comments || !deep) {
return comments;
}
return comments.map(comment => {
const cache = commentsCache.get(comment);
if (cache) return cache;
const {
type,
value,
loc
} = comment;
const ret = {
type,
value,
loc
};
if (withoutLoc) {
ret.loc = null;
}
commentsCache.set(comment, ret);
return ret;
});
}
//# sourceMappingURL=cloneNode.js.map
File diff suppressed because one or more lines are too long
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = cloneWithoutLoc;
var _cloneNode = require("./cloneNode.js");
function cloneWithoutLoc(node) {
return (0, _cloneNode.default)(node, false, true);
}
//# sourceMappingURL=cloneWithoutLoc.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["_cloneNode","require","cloneWithoutLoc","node","cloneNode"],"sources":["../../src/clone/cloneWithoutLoc.ts"],"sourcesContent":["import cloneNode from \"./cloneNode.ts\";\nimport type * as t from \"../index.ts\";\n\n/**\n * Create a shallow clone of a `node` excluding `_private` and location properties.\n */\nexport default function cloneWithoutLoc<T extends t.Node>(node: T): T {\n return cloneNode(node, /* deep */ false, /* withoutLoc */ true);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA;AAMe,SAASC,eAAeA,CAAmBC,IAAO,EAAK;EACpE,OAAO,IAAAC,kBAAS,EAACD,IAAI,EAAa,KAAK,EAAmB,IAAI,CAAC;AACjE","ignoreList":[]}
+15
View File
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = addComment;
var _addComments = require("./addComments.js");
function addComment(node, type, content, line) {
return (0, _addComments.default)(node, type, [{
type: line ? "CommentLine" : "CommentBlock",
value: content
}]);
}
//# sourceMappingURL=addComment.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["_addComments","require","addComment","node","type","content","line","addComments","value"],"sources":["../../src/comments/addComment.ts"],"sourcesContent":["import addComments from \"./addComments.ts\";\nimport type * as t from \"../index.ts\";\n\n/**\n * Add comment of certain type to a node.\n */\nexport default function addComment<T extends t.Node>(\n node: T,\n type: t.CommentTypeShorthand,\n content: string,\n line?: boolean,\n): T {\n return addComments(node, type, [\n {\n type: line ? \"CommentLine\" : \"CommentBlock\",\n value: content,\n } as t.Comment,\n ]);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAMe,SAASC,UAAUA,CAChCC,IAAO,EACPC,IAA4B,EAC5BC,OAAe,EACfC,IAAc,EACX;EACH,OAAO,IAAAC,oBAAW,EAACJ,IAAI,EAAEC,IAAI,EAAE,CAC7B;IACEA,IAAI,EAAEE,IAAI,GAAG,aAAa,GAAG,cAAc;IAC3CE,KAAK,EAAEH;EACT,CAAC,CACF,CAAC;AACJ","ignoreList":[]}
+22
View File
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = addComments;
function addComments(node, type, comments) {
if (!comments || !node) return node;
const key = `${type}Comments`;
if (node[key]) {
if (type === "leading") {
node[key] = comments.concat(node[key]);
} else {
node[key].push(...comments);
}
} else {
node[key] = comments;
}
return node;
}
//# sourceMappingURL=addComments.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["addComments","node","type","comments","key","concat","push"],"sources":["../../src/comments/addComments.ts"],"sourcesContent":["import type * as t from \"../index.ts\";\n\n/**\n * Add comments of certain type to a node.\n */\nexport default function addComments<T extends t.Node>(\n node: T,\n type: t.CommentTypeShorthand,\n comments: t.Comment[],\n): T {\n if (!comments || !node) return node;\n\n const key = `${type}Comments` as const;\n\n if (node[key]) {\n if (type === \"leading\") {\n node[key] = comments.concat(node[key]);\n } else {\n node[key].push(...comments);\n }\n } else {\n node[key] = comments;\n }\n\n return node;\n}\n"],"mappings":";;;;;;AAKe,SAASA,WAAWA,CACjCC,IAAO,EACPC,IAA4B,EAC5BC,QAAqB,EAClB;EACH,IAAI,CAACA,QAAQ,IAAI,CAACF,IAAI,EAAE,OAAOA,IAAI;EAEnC,MAAMG,GAAG,GAAG,GAAGF,IAAI,UAAmB;EAEtC,IAAID,IAAI,CAACG,GAAG,CAAC,EAAE;IACb,IAAIF,IAAI,KAAK,SAAS,EAAE;MACtBD,IAAI,CAACG,GAAG,CAAC,GAAGD,QAAQ,CAACE,MAAM,CAACJ,IAAI,CAACG,GAAG,CAAC,CAAC;IACxC,CAAC,MAAM;MACLH,IAAI,CAACG,GAAG,CAAC,CAACE,IAAI,CAAC,GAAGH,QAAQ,CAAC;IAC7B;EACF,CAAC,MAAM;IACLF,IAAI,CAACG,GAAG,CAAC,GAAGD,QAAQ;EACtB;EAEA,OAAOF,IAAI;AACb","ignoreList":[]}
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = inheritInnerComments;
var _inherit = require("../utils/inherit.js");
function inheritInnerComments(child, parent) {
(0, _inherit.default)("innerComments", child, parent);
}
//# sourceMappingURL=inheritInnerComments.js.map
@@ -0,0 +1 @@
{"version":3,"names":["_inherit","require","inheritInnerComments","child","parent","inherit"],"sources":["../../src/comments/inheritInnerComments.ts"],"sourcesContent":["import inherit from \"../utils/inherit.ts\";\nimport type * as t from \"../index.ts\";\n\nexport default function inheritInnerComments(\n child: t.Node,\n parent: t.Node,\n): void {\n inherit(\"innerComments\", child, parent);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,QAAA,GAAAC,OAAA;AAGe,SAASC,oBAAoBA,CAC1CC,KAAa,EACbC,MAAc,EACR;EACN,IAAAC,gBAAO,EAAC,eAAe,EAAEF,KAAK,EAAEC,MAAM,CAAC;AACzC","ignoreList":[]}

Some files were not shown because too many files have changed in this diff Show More