diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 52f5664..48ee87e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,5 @@ # These owners will be the default owners for everything in -# the repo. Unless a later match takes precedence, they will +# the repo. Unless a later match takes precedence, they will # be requested for review when someone opens a pull request. * @kjanat diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index ccb9e57..5ce0145 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -17,23 +17,23 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -- Demonstrating empathy and kindness toward other people -- Being respectful of differing opinions, viewpoints, and experiences -- Giving and gracefully accepting constructive feedback -- Accepting responsibility and apologizing to those affected by our mistakes, +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -- Focusing on what is best not just for us as individuals, but for the +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -- The use of sexualized language or imagery, and sexual attention or +- The use of sexualized language or imagery, and sexual attention or advances of any kind -- Trolling, insulting or derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or email +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission -- Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3b4e6ae..e336ff2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -12,38 +12,38 @@ This project and everyone participating in it is governed by our Code of Conduct Before creating bug reports, please check existing issues as you might find that the issue has already been reported. When creating a bug report, include as many details as possible: -- Use the bug report template -- Include sample Articulate Rise content that reproduces the issue -- Provide your environment details (OS, Go version, etc.) -- Include error messages and stack traces +- Use the bug report template +- Include sample Articulate Rise content that reproduces the issue +- Provide your environment details (OS, Go version, etc.) +- Include error messages and stack traces ### Suggesting Enhancements Enhancement suggestions are welcome! Please use the feature request template and include: -- A clear description of the enhancement -- Your use case and why this would be valuable -- Any implementation ideas you might have +- A clear description of the enhancement +- Your use case and why this would be valuable +- Any implementation ideas you might have ### Pull Requests -1. **Fork the repository** and create your branch from `master` -2. **Make your changes** following our coding standards -3. **Add tests** for any new functionality -4. **Ensure all tests pass** by running `go test ./...` -5. **Run `go fmt`** to format your code -6. **Run `go vet`** to check for common issues -7. **Update documentation** if needed -8. **Create a pull request** with a clear title and description +1. **Fork the repository** and create your branch from `master` +2. **Make your changes** following our coding standards +3. **Add tests** for any new functionality +4. **Ensure all tests pass** by running `go test ./...` +5. **Run `go fmt`** to format your code +6. **Run `go vet`** to check for common issues +7. **Update documentation** if needed +8. **Create a pull request** with a clear title and description ## Development Setup -1. **Prerequisites:** +1. **Prerequisites:** -- Go 1.21 or later -- Git +- Go 1.21 or later +- Git -2. **Clone and setup:** +2. **Clone and setup:** ```bash git clone https://github.com/your-username/articulate-parser.git @@ -51,13 +51,13 @@ Enhancement suggestions are welcome! Please use the feature request template and go mod download ``` -3. **Run tests:** +3. **Run tests:** ```bash go test -v ./... ``` -4. **Build:** +4. **Build:** ```bash go build main.go @@ -67,18 +67,18 @@ Enhancement suggestions are welcome! Please use the feature request template and ### Go Style Guide -- Follow the [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) -- Use `gofmt` to format your code -- Use meaningful variable and function names -- Add comments for exported functions and types -- Keep functions focused and small +- Follow the [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) +- Use `gofmt` to format your code +- Use meaningful variable and function names +- Add comments for exported functions and types +- Keep functions focused and small ### Testing -- Write tests for new functionality -- Use table-driven tests where appropriate -- Aim for good test coverage -- Test error cases and edge conditions +- Write tests for new functionality +- Use table-driven tests where appropriate +- Aim for good test coverage +- Test error cases and edge conditions ### Commit Messages @@ -112,19 +112,19 @@ articulate-parser/ ### New Content Types -1. Add the content type definition to `types/` -2. Implement parsing logic in `parser/` -3. Add export handling in `exporters/` -4. Write comprehensive tests -5. Update documentation +1. Add the content type definition to `types/` +2. Implement parsing logic in `parser/` +3. Add export handling in `exporters/` +4. Write comprehensive tests +5. Update documentation ### New Export Formats -1. Create a new exporter in `exporters/` -2. Implement the `Exporter` interface -3. Add CLI support in `main.go` -4. Add tests with sample output -5. Update README with usage examples +1. Create a new exporter in `exporters/` +2. Implement the `Exporter` interface +3. Add CLI support in `main.go` +4. Add tests with sample output +5. Update README with usage examples ## Testing @@ -146,31 +146,31 @@ go test -run TestSpecificFunction ./... ### Test Data -- Add sample Articulate Rise JSON files to `tests/data/` -- Include both simple and complex content examples -- Test edge cases and error conditions +- Add sample Articulate Rise JSON files to `tests/data/` +- Include both simple and complex content examples +- Test edge cases and error conditions ## Documentation -- Update the README for user-facing changes -- Add inline code comments for complex logic -- Update examples when adding new features -- Keep the feature list current +- Update the README for user-facing changes +- Add inline code comments for complex logic +- Update examples when adding new features +- Keep the feature list current ## Release Process Releases are handled by maintainers: -1. Version bumping follows semantic versioning -2. Releases are created from the `master` branch -3. GitHub Actions automatically builds and publishes releases -4. Release notes are auto-generated from commits +1. Version bumping follows semantic versioning +2. Releases are created from the `master` branch +3. GitHub Actions automatically builds and publishes releases +4. Release notes are auto-generated from commits ## Questions? -- Open a discussion for general questions -- Use the question issue template for specific help -- Check existing issues and documentation first +- Open a discussion for general questions +- Use the question issue template for specific help +- Check existing issues and documentation first ## Recognition diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b6da683..3232a52 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,26 +10,26 @@ Fixes # ## Type of Change -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Documentation update -- [ ] Performance improvement -- [ ] Code refactoring (no functional changes) -- [ ] Test updates +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update +- [ ] Performance improvement +- [ ] Code refactoring (no functional changes) +- [ ] Test updates ## Checklist -- [ ] My code follows the style guidelines of this project -- [ ] I have performed a self-review of my code -- [ ] I have added comments to complex logic -- [ ] I have updated the documentation -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] New and existing unit tests pass locally with my changes -- [ ] I have checked for potential breaking changes -- [ ] No new warnings are generated -- [ ] The commit message follows our guidelines +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my code +- [ ] I have added comments to complex logic +- [ ] I have updated the documentation +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] I have checked for potential breaking changes +- [ ] No new warnings are generated +- [ ] The commit message follows our guidelines ## Screenshots (if appropriate) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 5b7d306..50d2e83 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -13,32 +13,32 @@ Currently, the following versions of Articulate Rise Parser are supported with s We take the security of Articulate Rise Parser seriously. If you believe you have found a security vulnerability, please follow these steps: -1. **Do not disclose the vulnerability publicly** - Please do not create a public GitHub issue for security vulnerabilities. -2. **Email the details to [security+articulate-parser@kjanat.com]** - Include as much information as possible about the vulnerability. -3. **Wait for a response** - We will acknowledge your email within 48 hours and provide an estimated timeline for a fix. -4. **Work with us** - We may ask for additional information to help us understand and address the issue. +1. **Do not disclose the vulnerability publicly** - Please do not create a public GitHub issue for security vulnerabilities. +2. **Email the details to [security+articulate-parser@kjanat.com]** - Include as much information as possible about the vulnerability. +3. **Wait for a response** - We will acknowledge your email within 48 hours and provide an estimated timeline for a fix. +4. **Work with us** - We may ask for additional information to help us understand and address the issue. ## What to Include in a Report When reporting a vulnerability, please include: -- A clear description of the issue -- Steps to reproduce the vulnerability -- The potential impact of the vulnerability -- Any possible mitigations you've identified +- A clear description of the issue +- Steps to reproduce the vulnerability +- The potential impact of the vulnerability +- Any possible mitigations you've identified ## What to Expect -- We will acknowledge receipt of your vulnerability report within 48 hours. -- We will provide regular updates about our progress. -- We will notify you when the vulnerability is fixed. -- With your permission, we will include your name in the acknowledgments. +- We will acknowledge receipt of your vulnerability report within 48 hours. +- We will provide regular updates about our progress. +- We will notify you when the vulnerability is fixed. +- With your permission, we will include your name in the acknowledgments. ## Security Measures This project follows these security practices: -- Regular dependency updates via Dependabot -- CodeQL security scanning -- Automated testing for each pull request -- Code review requirements for all changes +- Regular dependency updates via Dependabot +- CodeQL security scanning +- Automated testing for each pull request +- Code review requirements for all changes diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index 3e5eed3..dfbf422 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -22,7 +22,7 @@ jobs: - name: Setup go deps run: | # Install golangci-lint - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b "$(go env GOPATH)/bin" # Install go-task dependencies go install golang.org/x/tools/cmd/goimports@latest @@ -34,7 +34,7 @@ jobs: run: golangci-lint run --fix - name: Run golangci-lint format - run: golangci-lint format + run: golangci-lint fmt - name: Run go mod tidy run: go mod tidy diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 01787a7..1c43bc6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,9 +38,6 @@ jobs: strategy: matrix: go: - - 1.21.x - - 1.22.x - - 1.23.x - 1.24.x - 1.25.x @@ -67,14 +64,18 @@ jobs: - name: Run tests with enhanced reporting id: test + env: + CGO_ENABLED: 1 run: | - cat >> $GITHUB_STEP_SUMMARY << EOF + { + cat << EOF ## ๐Ÿ”ง Test Environment - **Go Version:** ${{ matrix.go }} - **OS:** ubuntu-latest - **Timestamp:** $(date -u) EOF + } >> "$GITHUB_STEP_SUMMARY" echo "Running tests with coverage..." task test:coverage 2>&1 | tee test-output.log @@ -82,21 +83,22 @@ jobs: # Extract test results for summary TEST_STATUS=$? TOTAL_TESTS=$(grep -c "=== RUN" test-output.log || echo "0") - PASSED_TESTS=$(grep -c "--- PASS:" test-output.log || echo "0") - FAILED_TESTS=$(grep -c "--- FAIL:" test-output.log || echo "0") - SKIPPED_TESTS=$(grep -c "--- SKIP:" test-output.log || echo "0") + PASSED_TESTS=$(grep -c -- "--- PASS:" test-output.log || echo "0") + FAILED_TESTS=$(grep -c -- "--- FAIL:" test-output.log || echo "0") + SKIPPED_TESTS=$(grep -c -- "--- SKIP:" test-output.log || echo "0") # Generate test summary - cat >> $GITHUB_STEP_SUMMARY << EOF + { + cat << EOF ## ๐Ÿงช Test Results (Go ${{ matrix.go }}) - | Metric | Value | - | ----------- | ----------------------------------------------------------- | - | Total Tests | $TOTAL_TESTS | - | Passed | $PASSED_TESTS | - | Failed | $FAILED_TESTS | - | Skipped | $SKIPPED_TESTS | - | Status | $([ $TEST_STATUS -eq 0 ] && echo "PASSED" || echo "FAILED") | + | Metric | Value | + | ----------- | ------------------------------------------------------------- | + | Total Tests | $TOTAL_TESTS | + | Passed | $PASSED_TESTS | + | Failed | $FAILED_TESTS | + | Skipped | $SKIPPED_TESTS | + | Status | $([ "$TEST_STATUS" -eq 0 ] && echo "PASSED" || echo "FAILED") | ### ๐Ÿ“ฆ Package Test Results @@ -108,38 +110,39 @@ jobs: grep "^ok\|^FAIL" test-output.log | while read -r line; do if [[ $line == ok* ]]; then pkg=$(echo "$line" | awk '{print $2}') - echo "| $pkg | โœ… PASS |" >> $GITHUB_STEP_SUMMARY + echo "| $pkg | โœ… PASS |" elif [[ $line == FAIL* ]]; then pkg=$(echo "$line" | awk '{print $2}') - echo "| $pkg | โŒ FAIL |" >> $GITHUB_STEP_SUMMARY + echo "| $pkg | โŒ FAIL |" fi done - echo "" >> $GITHUB_STEP_SUMMARY + echo "" # Add detailed results if tests failed - if [ $TEST_STATUS -ne 0 ]; then - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + if [ "$TEST_STATUS" -ne 0 ]; then + cat << 'EOF' ### โŒ Failed Tests Details ``` EOF - grep -A 10 "--- FAIL:" test-output.log | head -100 >> $GITHUB_STEP_SUMMARY - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + grep -A 10 -- "--- FAIL:" test-output.log | head -100 + cat << 'EOF' ``` EOF fi + } >> "$GITHUB_STEP_SUMMARY" # Set outputs for other steps - cat >> $GITHUB_OUTPUT << EOF - test-status=$TEST_STATUS - total-tests=$TOTAL_TESTS - passed-tests=$PASSED_TESTS - failed-tests=$FAILED_TESTS - EOF + { + echo "test-status=$TEST_STATUS" + echo "total-tests=$TOTAL_TESTS" + echo "passed-tests=$PASSED_TESTS" + echo "failed-tests=$FAILED_TESTS" + } >> "$GITHUB_OUTPUT" # Exit with the original test status - exit $TEST_STATUS + exit "$TEST_STATUS" - name: Generate coverage report if: always() @@ -147,7 +150,8 @@ jobs: if [ -f coverage/coverage.out ]; then COVERAGE=$(go tool cover -func=coverage/coverage.out | grep total | awk '{print $3}') - cat >> $GITHUB_STEP_SUMMARY << EOF + { + cat << EOF ## ๐Ÿ“Š Code Coverage (Go ${{ matrix.go }}) **Total Coverage: $COVERAGE** @@ -159,45 +163,46 @@ jobs: | ------- | -------- | EOF - # Create temporary file for package coverage aggregation - temp_coverage=$(mktemp) - - # Extract package-level coverage data - go tool cover -func=coverage/coverage.out | grep -v total | while read -r line; do - if [[ $line == *".go:"* ]]; then - # Extract package path from file path (everything before the filename) - filepath=$(echo "$line" | awk '{print $1}') - pkg_path=$(dirname "$filepath" | sed 's|github.com/kjanat/articulate-parser/||; s|^\./||') - coverage=$(echo "$line" | awk '{print $3}' | sed 's/%//') - - # Use root package if no subdirectory - [[ "$pkg_path" == "." || "$pkg_path" == "" ]] && pkg_path="root" - - echo "$pkg_path $coverage" >> "$temp_coverage" - fi - done - - # Aggregate coverage by package (average) - awk '{ - packages[$1] += $2 - counts[$1]++ - } - END { - for (pkg in packages) { - avg = packages[pkg] / counts[pkg] - printf "| %s | %.1f%% |\n", pkg, avg + # Create temporary file for package coverage aggregation + temp_coverage=$(mktemp) + + # Extract package-level coverage data + go tool cover -func=coverage/coverage.out | grep -v total | while read -r line; do + if [[ $line == *".go:"* ]]; then + # Extract package path from file path (everything before the filename) + filepath=$(echo "$line" | awk '{print $1}') + pkg_path=$(dirname "$filepath" | sed 's|github.com/kjanat/articulate-parser/||; s|^\./||') + coverage=$(echo "$line" | awk '{print $3}' | sed 's/%//') + + # Use root package if no subdirectory + [[ "$pkg_path" == "." || "$pkg_path" == "" ]] && pkg_path="root" + + echo "$pkg_path $coverage" >> "$temp_coverage" + fi + done + + # Aggregate coverage by package (average) + awk '{ + packages[$1] += $2 + counts[$1]++ } - }' "$temp_coverage" | sort >> $GITHUB_STEP_SUMMARY + END { + for (pkg in packages) { + avg = packages[pkg] / counts[pkg] + printf "| %s | %.1f%% |\n", pkg, avg + } + }' "$temp_coverage" | sort - rm -f "$temp_coverage" + rm -f "$temp_coverage" - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + cat << 'EOF' EOF + } >> "$GITHUB_STEP_SUMMARY" else - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + cat >> "$GITHUB_STEP_SUMMARY" << 'EOF' ## โš ๏ธ Coverage Report No coverage file generated @@ -217,51 +222,53 @@ jobs: - name: Run linters run: | # Initialize summary - cat >> $GITHUB_STEP_SUMMARY << EOF + { + cat << EOF ## ๐Ÿ” Static Analysis (Go ${{ matrix.go }}) EOF - # Run go vet - VET_OUTPUT=$(task lint:vet 2>&1 || echo "") - VET_STATUS=$? + # Run go vet + VET_OUTPUT=$(task lint:vet 2>&1 || echo "") + VET_STATUS=$? - if [ $VET_STATUS -eq 0 ]; then - echo "โœ… **go vet:** No issues found" >> $GITHUB_STEP_SUMMARY - else - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + if [ "$VET_STATUS" -eq 0 ]; then + echo "โœ… **go vet:** No issues found" + else + cat << 'EOF' โŒ **go vet:** Issues found ``` EOF - echo "$VET_OUTPUT" >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - fi - echo "" >> $GITHUB_STEP_SUMMARY + echo "$VET_OUTPUT" + echo '```' + fi + echo "" - # Run go fmt check - FMT_OUTPUT=$(task lint:fmt 2>&1 || echo "") - FMT_STATUS=$? + # Run go fmt check + FMT_OUTPUT=$(task lint:fmt 2>&1 || echo "") + FMT_STATUS=$? - if [ $FMT_STATUS -eq 0 ]; then - echo "โœ… **go fmt:** All files properly formatted" >> $GITHUB_STEP_SUMMARY - else - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + if [ "$FMT_STATUS" -eq 0 ]; then + echo "โœ… **go fmt:** All files properly formatted" + else + cat << 'EOF' โŒ **go fmt:** Files need formatting ``` EOF - echo "$FMT_OUTPUT" >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - fi + echo "$FMT_OUTPUT" + echo '```' + fi + } >> "$GITHUB_STEP_SUMMARY" # Exit with error if any linter failed - [ $VET_STATUS -eq 0 ] && [ $FMT_STATUS -eq 0 ] || exit 1 + [ "$VET_STATUS" -eq 0 ] && [ "$FMT_STATUS" -eq 0 ] || exit 1 - name: Job Summary if: always() run: | - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + cat >> "$GITHUB_STEP_SUMMARY" << 'EOF' ## ๐Ÿ“‹ Job Summary (Go ${{ matrix.go }}) | Step | Status | @@ -316,24 +323,26 @@ jobs: - name: Test Docker image using Task run: | - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + { + cat << 'EOF' ## ๐Ÿงช Docker Image Tests EOF - # Run Task docker test - task docker:test + # Run Task docker test + task docker:test - echo "**Testing help command:**" >> $GITHUB_STEP_SUMMARY - echo '```terminaloutput' >> $GITHUB_STEP_SUMMARY - docker run --rm articulate-parser:latest --help >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + echo "**Testing help command:**" + echo '```terminaloutput' + docker run --rm articulate-parser:latest --help + echo '```' + echo "" - # Test image size - IMAGE_SIZE=$(docker image inspect articulate-parser:latest --format='{{.Size}}' | numfmt --to=iec-i --suffix=B) - echo "**Image size:** $IMAGE_SIZE" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + # Test image size + IMAGE_SIZE=$(docker image inspect articulate-parser:latest --format='{{.Size}}' | numfmt --to=iec-i --suffix=B) + echo "**Image size:** $IMAGE_SIZE" + echo "" + } >> "$GITHUB_STEP_SUMMARY" dependency-review: name: Dependency Review @@ -357,7 +366,7 @@ jobs: permissions: contents: read packages: write - needs: [test, docker-test, dependency-review] + needs: [test] if: | github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || @@ -436,7 +445,7 @@ jobs: - name: Generate Docker summary run: | - cat >> $GITHUB_STEP_SUMMARY << 'EOF' + cat >> "$GITHUB_STEP_SUMMARY" << 'EOF' ## ๐Ÿณ Docker Build Summary **Image:** `ghcr.io/${{ github.repository }}` diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6299e32..10c8e95 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,104 +1,104 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -# This workflow is configured to be called by other workflows for more controlled execution -# This allows integration with the main CI pipeline and avoids redundant runs -# To enable automatic execution, uncomment the triggers below: -on: - workflow_call: - schedule: - - cron: '44 16 * * 6' - # push: - # branches: [ "master" ] - # pull_request: - # branches: [ "master" ] - -jobs: - analyze: - name: Analyze (${{ matrix.language }}) - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners (GitHub.com only) - # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} - permissions: - # required for all workflows - security-events: write - - # required to fetch internal or private CodeQL packs - packages: read - - # only required for workflows in private repositories - actions: read - contents: read - - strategy: - fail-fast: false - matrix: - include: - - language: actions - build-mode: none - - language: go - build-mode: autobuild - # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' - # Use `c-cpp` to analyze code written in C, C++ or both - # Use 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, - # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. - # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how - # 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: - - name: Checkout repository - uses: actions/checkout@v5 - - # Add any setup steps before running the `github/codeql-action/init` action. - # This includes steps like installing compilers or runtimes (`actions/setup-node` - # or others). This is typically only required for manual builds. - # - name: Setup runtime (example) - # uses: actions/setup-example@v1 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # โ„น๏ธ Command-line programs to run using the OS shell. - # ๐Ÿ“š See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - if: matrix.build-mode == 'manual' - shell: bash - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:${{matrix.language}}" +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +# This workflow is configured to be called by other workflows for more controlled execution +# This allows integration with the main CI pipeline and avoids redundant runs +# To enable automatic execution, uncomment the triggers below: +on: + workflow_call: + schedule: + - cron: '44 16 * * 6' + # push: + # branches: [ "master" ] + # pull_request: + # branches: [ "master" ] + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: go + build-mode: autobuild + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # 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: + - name: Checkout repository + uses: actions/checkout@v5 + + # Add any setup steps before running the `github/codeql-action/init` action. + # This includes steps like installing compilers or runtimes (`actions/setup-node` + # or others). This is typically only required for manual builds. + # - name: Setup runtime (example) + # uses: actions/setup-example@v1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # โ„น๏ธ Command-line programs to run using the OS shell. + # ๐Ÿ“š See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" diff --git a/.gitignore b/.gitignore index 0627806..fd64c00 100644 --- a/.gitignore +++ b/.gitignore @@ -1,79 +1,79 @@ -# Created by https://www.toptal.com/developers/gitignore/api/go -# Edit at https://www.toptal.com/developers/gitignore?templates=go - -### Go ### -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file -go.work - -# End of https://www.toptal.com/developers/gitignore/api/go - -# Shit -.github/TODO - -# Local test files -output/ -outputs/ -articulate-sample.json -test-output.* -go-os-arch-matrix.csv -test_godocx.go -test_input.json - -# Build artifacts -build/ - -# Old workflows -.github/workflows/ci-old.yml -.github/workflows/ci-enhanced.yml - -# Test coverage files -coverage.out -coverage.txt -coverage.html -coverage.* -coverage -*.cover -*.coverprofile -main_coverage - -# Other common exclusions -*.exe -*.exe~ -*.dll -*.so -*.dylib -*.test -*.out -/tmp/ -.github/copilot-instructions.md - -# Editors -.vscode/ -.idea/ - -.task/ - -**/*.local.* - -.claude/ - -NUL +# Created by https://www.toptal.com/developers/gitignore/api/go +# Edit at https://www.toptal.com/developers/gitignore?templates=go + +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# End of https://www.toptal.com/developers/gitignore/api/go + +# Shit +.github/TODO + +# Local test files +output/ +outputs/ +articulate-sample.json +test-output.* +go-os-arch-matrix.csv +test_godocx.go +test_input.json + +# Build artifacts +build/ + +# Old workflows +.github/workflows/ci-old.yml +.github/workflows/ci-enhanced.yml + +# Test coverage files +coverage.out +coverage.txt +coverage.html +coverage.* +coverage +*.cover +*.coverprofile +main_coverage + +# Other common exclusions +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.test +*.out +/tmp/ +.github/copilot-instructions.md + +# Editors +.vscode/ +.idea/ + +.task/ + +**/*.local.* + +.claude/ + +NUL diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9c7ef4e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,75 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + # File quality + - id: trailing-whitespace + exclude: '^\.github/ISSUE_TEMPLATE/.*\.yml$' + - id: end-of-file-fixer + - id: mixed-line-ending + args: ['--fix=lf'] + + # File validation + - id: check-yaml + - id: check-json + - id: check-toml + + # Security + - id: detect-private-key + + # Git safety + - id: check-merge-conflict + - id: check-case-conflict + - id: no-commit-to-branch + args: ['--branch=master', '--branch=main'] + + # File structure + - id: check-added-large-files + - id: check-symlinks + - id: check-executables-have-shebangs + - repo: local + hooks: + - id: actionlint + name: Lint GitHub Actions workflow files + description: Runs actionlint to lint GitHub Actions workflow files + language: golang + types: ["yaml"] + files: ^\.github/workflows/ + entry: actionlint + minimum_pre_commit_version: 3.0.0 + - repo: https://github.com/golangci/golangci-lint + rev: v2.6.1 + hooks: + - id: golangci-lint + name: golangci-lint + description: Fast linters runner for Go. Note that only modified files are linted, so linters like 'unused' that need to scan all files won't work as expected. + entry: golangci-lint run --new-from-rev HEAD --fix + types: [go] + language: golang + require_serial: true + pass_filenames: false + # - id: golangci-lint-full + # name: golangci-lint-full + # description: Fast linters runner for Go. Runs on all files in the module. Use this hook if you use pre-commit in CI. + # entry: golangci-lint run --fix + # types: [go] + # language: golang + # require_serial: true + # pass_filenames: false + - id: golangci-lint-fmt + name: golangci-lint-fmt + description: Fast linters runner for Go. Formats all files in the repo. + entry: golangci-lint fmt + types: [go] + language: golang + require_serial: true + pass_filenames: false + - id: golangci-lint-config-verify + name: golangci-lint-config-verify + description: Verifies the configuration file + entry: golangci-lint config verify + files: '\.golangci\.(?:yml|yaml|toml|json)' + language: golang + pass_filenames: false diff --git a/AGENTS.md b/AGENTS.md index 4f5eb1b..02941c0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,11 +1,12 @@ # Agent Guidelines for articulate-parser ## 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 ./...` - **Run single test**: `go test -v -race -run ^TestName$ ./path/to/package` -- **Test with coverage**: - - `task test:coverage` or +- **Test with coverage**: + - `task test:coverage` or - `go test -race -coverprofile=coverage/coverage.out -covermode=atomic ./...` - **Lint**: `task lint` (runs vet, fmt check, staticcheck, golangci-lint) - **Format**: `task fmt` or `gofmt -s -w .` @@ -14,43 +15,413 @@ ## Code Style Guidelines ### Imports + - Use `goimports` with local prefix: `github.com/kjanat/articulate-parser` - Order: stdlib, external, internal packages - Group related imports together ### Formatting + - Use `gofmt -s` (simplify) and `gofumpt` with extra rules - Function length: max 100 lines, 50 statements - Cyclomatic complexity: max 15 - Cognitive complexity: max 20 ### Types & Naming + - Use interface-based design (see `internal/interfaces/`) - Export types/functions with clear godoc comments ending with period - Use descriptive names: `ArticulateParser`, `MarkdownExporter` - Receiver names: short (1-2 chars), consistent per type ### Error Handling + - Always wrap errors with context: `fmt.Errorf("operation failed: %w", err)` - Use `%w` verb for error wrapping to preserve error chain - Check all error returns (enforced by `errcheck`) - Document error handling rationale in defer blocks when ignoring close errors ### Comments + - All exported types/functions require godoc comments - End sentences with periods (`godot` linter enforced) - Mark known issues with TODO/FIXME/HACK/BUG/XXX ### 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 ### Testing + - Enable race detection: `-race` flag - Use table-driven tests where applicable - Mark test helpers with `t.Helper()` - Benchmarks in `*_bench_test.go`, examples in `*_example_test.go` ### Dependencies + - Minimal external dependencies (currently: go-docx, golang.org/x/net, golang.org/x/text) - Run `task deps:tidy` after adding/removing dependencies + +--- + +## Go 1.24 & 1.25 New Features Reference + +This project uses Go 1.24+. Below is a comprehensive summary of new features and changes in Go 1.24 and 1.25 that may be relevant for development and maintenance. + +### Go 1.24 Major Changes (Released February 2025) + +#### Language Features + +**Generic Type Aliases** + +- Type aliases can now be parameterized with type parameters +- Example: `type List[T any] = []T` +- Can be disabled via `GOEXPERIMENT=noaliastypeparams` (removed in 1.25) + +#### Tooling Enhancements + +**Module Tool Dependencies** + +- New `tool` directive in go.mod tracks executable dependencies +- Use `go get -tool ` to add tool dependencies +- Use `go install tool` and `go get tool` to manage them +- Eliminates need for blank imports in `tools.go` files + +**Build Output Formatting** + +- Both `go build` and `go test` support `-json` flag for structured JSON output +- New action types distinguish build output from test results + +**Authentication** + +- New `GOAUTH` environment variable provides flexible authentication for private modules + +**Automatic Version Tracking** + +- `go build` automatically sets main module version in binaries based on VCS tags +- Adds `+dirty` suffix for uncommitted changes + +**Cgo Performance Improvements** + +- New `#cgo noescape` annotation: Prevents escape analysis overhead for C function calls +- New `#cgo nocallback` annotation: Indicates C function won't call back to Go + +**Toolchain Tracing** + +- `GODEBUG=toolchaintrace=1` enables tracing of toolchain selection + +#### Runtime & Performance + +**Performance Improvements** + +- **2-3% CPU overhead reduction** across benchmark suites +- New Swiss Tables-based map implementation (faster lookups) + - Disable via `GOEXPERIMENT=noswissmap` +- More efficient small object allocation +- Redesigned runtime-internal mutexes + - Disable via `GOEXPERIMENT=nospinbitmutex` + +#### Compiler & Linker + +**Method Receiver Restrictions** + +- Methods on cgo-generated types now prevented (both directly and through aliases) + +**Build IDs** + +- Linkers generate GNU build IDs (ELF) and UUIDs (macOS) by default +- Disable via `-B none` flag + +#### Standard Library Additions + +**File System Safety - `os.Root`** + +- New `os.Root` type enables directory-limited operations +- Prevents path escape and symlink breakouts +- Essential for sandboxed file operations + +**Cryptography Expansion** + +- `crypto/mlkem`: ML-KEM-768/1024 post-quantum key exchange (FIPS 203) +- `crypto/hkdf`: HMAC-based Extract-and-Expand KDF (RFC 5869) +- `crypto/pbkdf2`: Password-based key derivation (RFC 8018) +- `crypto/sha3`: SHA-3 and SHAKE functions (FIPS 202) + +**FIPS 140-3 Support** + +- New `GOFIPS140` environment variable enables FIPS mode +- New `fips140` GODEBUG setting for cryptographic module compliance + +**Weak References - `weak` Package** + +- New `weak` package provides low-level weak pointers +- Enables memory-efficient structures like weak maps and caches +- Useful for preventing memory leaks in cache implementations + +**Testing Improvements** + +- `testing.B.Loop()`: Cleaner syntax replacing manual `b.N` iteration +- Prevents compiler from optimizing away benchmarked code +- New `testing/synctest` package (experimental) for testing concurrent code with fake clocks + +**Iterator Support** + +- Multiple packages now offer iterator-returning variants: + - `bytes`: Iterator-based functions + - `strings`: Iterator-based functions + - `go/types`: Iterator support + +#### Security Enhancements + +**TLS Post-Quantum Cryptography** + +- `X25519MLKEM768` hybrid key exchange enabled by default in TLS +- Provides quantum-resistant security + +**Encrypted Client Hello (ECH)** + +- TLS servers can enable ECH via `Config.EncryptedClientHelloKeys` +- Protects client identity during TLS handshake + +**RSA Key Validation** + +- Keys smaller than 1024 bits now rejected by default +- Use `GODEBUG=rsa1024min=0` to revert (testing only) + +**Constant-Time Execution** + +- New `crypto/subtle.WithDataIndependentTiming()` enables architecture-specific timing guarantees +- Helps prevent timing attacks + +#### Deprecations & Removals + +- `runtime.GOROOT()`: Deprecated; use system path instead +- `crypto/cipher` OFB/CFB modes: Deprecated (unauthenticated encryption) +- `x509sha1` GODEBUG: Removed; SHA-1 certificates no longer verified +- Experimental `X25519Kyber768Draft00`: Removed + +#### Platform Changes + +- **Linux**: Now requires kernel 3.2+ (enforced) +- **macOS**: Go 1.24 is final release supporting Big Sur +- **Windows/ARM 32-bit**: Marked broken +- **WebAssembly**: + - New `go:wasmexport` directive + - Reactor/library builds supported via `-buildmode=c-shared` + +#### Bootstrap Requirements + +- Go 1.24 requires Go 1.22.6+ for bootstrapping +- Go 1.26 will require Go 1.24+ + +--- + +### Go 1.25 Major Changes (Released August 2025) + +#### Language Changes + +- No breaking language changes +- "Core types" concept removed from specification (replaced with clearer prose) + +#### Tooling Improvements + +**Go Command Enhancements** + +- `go build -asan`: Now defaults to leak detection at program exit +- New `go.mod ignore` directive: Specify directories for go command to ignore +- `go doc -http`: Starts documentation server and opens in browser +- `go version -m -json`: Prints JSON-encoded BuildInfo structures +- Module path resolution now supports subdirectories using `` syntax +- New `work` package pattern matches all packages in work/workspace modules +- Removed automatic toolchain line additions when updating `go` version + +**Vet Analyzers** + +- **"waitgroup"**: Detects misplaced `sync.WaitGroup.Add` calls +- **"hostport"**: Warns against using `fmt.Sprintf` for constructing addresses + - Recommends `net.JoinHostPort` instead + +#### Runtime Enhancements + +**Container-Aware GOMAXPROCS** + +- Linux now respects cgroup CPU bandwidth limits +- All OSes periodically update GOMAXPROCS if CPU availability changes +- Disable via environment variables or GODEBUG settings +- Critical for containerized applications + +**New Garbage Collector - "Green Tea GC"** + +- Experimental `GOEXPERIMENT=greenteagc` enables new GC +- **10-40% reduction in garbage collection overhead** +- Significant for GC-sensitive applications + +**Trace Flight Recorder** + +- New `runtime/trace.FlightRecorder` API +- Captures execution traces in in-memory ring buffer +- Essential for debugging rare events and production issues + +**Other Runtime Changes** + +- Simplified unhandled panic output +- VMA names on Linux identify memory purpose (debugging aid) +- New `SetDefaultGOMAXPROCS` function resets GOMAXPROCS to defaults + +#### Compiler Fixes & Improvements + +**Critical Nil Pointer Bug Fix** + +- Fixed Go 1.21 regression where nil pointer checks were incorrectly delayed +- โš ๏ธ **May cause previously passing code to now panic** (correct behavior) +- Review code for assumptions about delayed nil checks + +**DWARF5 Support** + +- Debug information now uses DWARF version 5 +- Reduces binary size and linking time +- Better debugging experience + +**Faster Slices** + +- Expanded stack allocation for slice backing stores +- Improved slice performance + +#### Linker + +- New `-funcalign=N` option specifies function entry alignment + +#### Standard Library Highlights + +**New Packages** + +1. **`testing/synctest`** (Promoted from Experimental) + - Concurrent code testing with virtualized time + - Control time progression in tests + - Essential for testing time-dependent concurrent code + +2. **`encoding/json/v2`** (Experimental) + - **Substantially better decoding performance** + - Improved API design + - Backward compatible with v1 + +**Major Package Updates** + +| Package | Key Changes | +|---------|------------| +| `crypto` | New `MessageSigner` interface and `SignMessage` function | +| `crypto/ecdsa` | New raw key parsing/serialization functions | +| `crypto/rsa` | **Key generation now 3x faster** | +| `crypto/sha1` | **Hashing 2x faster on amd64 with SHA-NI** | +| `crypto/tls` | New `CurveID` field; SHA-1 algorithms disallowed in TLS 1.2 | +| `net` | Windows now supports file-to-connection conversion; IPv6 multicast improvements | +| `net/http` | **New `CrossOriginProtection` middleware for CSRF defense** | +| `os` | Windows async I/O support; `Root` type expanded with 12 new methods | +| `sync` | **New `WaitGroup.Go` method for convenient goroutine creation** | +| `testing` | New `Attr`, `Output` methods; `AllocsPerRun` panics with parallel tests | +| `unique` | More eager and parallel reclamation of interned values | + +#### Performance Notes + +**Performance Improvements** + +- ECDSA and Ed25519 signing **4x faster** in FIPS 140-3 mode +- SHA3 hashing **2x faster** on Apple M processors +- AMD64 fused multiply-add instructions in v3+ mode + - โš ๏ธ **Changes floating-point results** (within IEEE 754 spec) + +**Performance Regressions** + +- SHA-1, SHA-256, SHA-512 slower without AVX2 + - Most servers post-2015 support AVX2 + +#### Platform Changes + +- **macOS**: Requires version 12 Monterey or later +- **Windows**: 32-bit windows/arm port marked for removal in Go 1.26 +- **Loong64**: Race detector now supported +- **RISC-V**: + - Plugin build mode support + - New `GORISCV64=rva23u64` environment variable value + +#### Deprecations + +- `go/ast` functions: `FilterPackage`, `PackageExports`, `MergePackageFiles` +- `go/parser.ParseDir` function +- Old `testing/synctest` API (when `GOEXPERIMENT=synctest` set) + +--- + +### Actionable Recommendations for This Project + +#### Immediate Opportunities + +1. **Replace `sync.WaitGroup` patterns with `WaitGroup.Go()`** (Go 1.25) + + ```go + // Old pattern + wg.Add(1) + go func() { + defer wg.Done() + // work + }() + + // New pattern (Go 1.25) + wg.Go(func() { + // work + }) + ``` + +2. **Use `testing.B.Loop()` in benchmarks** (Go 1.24) + + ```go + // Old pattern + for i := 0; i < b.N; i++ { + // benchmark code + } + + // New pattern (Go 1.24) + for b.Loop() { + // benchmark code + } + ``` + +3. **Consider `os.Root` for file operations** (Go 1.24) + - Prevents path traversal vulnerabilities + - Safer for user-provided file paths + +4. **Enable Green Tea GC for testing** (Go 1.25) + - Test with `GOEXPERIMENT=greenteagc` + - May reduce GC overhead by 10-40% + +5. **Leverage container-aware GOMAXPROCS** (Go 1.25) + - No changes needed; automatic in containers + - Improves resource utilization + +6. **Review floating-point operations** (Go 1.25) + - AMD64 v3+ uses FMA instructions + - May change floating-point results (within spec) + +7. **Watch nil pointer checks** (Go 1.25) + - Compiler bug fix may expose latent nil pointer bugs + - Review crash reports carefully + +#### Future Considerations + +1. **Evaluate `encoding/json/v2`** when stable + - Better performance for JSON operations + - Currently experimental in Go 1.25 + +2. **Adopt tool directives** in go.mod + - Cleaner dependency management for build tools + - Remove `tools.go` if present + +3. **Enable FIPS mode if required** + - Use `GOFIPS140=1` for compliance + - Performance improvements in Go 1.25 (4x faster signing) + +4. **Use `runtime/trace.FlightRecorder`** for production debugging + - Capture traces of rare events + - Minimal overhead when not triggered diff --git a/DOCKER.md b/DOCKER.md index b8ae1d5..0b28b1b 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -49,17 +49,17 @@ docker run --rm ghcr.io/kjanat/articulate-parser:latest --version ## Available Tags -- `latest` - Latest stable release -- `v1.x.x` - Specific version tags -- `main` - Latest development build +- `latest` - Latest stable release +- `v1.x.x` - Specific version tags +- `main` - Latest development build ## Image Details -- **Base Image**: `scratch` (minimal attack surface) -- **Architecture**: Multi-arch support (amd64, arm64) -- **Size**: < 10MB (optimized binary) -- **Security**: Runs as non-root user -- **Features**: SBOM and provenance attestation included +- **Base Image**: `scratch` (minimal attack surface) +- **Architecture**: Multi-arch support (amd64, arm64) +- **Size**: < 10MB (optimized binary) +- **Security**: Runs as non-root user +- **Features**: SBOM and provenance attestation included ## Development @@ -77,6 +77,6 @@ docker-compose up --build ## Repository -- **Source**: [github.com/kjanat/articulate-parser](https://github.com/kjanat/articulate-parser) -- **Issues**: [Report bugs or request features](https://github.com/kjanat/articulate-parser/issues) -- **License**: See repository for license details +- **Source**: [github.com/kjanat/articulate-parser](https://github.com/kjanat/articulate-parser) +- **Issues**: [Report bugs or request features](https://github.com/kjanat/articulate-parser/issues) +- **License**: See repository for license details diff --git a/Dockerfile b/Dockerfile index 59b938e..b365d8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ ARG BUILD_TIME ARG GIT_COMMIT # Docker buildx automatically provides these for multi-platform builds ARG BUILDPLATFORM -ARG TARGETPLATFORM +ARG TARGETPLATFORM ARG TARGETOS ARG TARGETARCH ARG TARGETVARIANT diff --git a/Dockerfile.dev b/Dockerfile.dev index 47e34b9..4cfe848 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -30,7 +30,7 @@ ARG BUILD_TIME ARG GIT_COMMIT # Docker buildx automatically provides these for multi-platform builds ARG BUILDPLATFORM -ARG TARGETPLATFORM +ARG TARGETPLATFORM ARG TARGETOS ARG TARGETARCH ARG TARGETVARIANT diff --git a/README.md b/README.md index fc2fbfb..926f9bf 100644 --- a/README.md +++ b/README.md @@ -20,36 +20,36 @@ A Go-based parser that converts Articulate Rise e-learning content to various fo flowchart TD %% User Input CLI[Command Line Interface
main.go] --> APP{App Service
services/app.go} - + %% Core Application Logic APP --> |"ProcessCourseFromURI"| PARSER[Course Parser
services/parser.go] APP --> |"ProcessCourseFromFile"| PARSER APP --> |"exportCourse"| FACTORY[Exporter Factory
exporters/factory.go] - + %% Data Sources PARSER --> |"FetchCourse"| API[Articulate Rise API
rise.articulate.com] PARSER --> |"LoadCourseFromFile"| FILE[Local JSON File
*.json] - + %% Data Models API --> MODELS[Data Models
models/course.go] FILE --> MODELS MODELS --> |Course, Lesson, Item| APP - + %% Export Factory Pattern FACTORY --> |"CreateExporter"| MARKDOWN[Markdown Exporter
exporters/markdown.go] FACTORY --> |"CreateExporter"| HTML[HTML Exporter
exporters/html.go] FACTORY --> |"CreateExporter"| DOCX[DOCX Exporter
exporters/docx.go] - + %% HTML Cleaning Service CLEANER[HTML Cleaner
services/html_cleaner.go] --> MARKDOWN CLEANER --> HTML CLEANER --> DOCX - + %% Output Files MARKDOWN --> |"Export"| MD_OUT[Markdown Files
*.md] HTML --> |"Export"| HTML_OUT[HTML Files
*.html] DOCX --> |"Export"| DOCX_OUT[Word Documents
*.docx] - + %% Interfaces (Contracts) IPARSER[CourseParser Interface
interfaces/parser.go] -.-> PARSER IEXPORTER[Exporter Interface
interfaces/exporter.go] -.-> MARKDOWN @@ -64,7 +64,7 @@ flowchart TD classDef output fill:#fce7f3,stroke:#be185d,stroke-width:2px,color:#be185d classDef interface fill:#ecfdf5,stroke:#16a34a,stroke-width:1px,stroke-dasharray: 5 5,color:#16a34a classDef service fill:#cffafe,stroke:#0891b2,stroke-width:2px,color:#0891b2 - + class CLI userInput class APP,FACTORY coreLogic class API,FILE,MODELS dataSource @@ -78,32 +78,32 @@ flowchart TD The system follows **Clean Architecture** principles with clear separation of concerns: -- **๐ŸŽฏ Entry Point**: Command-line interface handles user input and coordinates operations -- **๐Ÿ—๏ธ Application Layer**: Core business logic with dependency injection -- **๐Ÿ“‹ Interface Layer**: Contracts defining behavior without implementation details -- **๐Ÿ”ง Service Layer**: Concrete implementations of parsing and utility services -- **๐Ÿ“ค Export Layer**: Factory pattern for format-specific exporters -- **๐Ÿ“Š Data Layer**: Domain models representing course structure +- **๐ŸŽฏ Entry Point**: Command-line interface handles user input and coordinates operations +- **๐Ÿ—๏ธ Application Layer**: Core business logic with dependency injection +- **๐Ÿ“‹ Interface Layer**: Contracts defining behavior without implementation details +- **๐Ÿ”ง Service Layer**: Concrete implementations of parsing and utility services +- **๐Ÿ“ค Export Layer**: Factory pattern for format-specific exporters +- **๐Ÿ“Š Data Layer**: Domain models representing course structure ## Features -- Parse Articulate Rise JSON data from URLs or local files -- Export to Markdown (.md) format -- Export to HTML (.html) format with professional styling -- Export to Word Document (.docx) format -- Support for various content types: - - Text content with headings and paragraphs - - Lists and bullet points - - Multimedia content (videos and images) - - Knowledge checks and quizzes - - Interactive content (flashcards) - - Course structure and metadata +- Parse Articulate Rise JSON data from URLs or local files +- Export to Markdown (.md) format +- Export to HTML (.html) format with professional styling +- Export to Word Document (.docx) format +- Support for various content types: + - Text content with headings and paragraphs + - Lists and bullet points + - Multimedia content (videos and images) + - Knowledge checks and quizzes + - Interactive content (flashcards) + - Course structure and metadata ## Installation ### Prerequisites -- Go, I don't know the version, but I have [![Go version](https://img.shields.io/github/go-mod/go-version/kjanat/articulate-parser?label=)][gomod] configured right now, and it works, see the [CI][Build] workflow where it is tested. +- Go, I don't know the version, but I have [![Go version](https://img.shields.io/github/go-mod/go-version/kjanat/articulate-parser?label=)][gomod] configured right now, and it works, see the [CI][Build] workflow where it is tested. ### Install from source @@ -124,7 +124,7 @@ go install github.com/kjanat/articulate-parser@latest The parser uses the following external library: -- `github.com/fumiama/go-docx` - For creating Word documents (MIT license) +- `github.com/fumiama/go-docx` - For creating Word documents (MIT license) ## Testing @@ -164,25 +164,25 @@ go run main.go [output_path] #### Examples -1. **Parse from URL and export to Markdown:** +1. **Parse from URL and export to Markdown:** ```bash go run main.go "https://rise.articulate.com/share/N_APNg40Vr2CSH2xNz-ZLATM5kNviDIO#/" md ``` -2. **Parse from local file and export to Word:** +2. **Parse from local file and export to Word:** ```bash go run main.go "articulate-sample.json" docx "my-course.docx" ``` -3. **Parse from local file and export to HTML:** +3. **Parse from local file and export to HTML:** ```bash go run main.go "articulate-sample.json" html "output.html" ``` -4. **Parse from local file and export to Markdown:** +4. **Parse from local file and export to Markdown:** ```bash go run main.go "articulate-sample.json" md "output.md" @@ -332,88 +332,88 @@ The Docker image supports the following build-time arguments: The project maintains high code quality standards: -- Cyclomatic complexity โ‰ค 15 (checked with [gocyclo](https://github.com/fzipp/gocyclo)) -- Race condition detection enabled -- Comprehensive test coverage -- Code formatting with `gofmt` -- Static analysis with `go vet` +- Cyclomatic complexity โ‰ค 15 (checked with [gocyclo](https://github.com/fzipp/gocyclo)) +- Race condition detection enabled +- Comprehensive test coverage +- Code formatting with `gofmt` +- Static analysis with `go vet` ### Contributing -1. Fork the repository -2. Create a feature branch -3. Make your changes -4. Run tests: `go test ./...` -5. Submit a pull request +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Run tests: `go test ./...` +5. Submit a pull request ## Output Formats ### Markdown (`.md`) -- Hierarchical structure with proper heading levels -- Clean text content with HTML tags removed -- Lists and bullet points preserved -- Quiz questions with correct answers marked -- Media references included -- Course metadata at the top +- Hierarchical structure with proper heading levels +- Clean text content with HTML tags removed +- Lists and bullet points preserved +- Quiz questions with correct answers marked +- Media references included +- Course metadata at the top ### HTML (`.html`) -- Professional styling with embedded CSS -- Interactive and visually appealing layout -- Proper HTML structure with semantic elements -- Responsive design for different screen sizes -- All content types beautifully formatted -- Maintains course hierarchy and organization +- Professional styling with embedded CSS +- Interactive and visually appealing layout +- Proper HTML structure with semantic elements +- Responsive design for different screen sizes +- All content types beautifully formatted +- Maintains course hierarchy and organization ### Word Document (`.docx`) -- Professional document formatting -- Bold headings and proper typography -- Bulleted lists -- Quiz questions with answers -- Media content references -- Maintains course structure +- Professional document formatting +- Bold headings and proper typography +- Bulleted lists +- Quiz questions with answers +- Media content references +- Maintains course structure ## Supported Content Types The parser handles the following Articulate Rise content types: -- **Text blocks**: Headings and paragraphs -- **Lists**: Bullet points and numbered lists -- **Multimedia**: Videos and images (references only) -- **Knowledge Checks**: Multiple choice, multiple response, fill-in-the-blank, matching -- **Interactive Content**: Flashcards and interactive scenarios -- **Dividers**: Section breaks -- **Sections**: Course organization +- **Text blocks**: Headings and paragraphs +- **Lists**: Bullet points and numbered lists +- **Multimedia**: Videos and images (references only) +- **Knowledge Checks**: Multiple choice, multiple response, fill-in-the-blank, matching +- **Interactive Content**: Flashcards and interactive scenarios +- **Dividers**: Section breaks +- **Sections**: Course organization ## Data Structure The parser works with the standard Articulate Rise JSON format which includes: -- Course metadata (title, description, settings) -- Lesson structure -- Content items with various types -- Media references -- Quiz/assessment data -- Styling and layout information +- Course metadata (title, description, settings) +- Lesson structure +- Content items with various types +- Media references +- Quiz/assessment data +- Styling and layout information ## URL Pattern Recognition The parser automatically extracts share IDs from Articulate Rise URLs: -- Input: `https://rise.articulate.com/share/N_APNg40Vr2CSH2xNz-ZLATM5kNviDIO#/` -- API URL: `https://rise.articulate.com/api/rise-runtime/boot/share/N_APNg40Vr2CSH2xNz-ZLATM5kNviDIO` +- Input: `https://rise.articulate.com/share/N_APNg40Vr2CSH2xNz-ZLATM5kNviDIO#/` +- API URL: `https://rise.articulate.com/api/rise-runtime/boot/share/N_APNg40Vr2CSH2xNz-ZLATM5kNviDIO` ## Error Handling The parser includes error handling for: -- Invalid URLs or share IDs -- Network connection issues -- Malformed JSON data -- File I/O errors -- Unsupported content types +- Invalid URLs or share IDs +- Network connection issues +- Malformed JSON data +- File I/O errors +- Unsupported content types