Skip to content

Ready to drop “beta” (e.g., improve config validation and symlink handling)#4

Merged
j9t merged 4 commits into
mainfrom
release-1.3.1
May 18, 2026
Merged

Ready to drop “beta” (e.g., improve config validation and symlink handling)#4
j9t merged 4 commits into
mainfrom
release-1.3.1

Conversation

@j9t
Copy link
Copy Markdown
Owner

@j9t j9t commented May 18, 2026

Summary by CodeRabbit

  • New Features

    • Symlinked HTML files within the scanned root are now followed during traversal; symlinked directories are still skipped to prevent cycles.
  • Bug Fixes

    • Clearer error messages for malformed configuration values.
    • Improved quiet-mode hint messaging when output is suppressed or a report is requested.
  • Documentation

    • Informational warnings now noted to exit with code 0.
    • Removed "Beta" from the product heading and clarified symlink behavior in the API.
  • Chores

    • Release bumped to 1.3.2.

Review Change Stack

Added explicit error messages for invalid config values (e.g., `links.timeout`, `links.warnOnPermanentRedirects`). Updated directory traversal logic to follow symlinked files while skipping symlinked directories to prevent cycles. Adjusted quiet mode message handling to correctly display report suggestions.

(This commit message was AI-generated.)

Signed-off-by: Jens Oliver Meiert <jens@meiert.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 56b0d842-1d03-48b1-824e-aa789020f4d8

📥 Commits

Reviewing files that changed from the base of the PR and between ef181bb and ef1fa89.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • README.md
  • bin/hihtml.test.js
  • src/lib/files.js

Walkthrough

This PR releases version 1.3.2 with centralized configuration validation, symlink-aware directory traversal that follows in-root symlinked HTML files while skipping symlinked directories, and refined quiet-mode CLI hints. Documentation and package version are updated accordingly.

Changes

v1.3.2 Release

Layer / File(s) Summary
Config validation framework and schema enforcement
src/lib/config.js, bin/hihtml.test.js
New validateConfig() centralizes runtime validation for optional config fields (extensions, ignore, validation.preset, links.timeout, links.concurrency, minification) and is invoked from loadConfig for .hihtml.json, default config, and package.json. Tests added to assert descriptive rejections for invalid types/values.
Follow symlinked HTML files in directory traversal
src/lib/files.js, bin/hihtml.test.js
collect() resolves a canonical root and passes it to walk(); walk() resolves symlinks and includes symlink paths that resolve to in-root files matching HTML extensions, skips symlinked directories to avoid cycles, and ignores broken/unresolvable symlinks. Tests cover in-root and outside-root symlink cases.
Tailored quiet-mode CLI messaging
bin/hihtml.js
quietHint() only emits a hint when --quiet is set and no output sections exist; the hint message differs based on whether --report was supplied (directing to generate a report) or not (suggesting running without -q for inline output).
Documentation clarifications and release metadata
README.md, CHANGELOG.md, package.json
README title removes “(Beta)”, API docs clarify collect() symlink behavior, exit-code table documents that ObsoHTML deprecation warnings map to exit code 0, CHANGELOG adds 1.3.2 entry, and package.json version bumped to 1.3.2.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • j9t/hihtml#2: Both PRs modify bin/hihtml.js quiet-mode behavior and output-section handling, creating a direct relationship at the CLI interface level.
  • j9t/hihtml#1: Also touches src/lib/files.js traversal logic; related to directory walking and concurrency changes that interact with the symlink handling changes here.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main objective of dropping the beta qualifier and lists key improvements (config validation and symlink handling) that are central to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release-1.3.1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bin/hihtml.js`:
- Line 147: The guard that decides whether to show the quiet-mode hint is
inverted: in the code around the conditional using opts.quiet and sections it
currently returns when (!opts.quiet || sections.length === 0); change the logic
so the function returns early only when not in quiet mode or when there are
existing sections (i.e., flip sections.length === 0 to sections.length > 0) so
the hint is shown when quiet is enabled and no sections exist; update the
conditional that references opts.quiet and sections accordingly (the surrounding
block that emits the hint).

