public/New-TriliumNote.ps1

function New-TriliumNote {
    <#
    .SYNOPSIS
        Creates a new note in Trilium Notes.
 
    .DESCRIPTION
        This function creates a new note in Trilium Notes with the specified content, type, and various formatting options.
        It supports creating different types of notes including text, code, markdown, and special note types like books, canvas, mermaid, etc.
         
        When using the -Markdown parameter, the function converts markdown to HTML before sending to Trilium.
        Code blocks in markdown will be properly formatted with syntax highlighting based on the language specified.
        The function supports mathematical expressions through MathJax when using the -Math switch with -Markdown.
         
        HTML content is beautified before sending to Trilium, ensuring proper spacing and formatting of headings and code blocks.
 
    .PARAMETER ParentNoteId
        The ID of the parent note under which the new note will be created. Defaults to 'root'.
        Use the Get-TriliumNotes function to find IDs of existing notes.
 
        Required? false
        Position? 0
        Default value 'root'
        Accept pipeline input? false
        Accept wildcard characters? false
 
    .PARAMETER Title
        The title of the new note. This will be displayed in the Trilium Notes UI.
 
        Required? false
        Position? 1
        Default value
        Accept pipeline input? false
        Accept wildcard characters? false
 
    .PARAMETER Content
        The content of the new note. This is required.
        For code notes, provide the code as plain text.
        For markdown notes, provide markdown-formatted text.
 
        Required? true
        Position? 2
        Default value
        Accept pipeline input? false
        Accept wildcard characters? false
 
    .PARAMETER NoteType
        The type of note to create. Tab completion is available for common types.
         
        Supported values include:
        - text: Plain text or HTML note (default)
        - markdown: Markdown formatted text note
        - powershell, python, ruby, etc.: Code notes with syntax highlighting
        - book: Special note type for organizing content
        - canvas: Interactive canvas note
        - mermaid: Diagram using Mermaid syntax
        - geoMap, mindMap, relationMap: Special visualization notes
         
        The NoteType parameter has tab completion for all supported note types.
 
        Required? false
        Position? 3
        Default value
        Accept pipeline input? false
        Accept wildcard characters? false
 
    .PARAMETER Mime
        The MIME type of the note content. If not specified, it will be determined based on NoteType.
        Only specify this if you need to override the default MIME type.
 
        Required? false
        Position? 4
        Default value
        Accept pipeline input? false
        Accept wildcard characters? false
 
    .PARAMETER SkipCertCheck
        If specified, certificate validation will be skipped when connecting to Trilium.
        Useful when connecting to Trilium instances with self-signed certificates.
 
        Required? false
        Position? named
        Default value false
        Accept pipeline input? false
        Accept wildcard characters? false
 
    .PARAMETER Markdown
        If specified, the Content will be treated as markdown and converted to HTML.
        When this parameter is used, NoteType must be 'text' or not specified.
        This parameter enables advanced markdown rendering including tables, task lists, and code blocks.
 
        Required? false
        Position? named
        Default value false
        Accept pipeline input? false
        Accept wildcard characters? false
 
    .PARAMETER Math
        If specified, adds support for mathematical expressions in markdown using MathJax.
        This parameter is only used with the -Markdown parameter.
        Math expressions can be included inline using $expression$ syntax or as blocks with $$ syntax.
 
        Required? false
        Position? named
        Default value false
        Accept pipeline input? false
        Accept wildcard characters? false
 
    .INPUTS
        None. You cannot pipe objects to New-TriliumNote.
 
    .OUTPUTS
        System.Management.Automation.PSCustomObject
        Returns the API response from Trilium which includes information about the created note.
 
    .EXAMPLE
        New-TriliumNote -Title "My Note" -Content "This is the content of my note"
 
        Creates a new text note with the specified title and content under the root.
 
    .EXAMPLE
        New-TriliumNote -Title "Code Sample" -Content "Get-Process" -NoteType "powershell"
 
        Creates a new powershell code note with syntax highlighting.
 
    .EXAMPLE
        New-TriliumNote -Title "Markdown Note" -Content "# Header`n`nThis is *markdown* content" -Markdown
 
        Creates a new note by converting the markdown content to HTML.
 
    .EXAMPLE
        New-TriliumNote -Title "Math Example" -Content "When $a \ne 0$, there are two solutions to $ax^2 + bx + c = 0$" -Markdown -Math
 
        Creates a note with markdown content that includes mathematical expressions.
 
    .EXAMPLE
        $parentId = (Get-TriliumNotes -Title "My Folder").noteId
        New-TriliumNote -ParentNoteId $parentId -Title "Nested Note" -Content "This is a nested note"
 
        Creates a new note inside an existing note folder by specifying its ID.
 
    .LINK
        Online version: https://github.com/ptmorris1/TriliumNext-Powershell-Module
 
    .LINK
        Connect-TriliumAuth
 
    .LINK
        Get-TriliumNotes
 
    .NOTES
        Requires connection to Trilium via Connect-TriliumAuth before use.
        Author: P. Morris
        Module: TriliumNext-Powershell-Module
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter()] [string]$ParentNoteId = 'root',
        [Parameter()] [string]$Title,
        [Parameter(Mandatory = $true)] [string]$Content,
        [Parameter()]
        [ArgumentCompleter({
            param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
            $noteTypes = @('image','file','text','book','canvas','mermaid','geoMap','mindMap','relationMap','renderNote','webview',
            'PlainText','CSS','html','http','JSbackend','JSfrontend','json','markdown','powershell','python','ruby','shellBash','sql','sqliteTrilium','xml','yaml')
            
            return $noteTypes | Where-Object { $_ -like "$wordToComplete*" }
        })]
        [string]$NoteType,
        [Parameter()] [string]$Mime,        [Parameter()] [switch]$SkipCertCheck,
        [Parameter()] [switch]$Markdown,
        [Parameter()] [switch]$Math
    )    begin {
        if (!$global:TriliumCreds) { Write-Error -Message 'Need to run: Connect-TriliumAuth'; exit }
        
        # Load the MimeTypeMap JSON directly
        $moduleRoot = $MyInvocation.MyCommand.Module.ModuleBase
        $mimeTypeMapPath = Join-Path -Path $moduleRoot -ChildPath 'data\MimeTypeMap.json'
        
        if (Test-Path -Path $mimeTypeMapPath) {
            $mimeTypeMap = Get-Content -Path $mimeTypeMapPath -Raw | ConvertFrom-Json
        } else {
            Write-Error "MimeTypeMap.json not found at path: $mimeTypeMapPath"
            exit
        }

        if ($Markdown) {
            if ($NoteType -and $NoteType -ne 'text') {
                Write-Error -Message 'If -Markdown is specified, -NoteType must be "text".'
                exit
            }
            $NoteType = 'text'
            $moduleRoot = $MyInvocation.MyCommand.Module.ModuleBase
            $dllPath = Join-Path -Path $moduleRoot -ChildPath 'lib\Markdig.dll'
            if (-not ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.Location -eq (Resolve-Path $dllPath) })) {
                Add-Type -Path $dllPath
            }            $builder = [Markdig.MarkdownPipelineBuilder]::new()
            [Markdig.MarkdownExtensions]::UseAdvancedExtensions($builder) | Out-Null
            if ($Math) {
                [Markdig.MarkdownExtensions]::UseMathematics($builder) | Out-Null
            }
            $pipeline = $builder.Build()
            $html = [Markdig.Markdown]::ToHtml($Content, $pipeline)
            if ($Math) {
                $html = $html.Replace('<span class="math"', '<span class="math-tex"')
                $html = $html.Replace('<div class="math"', '<span class="math-tex"')
            }            # Format code blocks with proper mime types using our unified mapping
            $html = [regex]::Replace($html, '(?i)<pre><code class="language-([a-z0-9+\-]+)">', {
                param($match)
                $lang = $match.Groups[1].Value.ToLower()
                $mimeType = ($mimeTypeMap | Where-Object { $_.Note -eq $lang })?.Mime
                if ($mimeType) {
                    # Use the found mime type from our mapping
                    $formattedMime = $mimeType.Replace('/', '-')
                } elseif ($lang -match '^(html|xml|json|markdown|sql|text|plaintext)$') {
                    $formattedMime = "text-$lang"
                } elseif ($lang -match '^(c|cpp|csharp|java|go|sh|bash|powershell)$') {
                    $formattedMime = "text-x-$lang"
                } else {
                    $formattedMime = "application-x-$lang"
                }                
                "<pre><code class=`"language-$formattedMime`">"
            })
            
            $Content = $html
            # Beautify the HTML content before sending to Trilium
            $Content = Format-TriliumHtml -Content $Content
        }
    }
    process {
        try {
            if ($SkipCertCheck) {
                $PSDefaultParameterValues = @{'Invoke-RestMethod:SkipCertificateCheck' = $true }
            }            $TriliumHeaders = @{ Authorization = "$($TriliumCreds.Authorization)" }
            $uri = "$($TriliumCreds.URL)/create-note"

            $body = @{ parentNoteId = $ParentNoteId }
            if ($Title) { $body.title = $Title }
            if ($Content) { $body.content = $Content }
            if ($Mime) { $body.mime = $Mime }            if ($NoteType) {
                $mimeObj = $mimeTypeMap | Where-Object { $_.Note -eq $NoteType }
                if ($mimeObj) {
                    $body.type = $mimeObj.Type
                    if ($null -ne $mimeObj.Mime -and -not $Mime) {
                        $body.mime = $mimeObj.Mime
                    }
                } else {
                    $body.type = $NoteType
                }
            } elseif (-not $body.ContainsKey('type')) {
                $body.type = 'text'
                if (-not $body.ContainsKey('mime')) { $body.mime = 'text/html' }
            }

            $json = $body | ConvertTo-Json -Depth 5
            if ($PSCmdlet.ShouldProcess($uri, 'Create new note')) {
                Invoke-RestMethod -Uri $uri -Headers $TriliumHeaders -SkipHeaderValidation -ContentType 'application/json' -Body $json -Method Post
            }
        } catch {
            $_.Exception.Response
        }
    }
    end { return }
}