[br-utils] Create package to consolidate itilities for CPF - #30
[br-utils] Create package to consolidate itilities for CPF#30juliolmuller wants to merge 7 commits into
br-utils] Create package to consolidate itilities for CPF#30Conversation
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
📝 WalkthroughWalkthroughThe PR replaces the placeholder gem with a unified, configurable ChangesUnified BrUtils façade
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Application
participant BrUtils
participant CpfUtils
participant CnpjUtils
Application->>BrUtils: access cpf or cnpj helper
BrUtils->>CpfUtils: delegate CPF operation
BrUtils->>CnpjUtils: delegate CNPJ operation
CpfUtils-->>Application: return CPF result
CnpjUtils-->>Application: return CNPJ result
Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 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 `@packages/br-utilities/README.md`:
- Around line 607-616: Update packages/br-utilities/README.md lines 607-616 and
packages/br-utilities/README.pt.md lines 600-609 to replace the undefined
BrUtils::DomainError rescue with a real bundled-package DomainError example.
Expand packages/br-utilities/README.md lines 641-652 and
packages/br-utilities/README.pt.md lines 634-645 with every propagated leaf,
including callback-delivered InvalidLengthError, documenting each in the
required order with its full hierarchy, marker, category, trigger, example, and
handling guidance.
- Line 26: Correct the façade wording to describe BrUtils.cpf and BrUtils.cnpj
as delegating to BrUtils::DEFAULT.cpf and BrUtils::DEFAULT.cnpj, not aliasing
the BrUtils::DEFAULT object. Apply the equivalent precise Portuguese wording in
packages/br-utilities/README.pt.md (line 19) and README.pt.md (line 19), and
update the same contract wording in packages/br-utilities/README.md (line 26),
README.md (line 26), and packages/br-utilities/CHANGELOG.md (line 11).
In `@packages/br-utilities/src/br-utilities/errors.rb`:
- Around line 4-8: Update the exposed sibling error marker modules, including
CpfFmt::Error and CnpjFmt::Error, to include BrUtils::Error so their derived
errors are caught by rescue BrUtils::Error. Add a rescue test covering a
propagated domain error such as CpfFmt::OutOfRangeError or
CnpjFmt::ValidationError.
In `@packages/br-utilities/src/br-utilities/version.rb`:
- Around line 3-6: The BrUtils constant is declared with conflicting module and
class kinds. In packages/br-utilities/src/br-utilities/version.rb lines 3-6,
declare BrUtils as a class and update the placeholder comment; keep the class
reopening in packages/br-utilities/src/br-utilities/br_utils.rb lines 37-42, and
align the BrUtils reopenings in
packages/br-utilities/src/br-utilities/cpf_gen.rb line 3, cpf_utils.rb line 3,
and cpf_val.rb line 3 with that class declaration.
In `@packages/br-utilities/tests/br_utils.spec.rb`:
- Around line 605-633: Add examples for the two documented BrUtils#initialize
contracts in the existing settings contexts: verify string-keyed settings are
normalized and adopt the provided CpfUtils/CnpjUtils instances, and verify
matching nested :cpf or :cnpj settings take precedence over flat keyword values.
Use the existing Helpers.normalize_settings behavior and preserve the current
non-Hash error coverage.
In `@README.md`:
- Around line 10-12: Add the blockquote marker to the blank line between callout
paragraphs in README.md lines 10-12, README.pt.md lines 3-5,
packages/br-utilities/README.md lines 10-12, and
packages/br-utilities/README.pt.md lines 3-5, keeping each callout in one
continuous blockquote.
- Line 239: Update repository-root documentation links to use package-relative
paths: in README.md (239-239) point CPF to packages/cpf-utilities/README.md,
(302-302) CNPJ to packages/cnpj-utilities/README.md, (471-471) both
bundled-package links, (643-643) both propagated-package links, (683-684) both
table links, and (703-703) the changelog to packages/br-utilities/CHANGELOG.md;
apply the corresponding README.pt.md paths at 232-232, 295-295, 464-464,
636-636, 670-670, and 676-677, with the changelog at 696-696 pointing to
packages/br-utilities/CHANGELOG.md.
🪄 Autofix
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 Plus
Run ID: 54e28ace-8710-4a3d-92f7-5bc81a132fdb
📒 Files selected for processing (21)
README.mdREADME.pt.mdpackages/br-utilities/CHANGELOG.mdpackages/br-utilities/Gemfilepackages/br-utilities/README.mdpackages/br-utilities/README.pt.mdpackages/br-utilities/br-utilities.gemspecpackages/br-utilities/src/br-utilities.rbpackages/br-utilities/src/br-utilities/br_utils.rbpackages/br-utilities/src/br-utilities/cnpj_fmt.rbpackages/br-utilities/src/br-utilities/cnpj_gen.rbpackages/br-utilities/src/br-utilities/cnpj_utils.rbpackages/br-utilities/src/br-utilities/cnpj_val.rbpackages/br-utilities/src/br-utilities/cpf_fmt.rbpackages/br-utilities/src/br-utilities/cpf_gen.rbpackages/br-utilities/src/br-utilities/cpf_utils.rbpackages/br-utilities/src/br-utilities/cpf_val.rbpackages/br-utilities/src/br-utilities/errors.rbpackages/br-utilities/src/br-utilities/version.rbpackages/br-utilities/tests/br_utilities.spec.rbpackages/br-utilities/tests/br_utils.spec.rb
💤 Files with no reviewable changes (2)
- packages/br-utilities/tests/br_utilities.spec.rb
- packages/br-utilities/Gemfile
|
|
||
| ## Features | ||
|
|
||
| - ✅ **Unified top-level API**: Class helpers `BrUtils.cpf` / `.cnpj` alias `BrUtils::DEFAULT`; each domain offers `format`, `generate`, and `is_valid` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
issue (blocking): Keep the façade identity contract consistent across the documentation.
The implementation delegates to BrUtils::DEFAULT.cpf and BrUtils::DEFAULT.cnpj. The current wording says that the helpers alias the BrUtils::DEFAULT façade object.
packages/br-utilities/README.md#L26-L26: Describe the helpers as delegating toBrUtils::DEFAULT.cpfand.cnpj.packages/br-utilities/README.pt.md#L19-L19: Use the same precise delegation wording in Portuguese.README.md#L26-L26: Correct the root English feature description.README.pt.md#L19-L19: Correct the root Portuguese feature description.packages/br-utilities/CHANGELOG.md#L11-L11: Correct the release-summary wording.
Based on the upstream contract in packages/br-utilities/src/br-utilities/br_utils.rb:242-267.
📍 Affects 5 files
packages/br-utilities/README.md#L26-L26(this comment)packages/br-utilities/README.pt.md#L19-L19README.md#L26-L26README.pt.md#L19-L19packages/br-utilities/CHANGELOG.md#L11-L11
🤖 Prompt for 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.
In `@packages/br-utilities/README.md` at line 26, Correct the façade wording to
describe BrUtils.cpf and BrUtils.cnpj as delegating to BrUtils::DEFAULT.cpf and
BrUtils::DEFAULT.cnpj, not aliasing the BrUtils::DEFAULT object. Apply the
equivalent precise Portuguese wording in packages/br-utilities/README.pt.md
(line 19) and README.pt.md (line 19), and update the same contract wording in
packages/br-utilities/README.md (line 26), README.md (line 26), and
packages/br-utilities/CHANGELOG.md (line 11).
| ```ruby | ||
| require 'br-utilities' | ||
|
|
||
| # 2) BrUtils::DomainError — not applicable: this gem defines no DomainError | ||
| # (and no domain leaves). Domain failures come from bundled packages only. | ||
| # begin | ||
| # BrUtils.new(cpf: { formatter: { hidden_start: -1 } }) | ||
| # rescue BrUtils::DomainError # NameError — constant is not defined | ||
| # end | ||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
issue (blocking): Apply the complete public error-documentation contract to both package READMEs.
The current documents omit the required details for propagated errors and do not demonstrate a real DomainError rescue.
packages/br-utilities/README.md#L607-L616: Replace the undefinedBrUtils::DomainErrorexample with the actual bundled-packageDomainError.packages/br-utilities/README.md#L641-L652: Document every propagated leaf, including callback-deliveredInvalidLengthError, with its full hierarchy, marker, category, trigger, example, and handling guidance.packages/br-utilities/README.pt.md#L600-L609: Add the equivalent realDomainErrorrescue example in Portuguese documentation.packages/br-utilities/README.pt.md#L634-L645: Add the equivalent complete propagated-error entries in Portuguese documentation.
As per coding guidelines, every public error must be documented in the required order, and the rescue section must use real library classes.
📍 Affects 2 files
packages/br-utilities/README.md#L607-L616(this comment)packages/br-utilities/README.md#L641-L652packages/br-utilities/README.pt.md#L600-L609packages/br-utilities/README.pt.md#L634-L645
🤖 Prompt for 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.
In `@packages/br-utilities/README.md` around lines 607 - 616, Update
packages/br-utilities/README.md lines 607-616 and
packages/br-utilities/README.pt.md lines 600-609 to replace the undefined
BrUtils::DomainError rescue with a real bundled-package DomainError example.
Expand packages/br-utilities/README.md lines 641-652 and
packages/br-utilities/README.pt.md lines 634-645 with every propagated leaf,
including callback-delivered InvalidLengthError, documenting each in the
required order with its full hierarchy, marker, category, trigger, example, and
handling guidance.
Source: Coding guidelines
| # Marker module mixed into every custom error raised by this library. | ||
| # | ||
| # Use +rescue BrUtils::Error+ to catch every library error regardless of | ||
| # native ancestry. Domain packages raise their own error hierarchies; | ||
| # this gem only defines the misuse errors it raises itself. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
issue (blocking): Include BrUtils::Error in every re-exported error hierarchy.
Line 6 promises that rescue BrUtils::Error catches every library error. The façade can propagate sibling errors such as CpfFmt::OutOfRangeError and CnpjFmt::ValidationError, but those hierarchies only use their sibling-package markers. Include BrUtils::Error in each exposed sibling Error marker, then add a rescue test for a propagated domain error.
🤖 Prompt for 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.
In `@packages/br-utilities/src/br-utilities/errors.rb` around lines 4 - 8, Update
the exposed sibling error marker modules, including CpfFmt::Error and
CnpjFmt::Error, to include BrUtils::Error so their derived errors are caught by
rescue BrUtils::Error. Add a rescue test covering a propagated domain error such
as CpfFmt::OutOfRangeError or CnpjFmt::ValidationError.
Source: Coding guidelines
| # Placeholder module so the gemspec (and any early require of this file) can read | ||
| # {BrUtils::VERSION}. The gem entry point promotes +BrUtils+ to a class and | ||
| # reopens it for the façade implementation. | ||
| module BrUtils |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
issue (blocking): The BrUtils constant is declared as both a module and a class. version.rb loads first and defines module BrUtils; four façade files then reopen it with class BrUtils. Ruby raises TypeError: BrUtils is not a class on the first such reopening, unless the entry point removes the constant first. Pick one kind for the constant across the package.
packages/br-utilities/src/br-utilities/version.rb#L3-L6: changemodule BrUtilstoclass BrUtilsand update the comment, or document the entry-pointremove_constsequence and confirmVERSIONis re-assigned.packages/br-utilities/src/br-utilities/br_utils.rb#L37-L42: keepclass BrUtilsonly ifversion.rbdeclares the same kind.packages/br-utilities/src/br-utilities/cpf_gen.rb#L3-L3: align the reopening kind with the chosen declaration.packages/br-utilities/src/br-utilities/cpf_utils.rb#L3-L3: align the reopening kind with the chosen declaration.packages/br-utilities/src/br-utilities/cpf_val.rb#L3-L3: align the reopening kind with the chosen declaration.
📍 Affects 5 files
packages/br-utilities/src/br-utilities/version.rb#L3-L6(this comment)packages/br-utilities/src/br-utilities/br_utils.rb#L37-L42packages/br-utilities/src/br-utilities/cpf_gen.rb#L3-L3packages/br-utilities/src/br-utilities/cpf_utils.rb#L3-L3packages/br-utilities/src/br-utilities/cpf_val.rb#L3-L3
🤖 Prompt for 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.
In `@packages/br-utilities/src/br-utilities/version.rb` around lines 3 - 6, The
BrUtils constant is declared with conflicting module and class kinds. In
packages/br-utilities/src/br-utilities/version.rb lines 3-6, declare BrUtils as
a class and update the placeholder comment; keep the class reopening in
packages/br-utilities/src/br-utilities/br_utils.rb lines 37-42, and align the
BrUtils reopenings in packages/br-utilities/src/br-utilities/cpf_gen.rb line 3,
cpf_utils.rb line 3, and cpf_val.rb line 3 with that class declaration.
| context 'when called with a settings Hash' do | ||
| it 'adopts nested domain utils from the Hash' do | ||
| cpf_utils = CpfUtils.new | ||
| cnpj_utils = CnpjUtils.new | ||
| utils = described_class.new({ cpf: cpf_utils, cnpj: cnpj_utils }) | ||
|
|
||
| aggregate_failures do | ||
| expect(utils.cpf).to equal(cpf_utils) | ||
| expect(utils.cnpj).to equal(cnpj_utils) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| context 'when called with a non-Hash settings value' do | ||
| it 'raises TypeMismatchError for a string' do | ||
| expect { described_class.new('not-a-hash') } | ||
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | ||
| end | ||
|
|
||
| it 'raises TypeMismatchError for false' do | ||
| expect { described_class.new(false) } | ||
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | ||
| end | ||
|
|
||
| it 'raises TypeMismatchError for an array' do | ||
| expect { described_class.new([]) } | ||
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | ||
| end | ||
| end |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
suggestion (non-blocking): Add coverage for two documented #initialize contracts.
Two documented behaviors of BrUtils#initialize have no example:
- String-keyed settings.
Helpers.normalize_settingsaccepts'cpf'and'cnpj'(packages/br-utilities/src/br-utilities/br_utils.rblines 62-63). - Flat-keyword precedence. Flat keywords are ignored when the matching
:cpfor:cnpjkeyword is present (documented on lines 129-132 of the same file).
Both are public contracts, so a silent regression would not fail the suite.
💚 Proposed additional examples
context 'when called with a settings Hash' do
it 'adopts nested domain utils from the Hash' do
cpf_utils = CpfUtils.new
cnpj_utils = CnpjUtils.new
utils = described_class.new({ cpf: cpf_utils, cnpj: cnpj_utils })
aggregate_failures do
expect(utils.cpf).to equal(cpf_utils)
expect(utils.cnpj).to equal(cnpj_utils)
end
end
+
+ it 'adopts domain utils from string keys' do
+ cpf_utils = CpfUtils.new
+ cnpj_utils = CnpjUtils.new
+ utils = described_class.new({ 'cpf' => cpf_utils, 'cnpj' => cnpj_utils })
+
+ aggregate_failures do
+ expect(utils.cpf).to equal(cpf_utils)
+ expect(utils.cnpj).to equal(cnpj_utils)
+ end
+ end
+ end
+
+ context 'when a domain keyword and its flat keyword are both given' do
+ it 'ignores the flat keyword' do
+ cpf_utils = CpfUtils.new
+ utils = described_class.new(
+ cpf: cpf_utils,
+ cpf_formatter: CpfFmt::CpfFormatterOptions.new(dash_key: '|')
+ )
+
+ expect(utils.cpf).to equal(cpf_utils)
+ end
end📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| context 'when called with a settings Hash' do | |
| it 'adopts nested domain utils from the Hash' do | |
| cpf_utils = CpfUtils.new | |
| cnpj_utils = CnpjUtils.new | |
| utils = described_class.new({ cpf: cpf_utils, cnpj: cnpj_utils }) | |
| aggregate_failures do | |
| expect(utils.cpf).to equal(cpf_utils) | |
| expect(utils.cnpj).to equal(cnpj_utils) | |
| end | |
| end | |
| end | |
| context 'when called with a non-Hash settings value' do | |
| it 'raises TypeMismatchError for a string' do | |
| expect { described_class.new('not-a-hash') } | |
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | |
| end | |
| it 'raises TypeMismatchError for false' do | |
| expect { described_class.new(false) } | |
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | |
| end | |
| it 'raises TypeMismatchError for an array' do | |
| expect { described_class.new([]) } | |
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | |
| end | |
| end | |
| context 'when called with a settings Hash' do | |
| it 'adopts nested domain utils from the Hash' do | |
| cpf_utils = CpfUtils.new | |
| cnpj_utils = CnpjUtils.new | |
| utils = described_class.new({ cpf: cpf_utils, cnpj: cnpj_utils }) | |
| aggregate_failures do | |
| expect(utils.cpf).to equal(cpf_utils) | |
| expect(utils.cnpj).to equal(cnpj_utils) | |
| end | |
| end | |
| it 'adopts domain utils from string keys' do | |
| cpf_utils = CpfUtils.new | |
| cnpj_utils = CnpjUtils.new | |
| utils = described_class.new({ 'cpf' => cpf_utils, 'cnpj' => cnpj_utils }) | |
| aggregate_failures do | |
| expect(utils.cpf).to equal(cpf_utils) | |
| expect(utils.cnpj).to equal(cnpj_utils) | |
| end | |
| end | |
| end | |
| context 'when a domain keyword and its flat keyword are both given' do | |
| it 'ignores the flat keyword' do | |
| cpf_utils = CpfUtils.new | |
| utils = described_class.new( | |
| cpf: cpf_utils, | |
| cpf_formatter: CpfFmt::CpfFormatterOptions.new(dash_key: '|') | |
| ) | |
| expect(utils.cpf).to equal(cpf_utils) | |
| end | |
| end | |
| context 'when called with a non-Hash settings value' do | |
| it 'raises TypeMismatchError for a string' do | |
| expect { described_class.new('not-a-hash') } | |
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | |
| end | |
| it 'raises TypeMismatchError for false' do | |
| expect { described_class.new(false) } | |
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | |
| end | |
| it 'raises TypeMismatchError for an array' do | |
| expect { described_class.new([]) } | |
| .to raise_error(BrUtils::TypeMismatchError, /settings must be a Hash/) | |
| end | |
| end |
🤖 Prompt for 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.
In `@packages/br-utilities/tests/br_utils.spec.rb` around lines 605 - 633, Add
examples for the two documented BrUtils#initialize contracts in the existing
settings contexts: verify string-keyed settings are normalized and adopt the
provided CpfUtils/CnpjUtils instances, and verify matching nested :cpf or :cnpj
settings take precedence over flat keyword values. Use the existing
Helpers.normalize_settings behavior and preserve the current non-Hash error
coverage.
| > 🚀 **Full support for the [new alphanumeric CNPJ format](https://github.com/user-attachments/files/23937961/calculodvcnpjalfanaumerico.pdf).** | ||
|
|
||
| - **Root**: Tooling (Rake, RuboCop), shared config in `config/gems.yml`, no app code. | ||
| - **Packages**: Under `packages/` — each is a gem (e.g. `cpf-dv`, `cpf-utilities`, `br-utilities`). Internal dependencies use path in development and version constraints when published. | ||
| > 🌎 [Acessar documentação em português](./README.pt.md) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
suggestion (non-blocking): Keep the callout paragraphs in one blockquote.
Each file has a blank line inside the blockquote without a > marker. Add the marker to remove the repeated MD028 warning.
README.md#L10-L12: Add>to the blank line.README.pt.md#L3-L5: Add>to the blank line.packages/br-utilities/README.md#L10-L12: Add>to the blank line.packages/br-utilities/README.pt.md#L3-L5: Add>to the blank line.
Based on the markdownlint MD028 warnings in the supplied static-analysis results.
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 11-11: Blank line inside blockquote
(MD028, no-blanks-blockquote)
📍 Affects 4 files
README.md#L10-L12(this comment)README.pt.md#L3-L5packages/br-utilities/README.md#L10-L12packages/br-utilities/README.pt.md#L3-L5
🤖 Prompt for 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.
In `@README.md` around lines 10 - 12, Add the blockquote marker to the blank line
between callout paragraphs in README.md lines 10-12, README.pt.md lines 3-5,
packages/br-utilities/README.md lines 10-12, and
packages/br-utilities/README.pt.md lines 3-5, keeping each callout in one
continuous blockquote.
Source: Linters/SAST tools
|
|
||
| ### CPF operations | ||
|
|
||
| CPF methods are accessed via `BrUtils.cpf`, `utils.cpf`, `CpfUtils`, or the `CpfFmt` / `CpfGen` / `CpfVal` helpers. CPF uses the API from [`cpf-utilities`](../cpf-utilities/README.md). |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
issue (blocking): Resolve repository-level documentation links from the repository root.
The root READMEs use paths intended for packages/br-utilities/README.md. Update each package README link and the changelog link for the repository-root location.
README.md#L239-L239: Change the CPF package link topackages/cpf-utilities/README.md.README.md#L302-L302: Change the CNPJ package link topackages/cnpj-utilities/README.md.README.md#L471-L471: Correct both bundled-package links.README.md#L643-L643: Correct both propagated-package links.README.md#L683-L684: Correct both table links.README.md#L703-L703: Change the changelog link topackages/br-utilities/CHANGELOG.md.README.pt.md#L232-L232: Change the CPF package link topackages/cpf-utilities/README.pt.md.README.pt.md#L295-L295: Change the CNPJ package link topackages/cnpj-utilities/README.pt.md.README.pt.md#L464-L464: Correct both bundled-package links.README.pt.md#L636-L636: Correct both propagated-package links.README.pt.md#L670-L670: Correct both detailed-package links.README.pt.md#L676-L677: Correct both table links.README.pt.md#L696-L696: Change the changelog link topackages/br-utilities/CHANGELOG.md.
Based on the repository paths in the review context.
🧰 Tools
🪛 LanguageTool
[style] ~239-~239: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...CpfFmt / CpfGen / CpfVal helpers. CPF uses the API from [cpf-utilities](../...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
📍 Affects 2 files
README.md#L239-L239(this comment)README.md#L302-L302README.md#L471-L471README.md#L643-L643README.md#L683-L684README.md#L703-L703README.pt.md#L232-L232README.pt.md#L295-L295README.pt.md#L464-L464README.pt.md#L636-L636README.pt.md#L670-L670README.pt.md#L676-L677README.pt.md#L696-L696
🤖 Prompt for 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.
In `@README.md` at line 239, Update repository-root documentation links to use
package-relative paths: in README.md (239-239) point CPF to
packages/cpf-utilities/README.md, (302-302) CNPJ to
packages/cnpj-utilities/README.md, (471-471) both bundled-package links,
(643-643) both propagated-package links, (683-684) both table links, and
(703-703) the changelog to packages/br-utilities/CHANGELOG.md; apply the
corresponding README.pt.md paths at 232-232, 295-295, 464-464, 636-636, 670-670,
and 676-677, with the changelog at 696-696 pointing to
packages/br-utilities/CHANGELOG.md.
Implements #12.
Summary by CodeRabbit
New Features
Documentation