@@ -8,6 +8,15 @@ $CHANGELOG_UNRELEASED_STATUS = "(Unreleased)"
88$CHANGELOG_DATE_FORMAT = " yyyy-MM-dd"
99$RecommendedSectionHeaders = @ (" Features Added" , " Breaking Changes" , " Bugs Fixed" , " Other Changes" )
1010
11+ # Helper function to build the section header regex pattern
12+ function Get-SectionHeaderRegex {
13+ param (
14+ [Parameter (Mandatory = $true )]
15+ [string ]$InitialAtxHeader
16+ )
17+ return " ^${InitialAtxHeader}${SECTION_HEADER_REGEX_SUFFIX} "
18+ }
19+
1120# Returns a Collection of changeLogEntry object containing changelog info for all versions present in the gived CHANGELOG
1221function Get-ChangeLogEntries {
1322 param (
@@ -49,7 +58,7 @@ function Get-ChangeLogEntriesFromContent {
4958 $initialAtxHeader = $matches [" HeaderLevel" ]
5059 }
5160
52- $sectionHeaderRegex = " ^ ${ initialAtxHeader}${SECTION_HEADER_REGEX_SUFFIX} "
61+ $sectionHeaderRegex = Get-SectionHeaderRegex - InitialAtxHeader $ initialAtxHeader
5362 $changeLogEntries | Add-Member - NotePropertyName " InitialAtxHeader" - NotePropertyValue $initialAtxHeader
5463 $releaseTitleAtxHeader = $initialAtxHeader + " #"
5564 $headerLines = @ ()
@@ -301,7 +310,7 @@ function Remove-EmptySections {
301310 $InitialAtxHeader = " #"
302311 )
303312
304- $sectionHeaderRegex = " ^ ${ InitialAtxHeader}${SECTION_HEADER_REGEX_SUFFIX} "
313+ $sectionHeaderRegex = Get-SectionHeaderRegex - InitialAtxHeader $InitialAtxHeader
305314 $releaseContent = $ChangeLogEntry.ReleaseContent
306315
307316 if ($releaseContent.Count -gt 0 )
@@ -460,3 +469,135 @@ function Confirm-ChangeLogForRelease {
460469 }
461470 return $ChangeLogStatus.IsValid
462471}
472+
473+ function Parse-ChangelogContent {
474+ <#
475+ . SYNOPSIS
476+ Parses raw changelog text into structured content with sections.
477+
478+ . DESCRIPTION
479+ Takes raw changelog text and parses it into structured arrays containing
480+ ReleaseContent (all lines) and Sections (organized by section headers).
481+ This function only generates content structure without modifying any files.
482+
483+ . PARAMETER ChangelogText
484+ The new changelog text containing sections (e.g., "### Breaking Changes", "### Features Added").
485+
486+ . PARAMETER InitialAtxHeader
487+ The markdown header level used in the changelog (e.g., "#" for H1, "##" for H2).
488+ Defaults to "#".
489+
490+ . OUTPUTS
491+ PSCustomObject with ReleaseContent and Sections properties.
492+
493+ . EXAMPLE
494+ $content = Parse-ChangelogContent -ChangelogText $changelogText -InitialAtxHeader "#"
495+ $content.ReleaseContent # Array of all lines
496+ $content.Sections # Hashtable of section name to content lines
497+ #>
498+ [CmdletBinding ()]
499+ param (
500+ [Parameter (Mandatory = $true )]
501+ [ValidateNotNullOrEmpty ()]
502+ [string ]$ChangelogText ,
503+
504+ [Parameter (Mandatory = $false )]
505+ [ValidateNotNullOrEmpty ()]
506+ [string ]$InitialAtxHeader = " #"
507+ )
508+
509+ Write-Verbose " Parsing changelog text into structured content..."
510+
511+ # Parse the new changelog content into lines
512+ $changelogLines = $ChangelogText -split " `r ?`n "
513+
514+ # Initialize content structure
515+ $releaseContent = @ ()
516+ $sections = @ {}
517+
518+ # Add an empty line after the version header
519+ $releaseContent += " "
520+
521+ # Parse the changelog content
522+ # InitialAtxHeader represents the markdown header level (e.g., "#" for H1, "##" for H2)
523+ # Section headers are two levels deeper than the changelog title
524+ # (e.g., "### Breaking Changes" if InitialAtxHeader is "#")
525+ $currentSection = $null
526+ $sectionHeaderRegex = Get-SectionHeaderRegex - InitialAtxHeader $InitialAtxHeader
527+
528+ foreach ($line in $changelogLines ) {
529+ if ($line.Trim () -match $sectionHeaderRegex ) {
530+ $currentSection = $matches [" sectionName" ].Trim()
531+ $sections [$currentSection ] = @ ()
532+ $releaseContent += $line
533+ Write-Verbose " Found section: $currentSection "
534+ }
535+ elseif ($currentSection ) {
536+ $sections [$currentSection ] += $line
537+ $releaseContent += $line
538+ }
539+ else {
540+ $releaseContent += $line
541+ }
542+ }
543+
544+ Write-Verbose " Parsed $ ( $sections.Count ) section(s)"
545+
546+ # Return structured content
547+ return [PSCustomObject ]@ {
548+ ReleaseContent = $releaseContent
549+ Sections = $sections
550+ }
551+ }
552+
553+ function Set-ChangeLogEntryContent {
554+ <#
555+ . SYNOPSIS
556+ Updates a changelog entry with new content.
557+
558+ . DESCRIPTION
559+ Takes a changelog entry object and new changelog text, parses the text into
560+ structured content, and updates the entry's ReleaseContent and Sections properties.
561+
562+ . PARAMETER ChangeLogEntry
563+ The changelog entry object to update (from Get-ChangeLogEntries).
564+
565+ . PARAMETER NewContent
566+ The new changelog text containing sections.
567+
568+ . PARAMETER InitialAtxHeader
569+ The markdown header level used in the changelog. Defaults to "#".
570+
571+ . OUTPUTS
572+ The updated changelog entry object.
573+
574+ . EXAMPLE
575+ $entries = Get-ChangeLogEntries -ChangeLogLocation $changelogPath
576+ $entry = $entries["1.0.0"]
577+ Set-ChangeLogEntryContent -ChangeLogEntry $entry -NewContent $newText -InitialAtxHeader $entries.InitialAtxHeader
578+ Set-ChangeLogContent -ChangeLogLocation $changelogPath -ChangeLogEntries $entries
579+ #>
580+ [CmdletBinding ()]
581+ param (
582+ [Parameter (Mandatory = $true )]
583+ [ValidateNotNull ()]
584+ [PSCustomObject ]$ChangeLogEntry ,
585+
586+ [Parameter (Mandatory = $true )]
587+ [ValidateNotNullOrEmpty ()]
588+ [string ]$NewContent ,
589+
590+ [Parameter (Mandatory = $false )]
591+ [ValidateNotNullOrEmpty ()]
592+ [string ]$InitialAtxHeader = " #"
593+ )
594+
595+ # Parse the new content into structured format
596+ $parsedContent = Parse- ChangelogContent - ChangelogText $NewContent - InitialAtxHeader $InitialAtxHeader
597+
598+ # Update the entry with the parsed content
599+ $ChangeLogEntry.ReleaseContent = $parsedContent.ReleaseContent
600+ $ChangeLogEntry.Sections = $parsedContent.Sections
601+
602+ return $ChangeLogEntry
603+ }
0 commit comments