Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions ConvertOneNote2MarkDown-v2.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,24 @@ Describe "Truncate-PathFileName" -Tag 'Unit' {
$path | Truncate-PathFileName -Length $length | Should -Be $expectedPath
}

It "Should keep a given -KeepSuffix when truncating" {
$drive = "C:$( [io.path]::DirectorySeparatorChar )" # E.g. C:\
$path = $drive + ("a" * 1000) + '-1'
$length = 123
$expectedPath = $drive + ("a" * 121) + '-1'

$path | Truncate-PathFileName -Length $length -KeepSuffix '-1' | Should -Be $expectedPath
}

It "Should ignore -KeepSuffix if the filename does not end with it" {
$drive = "C:$( [io.path]::DirectorySeparatorChar )" # E.g. C:\
$path = $drive + ("a" * 1000)
$length = 123
$expectedPath = $drive + ("a" * 123)

$path | Truncate-PathFileName -Length $length -KeepSuffix '-1' | Should -Be $expectedPath
}

}

}
Expand Down Expand Up @@ -833,6 +851,32 @@ Describe 'New-SectionGroupConversionConfig' -Tag 'Unit' {
}
}

It "Should not match an attachment's name inside a longer attachment name" {
Mock Get-OneNotePageContent {
@'
<?xml version="1.0"?>
<one:Page xmlns:one="http://schemas.microsoft.com/office/onenote/2013/onenote" ID="{3D017C7D-F890-4AC8-A094-DEC1163E7B85}{1}{E19461971475288592555920101886406896686096991}" name="p0.0 test">
<one:Outline>
<one:OEChildren>
<one:OE><one:InsertedFile pathCache="c:\cache\a.bin" pathSource="c:\a.pdf" preferredName="11-36-00002.pdf" /></one:OE>
<one:OE><one:InsertedFile pathCache="c:\cache\b.bin" pathSource="c:\b.pdf" preferredName="Datenblatt_11-36-00002.pdf" /></one:OE>
</one:OEChildren>
</one:Outline>
</one:Page>
'@ -as [xml]
}

$pageCfg = @( New-SectionGroupConversionConfig @params 6>$null ) | Select-Object -First 1
$content = '\<\<Datenblatt_11-36-00002.pdf\>\> and \<\<11-36-00002.pdf\>\>'
foreach ($m in ($pageCfg['mutations'] | Where-Object { $_['description'] -eq 'Change inserted attachment(s) filename references' })) {
foreach ($r in $m['replacements']) {
$content = $content -replace $r['searchRegex'], $r['replacement']
}
}

$content | Should -Be "\<\<[Datenblatt_11-36-00002.pdf]($( $pageCfg['mediaPathPandoc'] )/Datenblatt_11-36-00002.pdf)\>\> and \<\<[11-36-00002.pdf]($( $pageCfg['mediaPathPandoc'] )/11-36-00002.pdf)\>\>"
}

It "Should generate fully unique docx file for each page, even for identically-named pages in a section" {
$result = @( New-SectionGroupConversionConfig @params 6>$null )

Expand Down Expand Up @@ -885,6 +929,34 @@ Describe 'New-SectionGroupConversionConfig' -Tag 'Unit' {
}
}