In `@src/lib/files.js`:
- Line 84: The bare catch around the stat/lstat call swallows all errors; change
it to catch the error object (e.g., catch (err)) and only ignore expected
"broken symlink" errno values (at minimum 'ENOENT' and 'ELOOP') while rethrowing
any other errors so real permission/IO problems surface. Locate the try/catch
around the stat() call (the block that currently reads catch { /* broken
symlink—skip */ }) and replace it with logic that checks err.code and
continues/returns for the known symlink-related codes but throws err for
anything else.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 27b8b532-29ec-4b7e-9f69-4486ed42ac73

📥 Commits

Reviewing files that changed from the base of the PR and between 25c26cd and ef181bb.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • CHANGELOG.md
  • README.md
  • bin/hihtml.js
  • bin/hihtml.test.js
  • package.json
  • src/lib/config.js
  • src/lib/files.js

Comment thread bin/hihtml.js
Comment thread src/lib/files.js Outdated
Improved error handling to exclude specific error codes (`ENOENT`, `ELOOP`, `EACCES`, `EPERM`) while preserving existing behavior for broken symlinks. Ensures unexpected errors are rethrown to avoid masking critical issues.

(This commit message was AI-generated.)

Signed-off-by: Jens Oliver Meiert <jens@meiert.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prepares hihtml for a non-beta release by improving robustness and clarity around configuration handling, file traversal behavior, and user-facing messaging.

Changes:

  • Follow symlinked HTML files during directory traversal while continuing to skip symlinked directories to avoid cycles.
  • Add strict config shape/type validation with clearer error messages, plus new regression tests for invalid config values.
  • Update CLI quiet-mode hint messaging and refresh docs/versioning for the 1.3.2 release.

Reviewed changes

Copilot reviewed 5 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/lib/files.js Updates recursive walk logic to include symlinked HTML files (but skip symlinked dirs).
src/lib/config.js Adds runtime config validation to fail fast with clearer errors on malformed config.
bin/hihtml.js Adjusts --quiet hint messaging to avoid suggesting -r when report output is already enabled.
bin/hihtml.test.js Adds tests asserting config validation errors for invalid types/values.
README.md Removes “Beta” branding and documents symlink traversal + informational warning exit code behavior.
CHANGELOG.md Adds release notes for 1.3.2 dated 2026-05-18.
package.json Bumps version from 1.3.1-beta to 1.3.2.
package-lock.json Updates lockfile version metadata to match 1.3.2.
Comments suppressed due to low confidence (2)

src/lib/files.js:88

  • This change adds new symlink traversal behavior but there’s no corresponding test coverage. Since the repo already tests collect() in bin/hihtml.test.js, please add tests that (1) a symlinked .html file is included and (2) a symlinked directory is not traversed (to prevent cycles), with platform guards where necessary.
    if (entry.isSymbolicLink()) {
      try {
        const resolved = await fs.promises.stat(fullPath);
        if (resolved.isFile()) {
          const ext = path.extname(entry.name).slice(1).toLowerCase();
          if (extensions.has(ext)) results.push(fullPath);
        }
        // Symlinked directories are skipped to prevent cycles
      } catch (err) {
        const code = /** @type {NodeJS.ErrnoException} */ (err).code;
        if (code !== 'ENOENT' && code !== 'ELOOP' && code !== 'EACCES' && code !== 'EPERM') throw err;
      }
      continue;

src/lib/files.js:80

  • resolved here is a fs.Stats object (result of stat()), not a resolved path. Renaming it to something like stats would make the intent clearer and avoid confusion with the resolved path variable used elsewhere in this module.
        const resolved = await fs.promises.stat(fullPath);
        if (resolved.isFile()) {
          const ext = path.extname(entry.name).slice(1).toLowerCase();

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/files.js
Updated traversal logic to follow symlinked files only when their targets resolve within the scanned root, skipping symlinks pointing outside the root or to directories. Added corresponding unit tests to ensure correct behavior and prevent regressions.

(This commit message was AI-generated.)

Signed-off-by: Jens Oliver Meiert <jens@meiert.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 8 changed files in this pull request and generated 1 comment.

Comment thread src/lib/files.js
Updated symlink handling to ensure `realpath` calculations respect the scanned root directory. Improved logic to handle relative paths correctly and skip invalid symlinks pointing outside the root, preventing unintended traversal.

(This commit message was AI-generated.)

Signed-off-by: Jens Oliver Meiert <jens@meiert.com>
@j9t j9t merged commit 66bb5e6 into main May 18, 2026
8 checks passed
@j9t j9t deleted the release-1.3.1 branch May 18, 2026 12:47
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