4 Commits

10 changed files with 208 additions and 79 deletions

View File

@ -2,7 +2,7 @@ name: autofix.ci
on: on:
pull_request: pull_request:
push: push:
branches: [ "master" ] branches: ["master"]
permissions: permissions:
contents: read contents: read
@ -11,13 +11,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: Install Task - name: Install Task
uses: go-task/setup-task@v1 uses: go-task/setup-task@v1
- uses: actions/setup-go@v6 - uses: actions/setup-go@v6
with: { go-version-file: 'go.mod' } with: { go-version-file: "go.mod" }
- name: Setup go deps - name: Setup go deps
run: | run: |
@ -34,7 +34,7 @@ jobs:
run: golangci-lint run --fix run: golangci-lint run --fix
- name: Run golangci-lint format - name: Run golangci-lint format
run: golangci-lint format run: golangci-lint fmt
- name: Run go mod tidy - name: Run go mod tidy
run: go mod tidy run: go mod tidy

View File

@ -2,7 +2,7 @@ name: CI
on: on:
push: push:
branches: ['master', 'develop'] branches: ["master", "develop"]
pull_request: pull_request:
env: env:
@ -21,12 +21,12 @@ jobs:
contents: read contents: read
pull-requests: read pull-requests: read
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions/setup-go@v6 - uses: actions/setup-go@v6
with: with:
go-version: stable go-version: stable
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v9
with: { version: latest } with: { version: latest }
test: test:
@ -38,14 +38,11 @@ jobs:
strategy: strategy:
matrix: matrix:
go: go:
- 1.21.x
- 1.22.x
- 1.23.x
- 1.24.x - 1.24.x
- 1.25.x - 1.25.x
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- name: Set up Go ${{ matrix.go }} - name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v6 uses: actions/setup-go@v6
@ -206,7 +203,7 @@ jobs:
- name: Upload test artifacts - name: Upload test artifacts
if: failure() if: failure()
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: test-results-go-${{ matrix.go }} name: test-results-go-${{ matrix.go }}
path: | path: |
@ -297,7 +294,7 @@ jobs:
contents: read contents: read
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
@ -342,10 +339,10 @@ jobs:
contents: read contents: read
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
steps: steps:
- name: 'Checkout Repository' - name: "Checkout Repository"
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: 'Dependency Review' - name: "Dependency Review"
uses: actions/dependency-review-action@v4 uses: actions/dependency-review-action@v4
with: with:
fail-on-severity: moderate fail-on-severity: moderate
@ -364,7 +361,7 @@ jobs:
startsWith(github.ref, 'refs/heads/feature/docker')) startsWith(github.ref, 'refs/heads/feature/docker'))
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v3

View File

@ -61,7 +61,7 @@ jobs:
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
# Add any setup steps before running the `github/codeql-action/init` action. # Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node` # This includes steps like installing compilers or runtimes (`actions/setup-node`

View File

@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: 'Dependency Review' - name: 'Dependency Review'
uses: actions/dependency-review-action@v4 uses: actions/dependency-review-action@v4

View File

@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v5 uses: actions/checkout@v6
with: with:
fetch-depth: 0 fetch-depth: 0
@ -88,7 +88,7 @@ jobs:
packages: write packages: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v3

158
AGENTS.md
View File