It "Should keep the unique postfix of identically named pages when truncating long names" {
$longName = 'Some long name ' * 20
$fakeHierarchy = @"
<?xml version="1.0"?>
<one:Notebooks xmlns:one="http://schemas.microsoft.com/office/onenote/2013/onenote">
<one:Notebook name="test" nickname="test" ID="{38E47DAB-211E-4EC1-85F1-129656A9D2CE}{1}{B0}" path="https://d.docs.live.net/741e69cc14cf9571/Skydrive Notebooks/test/" lastModifiedTime="2021-08-06T16:27:58.000Z" color="#ADE792">
<one:Section name="s0" ID="{3D017C7D-F890-4AC8-A094-DEC1163E7B85}{1}{B0}" path="https://d.docs.live.net/741e69cc14cf9571/Skydrive Notebooks/test/s0.one" lastModifiedTime="2021-08-06T16:08:25.000Z" color="#8AA8E4">
<one:Page ID="{3D017C7D-F890-4AC8-A094-DEC1163E7B85}{1}{E19461971475288592555920101886406896686096991}" name="$longName" dateTime="2021-08-06T15:36:33.000Z" lastModifiedTime="2021-08-06T16:08:25.000Z" pageLevel="1" />
<one:Page ID="{3D017C7D-F890-4AC8-A094-DEC1163E7B85}{1}{E19461971475288592555920101886406896686096992}" name="$longName" dateTime="2021-08-06T15:36:33.000Z" lastModifiedTime="2021-08-06T16:08:25.000Z" pageLevel="1" />
<one:Page ID="{3D017C7D-F890-4AC8-A094-DEC1163E7B85}{1}{E19461971475288592555920101886406896686096993}" name="$( $longName )differs only after the cut-off" dateTime="2021-08-06T15:36:33.000Z" lastModifiedTime="2021-08-06T16:08:25.000Z" pageLevel="1" />
</one:Section>
</one:Notebook>
</one:Notebooks>
"@ -as [xml]
$params['SectionGroups'] = $fakeHierarchy.Notebooks.Notebook
$params['Config']['mdFileNameAndFolderNameMaxLength']['value'] = 100

$result = @( New-SectionGroupConversionConfig @params 6>$null )

$result.Count | Should -Be 3
$result[1]['fileName'] | Should -Match '-1\.md$'
$result[2]['fileName'] | Should -Match '-2\.md$'
@( $result | ForEach-Object { $_['filePathNormal'] } | Select-Object -Unique ).Count | Should -Be 3
foreach ($pageCfg in $result) {
$pageCfg['fileName'].Length | Should -BeLessOrEqual 100
}
}

