Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
{
// 파일 저장 시 자동 포맷팅
"editor.formatOnSave": true,

// TypeScript/JavaScript 파일에 대한 기본 포맷터로 Prettier 사용
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},

// Markdown 및 MDX 파일에 대한 ESLint 및 Prettier 비활성화
"[markdown]": {
"editor.formatOnSave": false,
Expand All @@ -23,21 +21,17 @@
"source.fixAll.eslint": "never"
}
},

// ESLint 설정
"eslint.enable": true,
"eslint.validate": ["javascript", "typescript"],

// 파일 저장 시 ESLint 자동 수정 (Markdown/MDX 제외)
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},

// Prettier 설정
"prettier.requireConfig": true,
"prettier.configPath": ".prettierrc",
"prettier.disableLanguages": ["markdown", "mdx"],

// TypeScript 설정
"typescript.tsdk": "node_modules/typescript/lib"
}
17 changes: 15 additions & 2 deletions bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ program
.description("Generate ITDOC test code based on LLM.")
.option("-a, --app <appPath>", "Path to the Express root app file.")
.option("-e, --env <envPath>", "Path to the .env file.")
.action(async (options: { env?: string; app?: string }) => {
.option(
"-l, --lang <language>",
"Output language for test generation: 'en' for English, 'ko' for Korean (default: 'ko')",
)
.action(async (options: { env?: string; app?: string; lang?: string }) => {
const envPath = options.env
? path.isAbsolute(options.env)
? options.env
Expand All @@ -74,13 +78,22 @@ program
process.exit(1)
}

const lang = options.lang?.toLowerCase()
const isEn = lang === "en"

if (lang && lang !== "en" && lang !== "ko") {
logger.error(`Invalid language option: ${lang}. Must be 'en' or 'ko'.`)
process.exit(1)
}

logger.box("ITDOC LLM START")
if (options.app) {
const appPath = resolvePath(options.app)

logger.info(`Running analysis based on Express app path: ${appPath}`)
logger.info(`Output language: ${isEn ? "English" : "Korean"}`)
try {
await generateByLLM(appPath, envPath)
await generateByLLM(appPath, envPath, isEn)
} catch (err) {
logger.error(`LLM generation failed: ${(err as Error).message}`)
process.exit(1)
Expand Down
21 changes: 20 additions & 1 deletion itdoc-doc/docs/experiments/LLM.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,29 @@ Currently, source code-based automatic test generation is only supported for the
```bash
itdoc generate -a {YOUR_APP_FILE_PATH}
itdoc generate --app {YOUR_APP_FILE_PATH}

# Generate tests in English(default : korean)
itdoc generate -a {YOUR_APP_FILE_PATH} -l en
itdoc generate --app {YOUR_APP_FILE_PATH} --lang en
```

| Option | Description |
|------------------------------------------------------------------------|--------------------------------|
| <span style={{color: '#0d6efd', fontWeight: 'bold'}}>--app (-a)</span> | Root app source code file path |
| <span style={{color: '#0d6efd', fontWeight: 'bold'}}>--lang (-l)</span> | Output language: `en` for English, `ko` for Korean (default: `ko`) |

When you run this command, it analyzes the Express application defined in `{YOUR_APP_FILE_PATH}` and automatically generates tests for the API endpoints in that application.

:::tip[Language Selection]
- By default, test descriptions and comments are generated in **Korean** (`ko`).
- Use the `--lang en` (or `-l en`) option to generate all test content in **English**.
:::

**Example:**
```bash
# Korean output (default)
itdoc generate -a ./app.js

When you run this command, it analyzes the Express application defined in `{YOUR_APP_FILE_PATH}` and automatically generates tests for the API endpoints in that application.
# English output
itdoc generate -a ./app.js --lang en
```
Original file line number Diff line number Diff line change
Expand Up @@ -190,16 +190,35 @@ LLM 기능을 사용하기 전과 후를 비교해보겠습니다.
```bash
itdoc generate -a {YOUR_APP_FILE_PATH}
itdoc generate --app {YOUR_APP_FILE_PATH}

# 영어로 테스트 생성 (기본값: 한국어)
itdoc generate -a {YOUR_APP_FILE_PATH} -l en
itdoc generate --app {YOUR_APP_FILE_PATH} --lang en
```

| 옵션 | 설명 |
|------------------------------------------------------------------------|---------------------|
| <span style={{color: '#0d6efd', fontWeight: 'bold'}}>--app (-a)</span> | root app 소스코드 파일 경로 |
| <span style={{color: '#0d6efd', fontWeight: 'bold'}}>--lang (-l)</span> | 출력 언어: `en`은 영어, `ko`는 한국어 (기본값: `ko`) |


명령어를 실행하면 `{YOUR_APP_FILE_PATH}`에 정의된 Express 애플리케이션을 분석하여,
해당 애플리케이션의 API 엔드포인트에 대한 테스트를 자동으로 생성합니다.

:::tip[언어 선택]
- 기본적으로 테스트 설명과 주석은 **한국어**(`ko`)로 생성됩니다.
- `--lang en` (또는 `-l en`) 옵션을 사용하면 모든 테스트 내용이 **영어**로 생성됩니다.
:::

**예시:**
```bash
# 한국어 출력 (기본값)
itdoc generate -a ./app.js

# 영어 출력
itdoc generate -a ./app.js --lang en
```

:::info[itdoc은 소스코드를 외부 서버에 전송하지 않습니다]
자체적인 AST 분석을 통해 `API Spec Markdown`을 만들고, 이를 ChatGPT에 전달하여 테스트 케이스를 생성합니다.
따라서, 여러분의 소스코드를 외부 서버에 전송하지 않으니 안심하고 사용하세요.
Expand Down
15 changes: 12 additions & 3 deletions script/llm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,12 @@ function groupAndChunkSpecRoutes(routes: RouteResult[], chunkSize: number = 10):
const by: Record<string, RouteResult[]> = {}
for (const r of routes) {
const prefix = getPathPrefix(r.path || "/unknown")
;(by[prefix] ||= []).push(r)
if (!by[prefix]) {
by[prefix] = []
}
by[prefix].push(r)
}

const out: RouteResult[][] = []
for (const group of Object.values(by)) {
for (const c of _.chunk(group, chunkSize)) out.push(c)
Expand Down Expand Up @@ -126,9 +130,14 @@ export async function makeitdoc(
* - Writes the resulting test file with prelude (imports/helpers).
* @param {string} [appPath] - Path to Express app entry.
* @param {string} [envPath] - Path to .env file containing OPENAI_API_KEY.
* @param {boolean} [isEn] - Output in English (true) or Korean (false). Defaults to false (Korean).
* @returns {Promise<void>} Exits the process on unrecoverable errors.
*/
export default async function generateByLLM(appPath?: string, envPath?: string): Promise<void> {
export default async function generateByLLM(
appPath?: string,
envPath?: string,
isEn: boolean = false,
): Promise<void> {
const actualEnv = loadFile("env", envPath, false)
dotenv.config({ path: actualEnv })
if (!process.env.OPENAI_API_KEY) {
Expand Down Expand Up @@ -163,7 +172,7 @@ export default async function generateByLLM(appPath?: string, envPath?: string):
process.exit(1)
}

const doc = await makeitdoc(openai, analyzedRoutes, false, isTypeScript)
const doc = await makeitdoc(openai, analyzedRoutes, isEn, isTypeScript)
if (!doc) {
logger.error("Failed to generate itdoc from markdown spec.")
process.exit(1)
Expand Down
29 changes: 28 additions & 1 deletion script/llm/prompt/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,32 @@ export function getItdocPrompt(
const codeMessage = `${codeType} ${lang.codeLabel}`
const partGuide = part > 1 ? lang.chunksGuideNext : lang.chunksGuideFirst

return `
const promptTemplate = isEn
? `
Generate an itdoc test script in ${codeMessage} based on the following test description.

Required Rules:
- ${lang.noComments}
- ${lang.codeOnly}
- ${lang.orderGuide}
- ${lang.branchGuide}
- ${lang.branchGuide2}
- ${lang.fieldGuide}
- ${lang.fieldGuide2}
- ${lang.headerGuide}
- ${lang.noPathImport}
- ${lang.initGiven}
- ${lang.etc}
- ${partGuide}
- ${lang.outputInstruction}

[Route Analysis Results to Test]
${JSON.stringify(routesChunk, null, 2)}

[Function Example]
${itdocExample}
`.trim()
: `
다음 테스트 설명을 기반으로 itdoc 테스트 스크립트를 ${codeMessage}로 생성하세요.

필수 규칙:
Expand All @@ -140,4 +165,6 @@ ${JSON.stringify(routesChunk, null, 2)}
[함수 예시]
${itdocExample}
`.trim()

return promptTemplate
}
Loading