@ -1,56 +1,178 @@
# Agent Guidelines for articulate-parser # Agent Guidelines for articulate-parser
A Go CLI tool that parses Articulate Rise courses from URLs or local JSON files and exports them to Markdown, HTML, or DOCX formats.
## Build/Test Commands ## Build/Test Commands
- **Build**: `task build` or `go build -o bin/articulate-parser main.go`
- **Run tests**: `task test` or `go test -race -timeout 5m ./...` ### Primary Commands (using Taskfile)
- **Run single test**: `go test -v -race -run ^TestName$ ./path/to/package`
- **Test with coverage**: ```bash
- `task test:coverage` or task build # Build binary to bin/articulate-parser
- `go test -race -coverprofile=coverage/coverage.out -covermode=atomic ./...` task test # Run all tests with race detection
- **Lint**: `task lint` (runs vet, fmt check, staticcheck, golangci-lint) task lint # Run all linters (vet, fmt, staticcheck, golangci-lint)
- **Format**: `task fmt` or `gofmt -s -w .` task fmt # Format all Go files
- **CI checks**: `task ci` (deps, lint, test with coverage, build) task ci # Full CI pipeline: deps, lint, test with coverage, build
task qa # Quick QA: fmt + lint + test
```
### Direct Go Commands
```bash
# Build
go build -o bin/articulate-parser main.go
# Run all tests
go test -race -timeout 5m ./...
# Run single test by name
go test -v -race -run ^TestMarkdownExporter_Export$ ./internal/exporters
# Run tests in specific package
go test -v -race ./internal/services
# Run tests matching pattern
go test -v -race -run "TestParser" ./...
# Test with coverage
go test -race -coverprofile=coverage/coverage.out -covermode=atomic ./...
go tool cover -html=coverage/coverage.out -o coverage/coverage.html
# Benchmarks
go test -bench=. -benchmem ./...
go test -bench=BenchmarkMarkdownExporter ./internal/exporters
```
### Security & Auditing
```bash
task security:check # Run gosec security scanner
task security:audit # Run govulncheck for vulnerabilities
```
## Code Style Guidelines ## Code Style Guidelines
### Imports ### Imports
- Use `goimports` with local prefix: `github.com/kjanat/articulate-parser` - Use `goimports` with local prefix: `github.com/kjanat/articulate-parser`
- Order: stdlib, external, internal packages - Order: stdlib, blank line, external packages, blank line, internal packages
- Group related imports together
```go
import (
"context"
"fmt"
"github.com/fumiama/go-docx"
"github.com/kjanat/articulate-parser/internal/interfaces"
)
```
### Formatting ### Formatting
- Use `gofmt -s` (simplify) and `gofumpt` with extra rules - Use `gofmt -s` (simplify) and `gofumpt` with extra rules
- Function length: max 100 lines, 50 statements - Function length: max 100 lines, 50 statements
- Cyclomatic complexity: max 15 - Cyclomatic complexity: max 15; Cognitive complexity: max 20
- Cognitive complexity: max 20
### Types & Naming ### Types & Naming
- Use interface-based design (see `internal/interfaces/`) - Use interface-based design (see `internal/interfaces/`)
- Export types/functions with clear godoc comments ending with period - Exported types/functions require godoc comments ending with period
- Use descriptive names: `ArticulateParser`, `MarkdownExporter` - Use descriptive names: `ArticulateParser`, `MarkdownExporter`
- Receiver names: short (1-2 chars), consistent per type - Receiver names: short (1-2 chars), consistent per type
### Error Handling ### Error Handling
- Always wrap errors with context: `fmt.Errorf("operation failed: %w", err)` - Always wrap errors with context: `fmt.Errorf("operation failed: %w", err)`
- Use `%w` verb for error wrapping to preserve error chain - Use `%w` verb for error wrapping to preserve error chain
- Check all error returns (enforced by `errcheck`) - Check all error returns (enforced by `errcheck`)
- Document error handling rationale in defer blocks when ignoring close errors - Document error handling rationale in defer blocks when ignoring close errors
```go
// Good: Error wrapping with context
if err := json.Unmarshal(body, &course); err != nil {
return nil, fmt.Errorf("failed to unmarshal JSON: %w", err)
}
// Good: Documented defer with error handling
defer func() {
if err := resp.Body.Close(); err != nil {
p.Logger.Warn("failed to close response body", "error", err)
}
}()
```
### Comments ### Comments
- All exported types/functions require godoc comments - All exported types/functions require godoc comments
- End sentences with periods (`godot` linter enforced) - End sentences with periods (`godot` linter enforced)
- Mark known issues with TODO/FIXME/HACK/BUG/XXX - Mark known issues with TODO/FIXME/HACK/BUG/XXX
### Security ### Security
- Use `#nosec` with justification for deliberate security exceptions (G304 for CLI file paths, G306 for export file permissions)
- Run `gosec` and `govulncheck` for security audits - Use `#nosec` with justification for deliberate security exceptions
- G304: File paths from CLI args; G306: Export file permissions
```go
// #nosec G304 - File path provided by user via CLI argument
data, err := os.ReadFile(filePath)
```
### Testing ### Testing
- Enable race detection: `-race` flag
- Enable race detection: `-race` flag always
- Use table-driven tests where applicable - Use table-driven tests where applicable
- Mark test helpers with `t.Helper()` - Mark test helpers with `t.Helper()`
- Use `t.TempDir()` for temporary files
- Benchmarks in `*_bench_test.go`, examples in `*_example_test.go` - Benchmarks in `*_bench_test.go`, examples in `*_example_test.go`
- Test naming: `Test<Type>_<Method>` or `Test<Function>`
```go
func TestMarkdownExporter_ProcessItemToMarkdown_AllTypes(t *testing.T) {
tests := []struct {
name, itemType, expectedText string
}{
{"text item", "text", ""},
{"divider item", "divider", "---"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// test implementation
})
}
}
```
### Dependencies ### Dependencies
- Minimal external dependencies (currently: go-docx, golang.org/x/net, golang.org/x/text)
- Minimal external dependencies (go-docx, golang.org/x/net, golang.org/x/text)
- Run `task deps:tidy` after adding/removing dependencies - Run `task deps:tidy` after adding/removing dependencies
- CGO disabled by default (`CGO_ENABLED=0`)
## Project Structure
```
articulate-parser/
internal/
config/ # Configuration loading
exporters/ # Export implementations (markdown, html, docx)
interfaces/ # Core interfaces (Exporter, CourseParser, Logger)
models/ # Data models (Course, Lesson, Item, Media)
services/ # Core services (parser, html cleaner, app, logger)
version/ # Version information
main.go # Application entry point
```
## Common Patterns
### Creating a new exporter
1. Implement `interfaces.Exporter` interface
2. Add factory method to `internal/exporters/factory.go`
3. Register format in `NewFactory()`
4. Add tests following existing patterns
### Adding configuration options
1. Add field to `Config` struct in `internal/config/config.go`
2. Load from environment variable with sensible default
3. Document in config struct comments