It "Should honor config notesdestpath" {
if ($env:OS -match 'windows') {
$params['Config']['notesdestpath']['value'] = 'D:\foo\bar'
Expand Down
36 changes: 25 additions & 11 deletions ConvertOneNote2MarkDown-v2.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@ Function Truncate-PathFileName {
[ValidateRange(0,255)]
[int]
$Length
,
# A suffix (e.g. the '-1' postfix of a duplicate page name) that must survive truncation
[Parameter()]
[string]
$KeepSuffix = ''
)

process {
Expand All @@ -404,7 +409,11 @@ Function Truncate-PathFileName {
$name = Split-Path $Path -Leaf
if ($name.Length -gt $maxLength) {
$parent = Split-Path $Path -Parent
$truncatedName = $name.Substring(0, $maxLength)
$truncatedName = if ($KeepSuffix -and $name.EndsWith($KeepSuffix) -and $maxLength -gt $KeepSuffix.Length) {
$name.Substring(0, $maxLength - $KeepSuffix.Length) + $KeepSuffix
}else {
$name.Substring(0, $maxLength)
}
[io.path]::combine( $parent, $truncatedName )
}else {
$Path
Expand Down Expand Up @@ -800,17 +809,18 @@ Function New-SectionGroupConversionConfig {
$pageCfg['filePathRel'] = & {
$filePathRel = "$( $pageCfg['pagePrefix'] )$( $pageCfg['nameCompat'] )"

# in case multiple pages with the same name exist in a section, postfix the filename
# In case multiple pages with the same name exist in a section, postfix the filename.
# Compare the names as they will be written (truncated to fit '<name>.md'), so two long names that only differ
# after the cut-off are also recognized as duplicates. The postfix is kept when truncating below, so it can't be cut off again.
$pageCfg['filePathRelKey'] = $filePathRel | Truncate-PathFileName -Length ($config['mdFileNameAndFolderNameMaxLength']['value'] - 3)
$recurrence = 0
foreach ($p in $sectionCfg['pages']) {
if ($p['pagePrefix'] -eq $pageCfg['pagePrefix'] -and $p['pathFromRoot'] -eq $pageCfg['pathFromRoot']) {
if ($p['filePathRelKey'] -eq $pageCfg['filePathRelKey']) {
$recurrence++
}
}
if ($recurrence -gt 0) {
$filePathRel = "$filePathRel-$recurrence"
}
$filePathRel | Truncate-PathFileName -Length $config['mdFileNameAndFolderNameMaxLength']['value'] # Truncate to no more than 255 characters so we don't hit the folder name limit on most file systems on Windows / Linux
$pageCfg['filePathRelPostfix'] = if ($recurrence -gt 0) { "-$recurrence" } else { '' }
"$filePathRel$( $pageCfg['filePathRelPostfix'] )" | Truncate-PathFileName -Length $config['mdFileNameAndFolderNameMaxLength']['value'] -KeepSuffix $pageCfg['filePathRelPostfix'] # Truncate to no more than 255 characters so we don't hit the folder name limit on most file systems on Windows / Linux
}
$pageCfg['filePathRelUnderscore'] = $pageCfg['filePathRel'].Replace( [io.path]::DirectorySeparatorChar, '_' )
$pageCfg['filePathNormal'] = & {
Expand All @@ -819,7 +829,7 @@ Function New-SectionGroupConversionConfig {
}else {
[io.path]::combine( $cfg['notesDirectory'], $sectionCfg['nameCompat'], "$( $pageCfg['filePathRel'] )" )
}
"$( $pathWithoutExtension | Truncate-PathFileName -Length ($config['mdFileNameAndFolderNameMaxLength']['value'] - 3) ).md" # Truncate to no more than 255 characters so we don't hit the file name limit on Windows / Linux
"$( $pathWithoutExtension | Truncate-PathFileName -Length ($config['mdFileNameAndFolderNameMaxLength']['value'] - 3) -KeepSuffix $pageCfg['filePathRelPostfix'] ).md" # Truncate to no more than 255 characters so we don't hit the file name limit on Windows / Linux
}
$pageCfg['filePathLong'] = "\\?\$( $pageCfg['filePathNormal'] )" # A non-Win32 path. Prefixing with '\\?\' allows Windows Powershell <= 5 (based on Win32) to support long absolute paths.
$pageCfg['filePath'] = if ($PSVersionTable.PSVersion.Major -le 5) {
Expand Down Expand Up @@ -896,7 +906,9 @@ Function New-SectionGroupConversionConfig {
description = 'Change inserted attachment(s) filename references'
replacements = @(
@{
searchRegex = [regex]::Escape( $attachmentCfg['object'].preferredName )
# Only where the name is not part of a longer file name: with attachments '11-36-00002.pdf' and 'Datenblatt_11-36-00002.pdf'
# on one page, a plain search for the first one also matched inside the second, nesting one link inside the other
searchRegex = '(?<![\w.\-/])' + [regex]::Escape( $attachmentCfg['object'].preferredName ) + '(?![\w.\-])'
replacement = "[$( $attachmentCfg['markdownFileName'] )]($( $pageCfg['mediaPathPandoc'] )/$( $attachmentCfg['markdownFileName'] ))"
}
)
Expand Down Expand Up @@ -1241,11 +1253,13 @@ Function Convert-OneNotePage {
foreach ($image in $images) {
# Rename Image
try {
$newimageName = if ($config['medialocation']['value'] -eq 2) {
# The page-name prefix may contain characters that are valid in file names but break the markdown image link,
# e.g. '#' (read as a URL fragment) or "'" (e.g. from a page named "c't: Newsletter #10"). Strip those, like for inserted attachments.
$newimageName = $( if ($config['medialocation']['value'] -eq 2) {
"$( $pageCfg['filePathRelUnderscore'] )-$($image.BaseName)$($image.Extension)"
}else {
"$( $pageCfg['pathFromRootCompat'] )-$($image.BaseName)$($image.Extension)"
}
} ) | Remove-InvalidFileNameCharsInsertedFiles
$newimagePath = [io.path]::combine( $pageCfg['mediaPath'], $newimageName )
"Moving image: $( $image.FullName ) to $( $newimagePath )" | Write-Verbose
if (!$config['dryRun']['value']) {
Expand Down