Skip to main content

Welcome Contributors!

Thank you for your interest in contributing to FG Character Extractor. This guide will help you understand the project structure, coding standards, and contribution workflow.

Project Overview

FG Character Extractor is a Go CLI tool that extracts individual character sheets from Fantasy Grounds db.xml campaign files. The project emphasizes:
  • Simplicity: Standard library only, no external dependencies
  • Reliability: Comprehensive testing with golden file validation
  • Cross-platform: Builds for macOS (Intel/ARM) and Windows
The project uses Go 1.25.7+ and is built with standard tooling (Go, Task, optional devbox).

Getting Started

1

Fork and clone the repository

git clone https://github.com/sdelrio/fg-char-extract.git
cd fg-char-extract
2

Set up your development environment

Install prerequisites:See Building for details.
3

Verify your setup

task build
task test
4

Create a feature branch

git checkout -b feat/your-feature-name

Code Style Guidelines

FG Character Extractor follows specific conventions based on AGENTS.md. Please adhere to these standards:

Naming Conventions

Use snake_case for all function names:
// Good
func skip_element(d *xml.Decoder, start xml.StartElement) error
func write_character(c *Character) error

// Avoid
func SkipElement(d *xml.Decoder, start xml.StartElement) error
func writeCharacter(c *Character) error
Start function names with verbs for clarity.
Use snake_case for variables:
// Good
current_char := &Character{}
xml_depth := 0

// Avoid
currentChar := &Character{}
xmlDepth := 0
Short names are acceptable when context is clear (f for file, c for character).
Export struct types and fields:
type Character struct {
    ID             string
    Level          string
    Tokens         []xml.Token
    ProfBonus      int
    AbilityBonuses map[string]int
}

Error Handling

Always handle errors explicitly and provide context:
// Good: Wrap errors with context
f, err := os.Open(filename)
if err != nil {
    return fmt.Errorf("opening %s: %w", filename, err)
}
defer f.Close()

// Avoid: Generic error messages
f, err := os.Open(filename)
if err != nil {
    return err
}
Use fmt.Errorf with %w to wrap errors, preserving the error chain.

XML Handling Patterns

Follow these patterns when working with XML:
// Use xml.CopyToken to avoid buffer reuse issues
tok := xml.CopyToken(t)

switch token := tok.(type) {
case xml.StartElement:
    // Handle start element
case xml.EndElement:
    // Handle end element
case xml.CharData:
    // Handle character data
}

File I/O Patterns

// Always use defer for cleanup
f, err := os.Create(filename)
if err != nil {
    return err
}
defer f.Close()

// Check write errors
if _, err := f.WriteString("content"); err != nil {
    return err
}

Code Formatting

  • No gofmt required - Code uses tabs for indentation
  • 2-space indent within function bodies
  • No trailing whitespace
  • Single blank line between logical blocks
  • Maximum line length: 80-100 characters

Testing Requirements

All contributions must include appropriate tests:
1

Add test cases for new features

Use the golden file pattern for integration tests. See Testing for details.
2

Ensure existing tests pass

task test
All tests must pass before submitting a pull request.
3

Update golden files if needed

If your change intentionally modifies output format, update golden files:
go run main.go tests/db.xml
cp character_id-00001_4.xml tests/expected_character_id-00001_4.xml
task test

Git Workflow

Follow the Conventional Commits format for all commit messages:
<type>(<scope>): <description>

[optional body]

[optional footer]

Commit Types

feat(extraction): add support for item lists
feat(output): include character race and class
fix(parser): handle missing level field
fix(skills): correct proficiency bonus calculation
docs(readme): update installation instructions
docs(contributing): clarify testing requirements
refactor(main): extract XML encoding to separate function
refactor(parser): simplify depth tracking logic
test(extraction): add golden file for multi-character scenario
test(skills): validate ability score calculations
chore(deps): update go.mod to 1.25.7
chore(taskfile): add coverage report task

Example Commits

# Good commit messages
feat(main): add proficiency bonus to character skillset xml
fix(parser): resolve test failures on skill calculations
docs(readme): update deployment instructions
refactor(writer): extract skill total calculation logic

# Avoid
Update code
Fix bug
WIP

Pull Request Process

1

Ensure your branch is up to date

git checkout main
git pull origin main
git checkout feat/your-feature-name
git rebase main
2

Run tests and build

task test
task build-all
Fix any issues before submitting.
3

Push your branch

git push origin feat/your-feature-name
4

Create a pull request

  1. Go to the repository on GitHub
  2. Click New Pull Request
  3. Select your branch
  4. Fill in the PR template:
    • Description: What does this PR do?
    • Motivation: Why is this change needed?
    • Testing: How was this tested?
    • Breaking changes: Any backward incompatibilities?
5

Address review feedback

Respond to comments and push additional commits as needed:
git add .
git commit -m "fix(review): address PR feedback"
git push origin feat/your-feature-name

What to Contribute

Bug Fixes

Found a bug? Submit a fix with a test case that reproduces the issue

New Features

Propose new extraction features or output formats in an issue first

Documentation

Improve documentation, add examples, or clarify usage instructions

Tests

Add test cases for edge cases or untested scenarios

Code Review Guidelines

When reviewing code, we focus on:
  • Correctness: Does it solve the problem?
  • Testing: Are there appropriate tests?
  • Style: Does it follow project conventions?
  • Performance: Is it efficient for large XML files?
  • Maintainability: Is it clear and well-documented?

Questions and Support

Open a GitHub issue with the “question” label, or start a discussion.
Open a GitHub issue with:
  • Steps to reproduce
  • Expected vs actual behavior
  • Sample db.xml (if possible)
  • Go version and OS
Open a GitHub issue describing:
  • The use case
  • Proposed solution
  • Alternatives considered
  • Example usage

License

By contributing to FG Character Extractor, you agree that your contributions will be licensed under the MIT License. See the LICENSE file for details.

Recognition

All contributors will be recognized in the project’s README. Thank you for helping make FG Character Extractor better!
First time contributing to open source? Check out the First Timers Only guide.

Build docs developers (and LLMs) love