Skip to content

Conversation

@radleta
Copy link
Owner

@radleta radleta commented Nov 4, 2025

Release v1.1.0: Grep Format for Automated Link Fixing

Summary

This release introduces the new grep format for mdite lint, enabling automated link fixing workflows with standard Unix tools. The format provides tab-delimited output that can be parsed with cut, awk, and sed to programmatically fix broken links without manual intervention or path reverse-engineering.

Key Improvements

  1. Grep Format - New --format grep option for machine-parseable, tab-delimited output
  2. Literal Path Capture - Error reporting now includes literal link text from source files
  3. Enhanced CLI Help - Comprehensive documentation following Unix best practices
  4. CI/CD Security - Release workflow restricted to main branch only

What's Changed

Added

🆕 Grep Format for Lint Output

New --format grep option provides machine-parseable, tab-delimited output for automated link fixing.

Format specification:

  • Field order: file, line, column, endColumn, severity, ruleId, literal, resolvedPath
  • Delimiter: Tab character (\t)
  • Colors: Auto-disabled for machine readability
  • Backward compatible: Existing text and JSON formats unchanged

Example usage:

# Get tab-delimited output
mdite lint --format grep

# Extract all literal link texts (field 7)
mdite lint --format grep | cut -d$'\t' -f7

# Extract file and literal for processing
mdite lint --format grep | awk -F'\t' '{print $1 ":" $2 " → " $7}'

# Automated fix workflow
mdite lint --format grep | while IFS=$'\t' read file line col endCol severity rule literal resolved; do
  if [ "$rule" = "dead-link" ]; then
    sed -i "${line}s|$literal|correct-path|" "$file"
  fi
done

# Extract broken links by file
mdite lint --format grep | awk -F'\t' '$6=="dead-link" {print $1, $7}' | sort

# Count broken links by type
mdite lint --format grep | cut -d$'\t' -f6 | sort | uniq -c

Impact: Users can now build automated scripts to fix broken links using standard Unix tools, without needing to parse human-readable error messages or reverse-engineer file paths.

CLI changes:

  • Added 'grep' to valid format options: --format text|json|grep
  • Auto-disables colors for grep format
  • Modified: src/commands/lint.ts

🔍 Literal Path Error Reporting

Enhanced error reporting that captures and reports literal link text exactly as written in source files.

What changed:

  • Extended LintError interface with three new optional fields:
    • literal: The literal link text from source (e.g., '../../../docs/file.md')
    • endColumn: End column position for range extraction
    • resolvedPath: Resolved path relative to basePath (e.g., 'features/docs/file.md')
  • LinkValidator enhancement: Captures literal text and position from markdown AST during validation
  • Text format: Shows 'literal' resolves to 'resolved' inline for clarity
  • JSON format: Includes all three new fields in flat structure (backward compatible)
  • Architecture: Clean separation - LinkValidator creates complete error messages, Reporter presents them

Impact: Error messages now provide both the literal text (for automated fixes) and the resolved path (for human understanding), eliminating the need to reverse-engineer paths from error messages.

Modified files:

  • src/types/errors.ts - Extended LintError interface
  • src/core/link-validator.ts - Capture literal text and position from AST
  • src/core/reporter.ts - Format grep output, enhanced text/JSON formats
  • README.md - Added "Automated Link Fixing with Grep Format" workflow section

Testing:

  • Added 11 new integration tests in tests/integration/lint-literal-paths.test.ts
  • Tests cover: text format display, JSON field structure, grep format parsing, backward compatibility, complex scenarios

📖 Enhanced CLI Help System

Comprehensive help documentation following Unix CLI best practices from git, docker, npm, and ripgrep.

What changed:

  • Added CLI Help Text Standards section to CONTRIBUTING.md (213 new lines)
    • Documents hybrid architecture (shared vs command-specific help text)
    • Provides templates for DESCRIPTION, EXAMPLES, OUTPUT, SEE_ALSO sections
    • Includes formatting guidelines, conventions, and pre-merge checklist
    • References industry patterns from established Unix tools
  • Enhanced help text across all 6 commands:
    • Added detailed OUTPUT sections (8-10 bullets per command)
    • Improved SEE_ALSO organization (Core workflow, Configuration, Global tiers)
    • Standardized cross-references between related commands
  • Expanded shared help in src/utils/help-text.ts:
    • Detailed ENVIRONMENT_VARS descriptions
    • Context for NO_COLOR, FORCE_COLOR, CI usage
    • Documents precedence and flag equivalents
  • Updated integration tests to verify new help structure