View File

@ -1,7 +1,7 @@
# yaml-language-server: $schema=https://taskfile.dev/schema.json # yaml-language-server: $schema=https://taskfile.dev/schema.json
# Articulate Parser - Task Automation # Articulate Parser - Task Automation
# https://taskfile.dev # https://taskfile.dev
version: '3' version: "3"
# Global output settings # Global output settings
output: prefixed output: prefixed
@ -47,11 +47,11 @@ vars:
# Environment variables # Environment variables
env: env:
CGO_ENABLED: '{{.CGO_ENABLED}}' CGO_ENABLED: "{{.CGO_ENABLED}}"
GO111MODULE: on GO111MODULE: on
# Load .env files if present # Load .env files if present
dotenv: ['.env', '.env.local'] dotenv: [".env", ".env.local"]
# Task definitions # Task definitions
tasks: tasks:
@ -69,12 +69,12 @@ tasks:
interactive: true interactive: true
watch: true watch: true
sources: sources:
- '**/*.go' - "**/*.go"
- go.mod - go.mod
- go.sum - go.sum
cmds: cmds:
- task: build - task: build
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} --help' - "{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} --help"
# Build tasks # Build tasks
build: build:
@ -82,14 +82,14 @@ tasks:
aliases: [b] aliases: [b]
deps: [clean-bin] deps: [clean-bin]
sources: sources:
- '**/*.go' - "**/*.go"
- go.mod - go.mod
- go.sum - go.sum
generates: generates:
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}}' - "{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}}"
cmds: cmds:
- task: mkdir - task: mkdir
vars: { DIR: '{{.OUTPUT_DIR}}' } vars: { DIR: "{{.OUTPUT_DIR}}" }
- go build {{.GO_FLAGS}} -ldflags="{{.LDFLAGS}}" -o {{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} {{.MAIN_FILE}} - go build {{.GO_FLAGS}} -ldflags="{{.LDFLAGS}}" -o {{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} {{.MAIN_FILE}}
method: checksum method: checksum
@ -99,25 +99,25 @@ tasks:
deps: [clean-bin] deps: [clean-bin]
cmds: cmds:
- task: mkdir - task: mkdir
vars: { DIR: '{{.OUTPUT_DIR}}' } vars: { DIR: "{{.OUTPUT_DIR}}" }
- for: - for:
matrix: matrix:
GOOS: [linux, darwin, windows] GOOS: [linux, darwin, windows]
GOARCH: [amd64, arm64] GOARCH: [amd64, arm64]
task: build:platform task: build:platform
vars: vars:
TARGET_GOOS: '{{.ITEM.GOOS}}' TARGET_GOOS: "{{.ITEM.GOOS}}"
TARGET_GOARCH: '{{.ITEM.GOARCH}}' TARGET_GOARCH: "{{.ITEM.GOARCH}}"
- echo "Built binaries for all platforms in {{.OUTPUT_DIR}}/" - echo "Built binaries for all platforms in {{.OUTPUT_DIR}}/"
build:platform: build:platform:
internal: true internal: true
vars: vars:
TARGET_EXT: '{{if eq .TARGET_GOOS "windows"}}.exe{{end}}' TARGET_EXT: '{{if eq .TARGET_GOOS "windows"}}.exe{{end}}'
OUTPUT_FILE: '{{.OUTPUT_DIR}}/{{.APP_NAME}}-{{.TARGET_GOOS}}-{{.TARGET_GOARCH}}{{.TARGET_EXT}}' OUTPUT_FILE: "{{.OUTPUT_DIR}}/{{.APP_NAME}}-{{.TARGET_GOOS}}-{{.TARGET_GOARCH}}{{.TARGET_EXT}}"
env: env:
GOOS: '{{.TARGET_GOOS}}' GOOS: "{{.TARGET_GOOS}}"
GOARCH: '{{.TARGET_GOARCH}}' GOARCH: "{{.TARGET_GOARCH}}"
cmds: cmds:
- echo "Building {{.OUTPUT_FILE}}..." - echo "Building {{.OUTPUT_FILE}}..."
- go build {{.GO_FLAGS}} -ldflags="{{.LDFLAGS}}" -o "{{.OUTPUT_FILE}}" {{.MAIN_FILE}} - go build {{.GO_FLAGS}} -ldflags="{{.LDFLAGS}}" -o "{{.OUTPUT_FILE}}" {{.MAIN_FILE}}
@ -134,6 +134,8 @@ tasks:
test: test:
desc: Run all tests desc: Run all tests
aliases: [t] aliases: [t]
env:
CGO_ENABLED: 1
cmds: cmds:
- go test {{.GO_FLAGS}} -race -timeout {{.TEST_TIMEOUT}} ./... - go test {{.GO_FLAGS}} -race -timeout {{.TEST_TIMEOUT}} ./...
@ -141,9 +143,11 @@ tasks:
desc: Run tests with coverage report desc: Run tests with coverage report
aliases: [cover, cov] aliases: [cover, cov]
deps: [clean-coverage] deps: [clean-coverage]
env:
CGO_ENABLED: 1
cmds: cmds:
- task: mkdir - task: mkdir
vars: { DIR: '{{.COVERAGE_DIR}}' } vars: { DIR: "{{.COVERAGE_DIR}}" }
- go test {{.GO_FLAGS}} -race -coverprofile={{.COVERAGE_DIR}}/coverage.out -covermode=atomic -timeout {{.TEST_TIMEOUT}} ./... - go test {{.GO_FLAGS}} -race -coverprofile={{.COVERAGE_DIR}}/coverage.out -covermode=atomic -timeout {{.TEST_TIMEOUT}} ./...
- go tool cover -html={{.COVERAGE_DIR}}/coverage.out -o {{.COVERAGE_DIR}}/coverage.html - go tool cover -html={{.COVERAGE_DIR}}/coverage.out -o {{.COVERAGE_DIR}}/coverage.html
- go tool cover -func={{.COVERAGE_DIR}}/coverage.out - go tool cover -func={{.COVERAGE_DIR}}/coverage.out
@ -152,6 +156,8 @@ tasks:
test:verbose: test:verbose:
desc: Run tests with verbose output desc: Run tests with verbose output
aliases: [tv] aliases: [tv]
env:
CGO_ENABLED: 1
cmds: cmds:
- go test -v -race -timeout {{.TEST_TIMEOUT}} ./... - go test -v -race -timeout {{.TEST_TIMEOUT}} ./...
@ -160,7 +166,7 @@ tasks:
aliases: [tw] aliases: [tw]
watch: true watch: true
sources: sources:
- '**/*.go' - "**/*.go"
cmds: cmds:
- task: test - task: test
@ -172,6 +178,8 @@ tasks:
test:integration: test:integration:
desc: Run integration tests desc: Run integration tests
env:
CGO_ENABLED: 1
status: status:
- '{{if eq OS "windows"}}if not exist "main_test.go" exit 1{{else}}test ! -f "main_test.go"{{end}}' - '{{if eq OS "windows"}}if not exist "main_test.go" exit 1{{else}}test ! -f "main_test.go"{{end}}'
cmds: cmds:
@ -352,14 +360,14 @@ tasks:
internal: true internal: true
cmds: cmds:
- task: rmdir - task: rmdir
vars: { DIR: '{{.OUTPUT_DIR}}' } vars: { DIR: "{{.OUTPUT_DIR}}" }
clean-coverage: clean-coverage:
desc: Remove coverage files desc: Remove coverage files
internal: true internal: true
cmds: cmds:
- task: rmdir - task: rmdir
vars: { DIR: '{{.COVERAGE_DIR}}' } vars: { DIR: "{{.COVERAGE_DIR}}" }
clean-cache: clean-cache:
desc: Clean Go build and test cache desc: Clean Go build and test cache
@ -410,10 +418,10 @@ tasks:
requires: requires:
vars: [VERSION] vars: [VERSION]
preconditions: preconditions:
- sh: 'git diff --exit-code' - sh: "git diff --exit-code"
msg: 'Working directory is not clean' msg: "Working directory is not clean"
- sh: 'git diff --cached --exit-code' - sh: "git diff --cached --exit-code"
msg: 'Staging area is not clean' msg: "Staging area is not clean"
cmds: cmds:
- git tag -a v{{.VERSION}} -m "Release v{{.VERSION}}" - git tag -a v{{.VERSION}} -m "Release v{{.VERSION}}"
- echo "Tagged v{{.VERSION}}" - echo "Tagged v{{.VERSION}}"
@ -498,11 +506,11 @@ tasks:
- '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}' - '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}'
deps: [build] deps: [build]
cmds: cmds:
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json md output-demo.md' - "{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json md output-demo.md"
- echo "Demo Markdown created{{:}} output-demo.md" - echo "Demo Markdown created{{:}} output-demo.md"
- defer: - defer:
task: rmfile task: rmfile
vars: { FILE: 'output-demo.md' } vars: { FILE: "output-demo.md" }
demo:html: demo:html:
desc: Demo - Convert sample to HTML desc: Demo - Convert sample to HTML
@ -510,11 +518,11 @@ tasks:
- '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}' - '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}'
deps: [build] deps: [build]
cmds: cmds:
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json html output-demo.html' - "{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json html output-demo.html"
- echo "Demo HTML created{{:}} output-demo.html" - echo "Demo HTML created{{:}} output-demo.html"
- defer: - defer:
task: rmfile task: rmfile
vars: { FILE: 'output-demo.html' } vars: { FILE: "output-demo.html" }
demo:docx: demo:docx:
desc: Demo - Convert sample to DOCX desc: Demo - Convert sample to DOCX
@ -522,11 +530,11 @@ tasks:
- '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}' - '{{if eq OS "windows"}}if not exist "articulate-sample.json" exit 1{{else}}test ! -f "articulate-sample.json"{{end}}'
deps: [build] deps: [build]
cmds: cmds:
- '{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json docx output-demo.docx' - "{{.OUTPUT_DIR}}/{{.APP_NAME}}{{.EXE_EXT}} articulate-sample.json docx output-demo.docx"
- echo "Demo DOCX created{{:}} output-demo.docx" - echo "Demo DOCX created{{:}} output-demo.docx"
- defer: - defer:
task: rmfile task: rmfile
vars: { FILE: 'output-demo.docx' } vars: { FILE: "output-demo.docx" }
# Performance profiling # Performance profiling
profile:cpu: profile:cpu:
@ -536,7 +544,7 @@ tasks:
- go tool pprof -http=:8080 cpu.prof - go tool pprof -http=:8080 cpu.prof
- defer: - defer:
task: rmfile task: rmfile
vars: { FILE: 'cpu.prof' } vars: { FILE: "cpu.prof" }
profile:mem: profile:mem:
desc: Run memory profiling desc: Run memory profiling
@ -545,14 +553,14 @@ tasks:
- go tool pprof -http=:8080 mem.prof - go tool pprof -http=:8080 mem.prof
- defer: - defer:
task: rmfile task: rmfile
vars: { FILE: 'mem.prof' } vars: { FILE: "mem.prof" }
# Git hooks # Git hooks
hooks:install: hooks:install:
desc: Install git hooks desc: Install git hooks
cmds: cmds:
- task: mkdir - task: mkdir
vars: { DIR: '.git/hooks' } vars: { DIR: ".git/hooks" }
- '{{if eq OS "windows"}}echo "#!/bin/sh" > .git/hooks/pre-commit && echo "task lint:fmt" >> .git/hooks/pre-commit{{else}}cat > .git/hooks/pre-commit << ''EOF''{{printf "\n"}}#!/bin/sh{{printf "\n"}}task lint:fmt{{printf "\n"}}EOF{{printf "\n"}}chmod +x .git/hooks/pre-commit{{end}}' - '{{if eq OS "windows"}}echo "#!/bin/sh" > .git/hooks/pre-commit && echo "task lint:fmt" >> .git/hooks/pre-commit{{else}}cat > .git/hooks/pre-commit << ''EOF''{{printf "\n"}}#!/bin/sh{{printf "\n"}}task lint:fmt{{printf "\n"}}EOF{{printf "\n"}}chmod +x .git/hooks/pre-commit{{end}}'
- echo "Git hooks installed" - echo "Git hooks installed"

8
go.mod
View File

@ -2,13 +2,15 @@ module github.com/kjanat/articulate-parser
go 1.24.0 go 1.24.0
toolchain go1.25.5
require ( require (
github.com/fumiama/go-docx v0.0.0-20250506085032-0c30fd09304b github.com/fumiama/go-docx v0.0.0-20250506085032-0c30fd09304b
golang.org/x/net v0.46.0 golang.org/x/net v0.48.0
golang.org/x/text v0.30.0 golang.org/x/text v0.32.0
) )
require ( require (
github.com/fumiama/imgsz v0.0.4 // indirect github.com/fumiama/imgsz v0.0.4 // indirect
golang.org/x/image v0.32.0 // indirect golang.org/x/image v0.34.0 // indirect
) )

12
go.sum
View File

@ -2,9 +2,9 @@ github.com/fumiama/go-docx v0.0.0-20250506085032-0c30fd09304b h1:/mxSugRc4SgN7Xg
github.com/fumiama/go-docx v0.0.0-20250506085032-0c30fd09304b/go.mod h1:ssRF0IaB1hCcKIObp3FkZOsjTcAHpgii70JelNb4H8M= github.com/fumiama/go-docx v0.0.0-20250506085032-0c30fd09304b/go.mod h1:ssRF0IaB1hCcKIObp3FkZOsjTcAHpgii70JelNb4H8M=
github.com/fumiama/imgsz v0.0.4 h1:Lsasu2hdSSFS+vnD+nvR1UkiRMK7hcpyYCC0FzgSMFI= github.com/fumiama/imgsz v0.0.4 h1:Lsasu2hdSSFS+vnD+nvR1UkiRMK7hcpyYCC0FzgSMFI=
github.com/fumiama/imgsz v0.0.4/go.mod h1:bISOQVTlw9sRytPwe8ir7tAaEmyz9hSNj9n8mXMBG0E= github.com/fumiama/imgsz v0.0.4/go.mod h1:bISOQVTlw9sRytPwe8ir7tAaEmyz9hSNj9n8mXMBG0E=
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ= golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc= golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=

Binary file not shown.