-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c1255b7
commit 7e7e0ad
Showing
3 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
import {OpenAI } from "openai"; | ||
import Anthropic from "@anthropic-ai/sdk"; | ||
import * as fs from "fs"; | ||
import * as ts from "typescript"; | ||
import * as dotenv from "dotenv"; | ||
import { Command } from 'commander'; | ||
const program = new Command(); | ||
|
||
|
||
dotenv.config(); | ||
|
||
const openai = new OpenAI({ | ||
apiKey: process.env.OPENAI_API_KEY, | ||
}); | ||
|
||
const claude = new Anthropic({ | ||
apiKey: process.env.CLAUDE_API_KEY | ||
}); | ||
|
||
type ClassMethod = { | ||
className: string; | ||
methodName: string; | ||
methodSignature: string; | ||
comments: string; // Add this line to include comments | ||
} | ||
|
||
type ParseSettings = { | ||
className: string; | ||
file: string; | ||
exclude?: string[]; | ||
include?: string[]; | ||
} | ||
|
||
function parseDeclarations(settings: ParseSettings): ClassMethod[] { | ||
const filePath = settings.file; | ||
|
||
const fileContent = fs.readFileSync(filePath, "utf8"); | ||
const sourceFile = ts.createSourceFile( | ||
filePath, | ||
fileContent, | ||
ts.ScriptTarget.Latest, | ||
true | ||
); | ||
let classMethods: ClassMethod[] = []; | ||
|
||
function getLeadingComments(node: ts.Node): string { | ||
const fullText = node.getFullText(sourceFile); | ||
const comments = ts.getLeadingCommentRanges(fullText, 0); | ||
|
||
if (!comments) return ''; | ||
let commentText = ''; | ||
comments.forEach((comment) => { | ||
commentText += fullText.substring(comment.pos, comment.end) + '\n'; | ||
}); | ||
return commentText.trim(); | ||
} | ||
|
||
function visit(node: ts.Node) { | ||
if ((ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && node.name) { | ||
|
||
if (settings.className && node.name.text !== settings.className) { | ||
return; | ||
} | ||
|
||
const className = node.name.text; | ||
node.members.forEach((member) => { | ||
if (ts.isMethodSignature(member) || ts.isMethodDeclaration(member)) { | ||
if (member.name) { | ||
let methodName = member.name.getText(sourceFile); | ||
|
||
if (settings.exclude && settings.exclude.includes(methodName)) { | ||
return; | ||
} | ||
|
||
if (settings.include && !settings.include.includes(methodName)) { | ||
return; | ||
} | ||
|
||
let methodSignature = member.getText(sourceFile); | ||
let comments = getLeadingComments(member); | ||
classMethods.push({ className, methodName, methodSignature, comments }); | ||
} | ||
} | ||
}); | ||
} | ||
ts.forEachChild(node, visit); | ||
} | ||
|
||
visit(sourceFile); | ||
return classMethods; | ||
} | ||
|
||
|
||
type AiModel = 'claude' | 'gpt3' | 'gpt4' | ||
|
||
async function createDocs(classMethods: ClassMethod[], aiModel: AiModel): Promise<void> { | ||
const fewShotExample = fs.readFileSync(`${__dirname}/wow.api.ts`); | ||
|
||
let currentClass = ''; | ||
for (const { className, methodName, methodSignature, comments } of classMethods) { | ||
if (currentClass !== className) { | ||
// When we encounter a new class, we reset currentClass to the new className | ||
currentClass = className; | ||
} | ||
|
||
let content: string; | ||
let response: any; | ||
const prompt = `${fewShotExample}\n\n Use the provided examples of documenting methods and knowneldge of mod-eluna, azerothcore, create markdown docs for this method: \n\n declare class ${className} {\n Inline Code Comment: ${comments} Method: ${methodName} MethodSignature ${methodSignature}\n} the examples should be not be too simple, and have 10-20 lines`; | ||
switch(aiModel) { | ||
case 'gpt3': | ||
response = await openai.chat.completions.create({ | ||
model: "gpt-3.5-turbo", | ||
messages: [{ role: 'user', content: prompt}], | ||
}); | ||
|
||
if(typeof response.choices[0].message.content == 'string') { | ||
content = response.choices[0].message.content; | ||
} | ||
break; | ||
case 'gpt4': | ||
response = await openai.chat.completions.create({ | ||
model: "gpt-4-turbo-preview", | ||
messages: [{ role: 'user', content: prompt}], | ||
}); | ||
if(typeof response.choices[0].message.content == 'string') { | ||
content = response.choices[0].message.content; | ||
} | ||
break; | ||
case 'claude': | ||
response = await claude.messages.create({ | ||
model: 'claude-3-opus-20240229', | ||
max_tokens: 2000, | ||
messages: [{ role: "user", content: prompt}] | ||
}); | ||
if(typeof response.content[0].text == 'string') { | ||
content = response.content[0].text; | ||
} | ||
break; | ||
} | ||
|
||
|
||
console.log(`writing documentation for ${className}.${methodName}`); | ||
const documentation = content.replace(`filename: ${className.toLowerCase()}.md\n`, ''); | ||
// Ensure directory exists | ||
const dir = './docs/wowapi/classes'; | ||
if (!fs.existsSync(dir)){ | ||
fs.mkdirSync(dir); | ||
} | ||
// Write to a separate markdown file for each class | ||
fs.appendFileSync(`${dir}/${className}.md`, documentation + '\n\n'); | ||
} | ||
} | ||
|
||
( async() => { | ||
|
||
program | ||
.option('-m, --model <model>', 'The AI model to use for documentation generation. Options are gpt3, gpt4, claude', 'gpt3') | ||
.requiredOption('-f, --file <file>', 'The file to parse for class methods') | ||
.requiredOption('-c, --class <class>', 'Which classe to process from the file') | ||
.option('-e, --exclude <exclude>', 'The file to parse for class methods') | ||
.option('-i, --include <include>', 'The file to parse for class methods') | ||
program.parse(); | ||
|
||
const options = program.opts(); | ||
const classOutputs = parseDeclarations({ | ||
file: options.file, | ||
className: options.class, | ||
exclude: options.exclude ? options.exclude.split(',') : undefined, | ||
include: options.include ? options.include.split(',') : undefined | ||
}); | ||
console.log(classOutputs); | ||
await createDocs(classOutputs, options.model); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
Here is an example of how to convert TypeScript Class definitions into | ||
readme documentation in a consistent format based on how it will be used | ||
to build mods for mod-eluna on Azerothcore. | ||
|
||
Given the following TypeScript class definition for the Player class: | ||
|
||
declare class Player extends Unit { | ||
/** | ||
* Adds combo points to the [Player] | ||
*/ | ||
AddComboPoints(target: Unit, count: number): void; | ||
|
||
/** | ||
* Adds the given amount of the specified item entry to the player. | ||
*/ | ||
AddItem(entry: number, itemCount?: number): Item; | ||
|
||
/** | ||
*/ | ||
AddLifetimeKills(): void; | ||
|
||
/** | ||
* Tries to add the given quest entry for the [Player]. | ||
*/ | ||
AddQuest(entry: number): void; | ||
|
||
/** | ||
* Advances all of the [Player]s skills to the amount specified | ||
*/ | ||
AdvanceAllSkills(skillStep: number): void; | ||
|
||
/** | ||
* Advances a [Player]s specific skill to the amount specified | ||
*/ | ||
AdvanceSkill(skillId: number, skillStep: number): void; | ||
|
||
/** | ||
* Advances all of the [Player]s weapon skills to the maximum amount available | ||
*/ | ||
AdvanceSkillsToMax(): void; | ||
|
||
/** | ||
* Completes the [Quest] if a [Quest] area is explored, or completes the [Quest] | ||
*/ | ||
AreaExploredOrEventHappens(quest: number): void; | ||
|
||
/** | ||
* Returns 'true' if the [Player] can block incomming attacks, 'false' otherwise. | ||
*/ | ||
CanBlock(): boolean; | ||
|
||
/** | ||
* Returns 'true' if the [Player] satisfies all requirements to complete the quest entry. | ||
*/ | ||
CanCompleteQuest(entry: number): boolean; | ||
} | ||
## AddComboPoints | ||
If the player is a rogue or druid, this method will add combo points to the player | ||
based on the target and the count of combo points to add. | ||
|
||
### Parameters | ||
* enemy: [Unit](./unit.md) - Unit to apply combo points to | ||
* count: number - The number of combo points to apply | ||
|
||
### Example Usage: | ||
Simple script to start a rogue/druid with an advantage. | ||
```typescript | ||
const onPlayerEnter: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { | ||
player.AddComboPoints(enemy, 5); | ||
} | ||
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onPlayerEnter(...args)); | ||
``` | ||
## AddItem | ||
Give the player an item based on the item entry. These items can be referenced in World Database item_template. | ||
for more information about items you can find more information here: https://www.azerothcore.org/wiki/item_template. | ||
Items will be added to the current bag inventory if there is space. | ||
|
||
### Parameters <hr /> | ||
entry: number - Item Entry Id from item_template table | ||
count: number - number of items to grant (Items that exceed unique counts or limits to amount will fail) | ||
### Returns | ||
item: [Item](./item.md) - The item(s) that was given to the player. | ||
### Example Usage: | ||
Grant bonus Badges of Justice | ||
const BADGE_OF_JUSTICE_ENTRY = 29434; | ||
const BADGE_OF_JUSTICE_BONUS = 2; | ||
|
||
const LootToken: player_event_on_loot_item = (event: number, player: Player, item: Item) => { | ||
|
||
if(item.GetEntry() == BADGE_OF_JUSTICE_ENTRY) { | ||
player.AddItem(BADGE_OF_JUSTICE_ENTRY, BADGE_OF_JUSTICE_BONUS); | ||
} | ||
} | ||
|
||
RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, (...args) => LootToken(...args)); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { isReturnStatement } from "typescript" | ||
|
||
Here is an example of how to convert TypeScript Class definitions into | ||
readme documentation in a consistent format based on how it will be used | ||
to build AIO plugins which is similar to World of Warcraft AddOns, which reference | ||
the World of Warcraft API that can be found here: https://wowpedia.fandom.com/wiki/World_of_Warcraft_API | ||
|
||
|
||
/** | ||
* This is another abstract object type that groups together a number of font related methods that are used by multiple other widget types. | ||
* This doesn't have a direct correlation to a UI object. See FontInstance object information for details. | ||
*/ | ||
interface FontInstance extends UIObject { | ||
|
||
/** | ||
* Returns detailed information on a font object. | ||
* @returns MultipleReturnValues: | ||
* - **fontName**: Path to font file | ||
* - **fontHeight**: Font height in pixels. Due to internal graphics engine workings, this will be ridiculously close to an integer number, | ||
* but not quite ever fully. | ||
* - **fontFlags**: See FontInstance:SetFont(). | ||
* @tupleReturn | ||
*/ | ||
GetFont(): [string, number, string]; | ||
|
||
/** | ||
* Gets the text color of of a Font Instance. | ||
* @return MultipleReturnValues: | ||
* r: The red color | ||
* g: The green color | ||
* b: The blue color | ||
* a?: the alpha (opacity) | ||
* @tupleReturn | ||
*/ | ||
GetTextColor(): [number, number, number, number?]; | ||
|
||
/** | ||
* The function is used to set the font to use for displaying text. | ||
* | ||
* @param font path to the font file, relative to the WoW base directory. | ||
* @param size size in points. | ||
* @param flags any comma-delimited combination of "OUTLINE", "THICKOUTLINE" and "MONOCHROME". | ||
*/ | ||
SetFont(font: string, size: number, flags?: FontInstanceFlags): void; | ||
|
||
/** | ||
* Sets horizontal text justification | ||
* | ||
* @param align the new align | ||
*/ | ||
SetJustifyH(align: HorizontalAlign): void; | ||
|
||
/** | ||
* Sets vertical text justification | ||
* | ||
* @param align the new align | ||
*/ | ||
SetJustifyV(align: VerticalAlign): void; | ||
|
||
/** | ||
* Sets the default text color. | ||
* | ||
* @param r red color | ||
* @param g green color | ||
* @param b blue color | ||
* @param a alpha (opacity) | ||
*/ | ||
SetTextColor(r: number, g: number, b: number, a?: number): void; | ||
} | ||
## GetFont | ||
This will return detailed information about the current font instanceof. | ||
|
||
### Parameters | ||
None | ||
|
||
### Returns | ||
**fontName** string - Path to font file | ||
**fontHeight** number - Font height in pixels. Due to internal graphics engine workings, this will be ridiculously close to an integer number, but not quite ever fully | ||
**fontFlags** atring - string - Any comma-delimited combination of OUTLINE, THICK and MONOCHROME; otherwise must be at least an empty string (except for FontString objects). | ||
|
||
### Example Usage: | ||
Get the font information for the current font instance. | ||
```typescript | ||
const myfont = CreateFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE"); | ||
const [fontName, height, flags] = myfont.GetFont(); | ||
const text = myFrame.CreateFontString(myId, "OVERLAY", myfont); | ||
text.SetText("Hello, World!"); | ||
``` | ||
## SetFont | ||
This will change the font details on an existing font instance. | ||
|
||
### Parameters <hr /> | ||
**fontName** string - Path to font file | ||
**fontHeight** number - Font height in pixels. Due to internal graphics engine workings, this will be ridiculously close to an integer number, but not quite ever fully | ||
**fontFlags** atring - string - Any comma-delimited combination of OUTLINE, THICK and MONOCHROME; otherwise must be at least an empty string (except for FontString objects). | ||
|
||
### Example Usage: | ||
```typescript | ||
const myfont = CreateFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE"); | ||
myFont.SetFont("Fonts\\Arial.TTF", 10, "OUTLINE"); | ||
const [fontName, height, flags] = myfont.GetFont(); | ||
const text = myFrame.CreateFontString(myId, "OVERLAY", myfont); | ||
text.SetText("I am Arial now!"); | ||
``` |