Modified files (9 files, 403 insertions):

  • CONTRIBUTING.md - New standards section
  • src/commands/*.ts - All 6 command files enhanced
  • src/utils/help-text.ts - Expanded shared help
  • tests/integration/cli-help.test.ts - Updated tests

Impact: Developers can discover features and usage patterns directly from --help output without consulting external documentation. Help text is now comprehensive, consistent, and follows industry best practices.

Fixed

🔒 CI/CD: Release Workflow Restricted to Main Branch

Security improvement prevents accidental releases from feature or develop branches.

What changed:

  • Added branch filter to workflow trigger (only main branch)
  • Added verification step to check tag is on main branch before publishing
  • Fetches full git history for reliable branch verification

Impact: npm releases can only happen from the main branch, eliminating risk of publishing pre-release or development code.

Modified: .github/workflows/release.yml

Changed

📦 Package Publishing: Removed Redundant .npmignore

Technical debt cleanup - removed .npmignore file that was overridden by package.json.

What changed:

  • Removed .npmignore file completely
  • Package.json files field is now the single source of truth (per npm documentation)

Impact: Eliminates maintainer confusion about which file controls package contents. No functional change - package contents and size remain identical (87.6 kB).

Verification: npm pack --dry-run confirms unchanged package contents


Breaking Changes

None - This release is fully backward compatible:

  • Grep format is additive (new option)
  • New error fields are optional
  • Existing text/JSON formats unchanged
  • All existing APIs preserved

Testing

  • 625 tests passing (614 existing + 11 new for literal paths)
  • 38 smoke tests passing (all examples)
  • 100% test coverage maintained
  • Integration tests cover all three output formats and field structures
  • Backward compatibility verified with existing test suite

Documentation Updates

  • README.md: Added "Automated Link Fixing with Grep Format" workflow section
  • CONTRIBUTING.md: Added comprehensive CLI Help Text Standards (213 lines)
  • CHANGELOG.md: Detailed breakdown of all changes

Commits

  • aec6bae - chore: remove redundant .npmignore (files field takes precedence)
  • 38da5b0 - docs(help): add comprehensive CLI help standards and enhance all commands
  • b03c970 - feat(lint): add literal path error reporting with grep format ⭐ NEW FORMAT
  • 763790d - fix(ci): restrict release workflow to main branch only
  • 0e6bef6 - fix: eliminate timing flakiness in delay test (merged from v1.0.2)

Migration Guide

No migration needed - this release is fully backward compatible.

To use new features:

# Use grep format for automated fixes
mdite lint --format grep | your-script.sh

# Existing commands work unchanged
mdite lint                # Text format (default)
mdite lint --format json  # JSON format

- Add branch filter to workflow trigger (only main branch)
- Add verification step to check tag is on main branch
- Fetch full git history for branch verification
- Prevents accidental releases from feature/develop branches

This ensures npm releases only happen from the main branch,
protecting against accidental releases from other branches.
Add literal link text and resolved path reporting to mdite lint errors,
enabling automated fix scripts with grep/sed without reverse-engineering paths.

## What Changed

### Error Type Enhancement
- Extended LintError interface with three new optional fields:
  - literal: The literal link text from source files (e.g., '../../../docs/file.md')
  - endColumn: End column position for range extraction
  - resolvedPath: Resolved path relative to basePath (e.g., 'features/docs/file.md')
- All fields optional for backward compatibility

### Link Validator Updates
- Capture literal text and position from markdown AST (remark/unified)
- Create complete error messages at source: "Dead link: 'literal' resolves to 'resolved'"
- Pass literal, endColumn, resolvedPath to all error objects
- Applies to dead-link, dead-anchor, and external-link errors

### Reporter Enhancements
- Text format: Shows 'literal' resolves to 'resolved' inline (uses error.message directly)
- JSON format: Includes literal, endColumn, resolvedPath fields (flat structure)
- **NEW grep format**: Tab-delimited output for Unix tool parsing
  - Field order: file, line, column, endColumn, severity, ruleId, literal, resolvedPath
  - Parseable with cut/awk/sed for automated fixes
  - Example: `mdite lint --format grep | cut -d$'\t' -f7` extracts all literal paths
- Clean architecture: LinkValidator creates messages, Reporter presents them (no parsing)

### CLI Updates
- Added 'grep' as valid format option: --format text|json|grep
- Auto-disables colors for grep format (machine-readable)

### Testing
- Added 11 new integration tests (tests/integration/lint-literal-paths.test.ts)
  - Text format literal display
  - JSON format field structure
  - Grep format tab-delimited parsing
  - Backward compatibility
  - Complex scenarios (multiple errors, anchors)
- Fixed 1 existing test updated for new format
- All 625 tests passing (614 existing + 11 new)
- All 38 smoke tests passing

### Documentation
- Updated CHANGELOG.md with feature details and examples
- Added README.md workflow 7: "Automated Link Fixing with Grep Format"
- Updated lint command documentation with grep format examples

## Use Cases

**Automated fix scripts**:
```bash
# Extract all literal paths
mdite lint --format grep | cut -d$'\t' -f7

# Process dead links
mdite lint --format grep | awk -F'\t' '$6=="dead-link" {print $1, $7}'

# Automated fix workflow
mdite lint --format grep | while IFS=$'\t' read file line col endCol severity rule literal resolved; do
  if [ "$rule" = "dead-link" ]; then
    sed -i "${line}s|$literal|correct-path|" "$file"
  fi
done
```

## Architecture

Clean separation of concerns achieved through iterative refinement:
1. LinkValidator creates complete error messages with literal/resolved at source
2. Reporter presents messages without any parsing or manipulation
3. Error type carries all necessary fields (literal, resolvedPath, endColumn)
4. All formats use error object fields directly (no regex, no brittleness)

## Breaking Changes

None - all new fields are optional and formats are additive.
…ands

- Add CLI help text standards section to CONTRIBUTING.md
  • Documents hybrid architecture (shared vs command-specific)
  • Provides templates for DESCRIPTION, EXAMPLES, OUTPUT, SEE_ALSO
  • Includes formatting guidelines and checklists
  • References industry best practices (git, docker, npm, ripgrep)

- Enhance help text across all commands
  • Add detailed OUTPUT sections (8-10 bullets each)
  • Improve SEE_ALSO organization (Core workflow, Configuration, Global tiers)
  • Standardize cross-references between related commands

- Improve shared help text (help-text.ts)
  • Expand ENVIRONMENT_VARS with detailed descriptions
  • Add context for NO_COLOR, FORCE_COLOR, CI usage
  • Document precedence and equivalents

- Update tests to match new help structure
  • Fix JMESPath reference check for new External tier
  • Maintain all existing coverage
The .npmignore file was redundant because the 'files' field in package.json
takes absolute precedence according to npm documentation. When a 'files' field
is present, .npmignore is completely ignored.

This change:
- Eliminates technical debt and maintainer confusion
- Establishes package.json 'files' as single source of truth
- No impact on package contents (verified with npm pack --dry-run)

Package size remains: 87.6 kB
Files included remain unchanged: dist/src/, README.md, CHANGELOG.md, LICENSE

Resolves: scratch/release-ready-20251104-140123/ISSUE-npmignore-conflicts-with-files.md
- Move unreleased changes to v1.1.0 section dated 2025-11-04
- Reorganize from "Enhanced" to proper "Added" section
- Add grep format as headline feature (new machine-parseable output)
- Document literal path error reporting enhancements
- Include CLI help system improvements across all commands
- Add Fixed section for CI/CD branch restriction
- Add Changed section for .npmignore removal
- Comprehensive release notes covering all 5 commits since v1.0.2
- Replace 5 instances of `any` type with proper `LintError` type
- Add import for LintError interface
- Improves type safety and eliminates ESLint warnings
@radleta radleta merged commit 0753338 into main Nov 4, 2025
8 checks passed
@radleta radleta deleted the releases/1.1.0 branch November 4, 2025 17:13
@radleta radleta restored the releases/1.1.0 branch November 4, 2025 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants