Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: [StartAutomating]
501 changes: 501 additions & 0 deletions .github/workflows/BuildMathML.yml

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions Build/GitHub/Jobs/BuildMathML.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@{
"runs-on" = "ubuntu-latest"
if = '${{ success() }}'
steps = @(
@{
name = 'Check out repository'
uses = 'actions/checkout@main'
},
'RunEZOut' # ,
<#@{
name = 'Run MathML (on branch)'
if = '${{github.ref_name != ''main''}}'
uses = './'
id = 'MathMLAction'
}#>
# 'BuildAndPublishContainer'
)
}
10 changes: 10 additions & 0 deletions Build/GitHub/Steps/PublishTestResults.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@{
name = 'PublishTestResults'
uses = 'actions/upload-artifact@main'
with = @{
name = 'PesterResults'
path = '**.TestResults.xml'
}
if = '${{always()}}'
}

15 changes: 15 additions & 0 deletions Build/MathML.GitHubWorkflow.PSDevOps.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#requires -Module PSDevOps
Import-BuildStep -SourcePath (
Join-Path $PSScriptRoot 'GitHub'
) -BuildSystem GitHubWorkflow

Push-Location ($PSScriptRoot | Split-Path)
New-GitHubWorkflow -Name "Build MathML Module" -On Push,
PullRequest,
Demand -Job TestPowerShellOnLinux,
TagReleaseAndPublish, BuildMathML -Environment ([Ordered]@{
REGISTRY = 'ghcr.io'
IMAGE_NAME = '${{ github.repository }}'
}) -OutputPath .\.github\workflows\BuildMathML.yml

Pop-Location
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## MathML 0.1

* Initial release of MathML (#1)
* Core Commands:
* Get-MathML (#2)
* Export-MathML (#3)
* Import-MathML (#4)
* Extended Types
* `MathML.get_SVG` (#5)
* `MathML.ToString()` (#8)
* `MathML.get/set_ID` (#9)
* MathML schemas included (#7)
* Initial Workflow (#6)
102 changes: 102 additions & 0 deletions Commands/Export-MathML.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
function Export-MathML {
<#
.SYNOPSIS
Exports MathML
.DESCRIPTION
Exports MathML into a file
.EXAMPLE
MathML https://dlmf.nist.gov/2.1 |
Export-MathML ./dlmf.2.1.html
#>
[Alias('Save-MathML')]
param(
# The export file path.
[Parameter(Mandatory)]
[Alias('Fullname')]
[string]
$FilePath,

# Any input objects.
[Parameter(ValueFromPipeline)]
[PSObject[]]
$InputObject,

# If set, will force an export, even if a file already exists.
[switch]
$Force
)

# Gather all the input
$allInput = @($input)

# If nothing was passed
if ($allInput.Length -eq 0) {
# briefly check for non-piped -InputObject
if ($PSBoundParameters.InputObject) {
$allInput = @($PSBoundParameters.InputObject | . { process { $_ } })
}
# If we still have no input, return (there is nothing to export)
if ($allInput.Length -eq 0) {return}
}

# Find the full path, but do not resolve it
$unresolvedPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($FilePath)
# If it already existed, and we are not using the `-Force`
if ((Test-Path $unresolvedPath) -and -not $Force) {
# write an error
Write-Error "$unresolvedPath already exists, use -Force"
# and return
return
}


# IF we have one MathML
if ($allInput.Length -eq 1 -and $allInput[0] -is [xml]) {
# save that to a file
$newFile = New-Item -Path $unresolvedPath -Force -ItemType File
# If the extension was .svg or .html, and the input has an SVG
if ($newFile.Extension -in '.svg', '.html' -and $allInput[0].SVG -is [xml]) {
# save the SVG to the file
$allInput[0].SVG.Save($newFile.FullName)
} else {
# otherwise, save the XML to the file
$allInput[0].Save($newFile.FullName)
}
}
# If we have multiple MathML
else {
# we can store them in an XHTML file
$html = @(
# construct a simple header
"<html><title>MathML</title><body>"
foreach ($in in $allInput) {
# and put each MathML within a div
"<div>"

# If it was XML
if ($in -is [xml]) {
$in.OuterXml # put it inline
}
# If there was a SVG property
elseif ($in.SVG) {
# put that inline
$in.SVG.OuterXml
}
# If there was a HTML property
elseif ($in.HTML) {
# put that inline (if it was unbalanced, export will not work)
$in.HTML
}
# last but not least, escape any text
else {
[Security.SecurityElement]::Escape("$in")
}
"</div>"
}
"</body></html>"
) -join [Environment]::NewLine

# Create a new file containing the HTML
New-Item -Path $unresolvedPath -Force -ItemType File -Value $html
}
}
140 changes: 140 additions & 0 deletions Commands/Get-MathML.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
function Get-MathML
{
<#
.SYNOPSIS
Gets MathML
.DESCRIPTION
Gets MathML from a file or page
.EXAMPLE
MathML https://dlmf.nist.gov/2.1
.EXAMPLE
MathML 'https://en.wikipedia.org/wiki/Rose_(mathematics)'
.EXAMPLE
MathML "<math xmlns='http://www.w3.org/1998/Math/MathML'>
<semantics>
<mrow>
<mn>1</mn>
<mo>+</mo>
<mn>1</mn>
<mo>=</mo>
<mn>2</mn>
</mrow>
</semantics>
</math>"
#>
[Alias('MathML')]
param(
# A url or file path that hopefully contains MathML
# The response from this URL will be cached.
[Parameter(ValueFromPipelineByPropertyName)]
[Alias('Uri','FilePath','Fullname')]
[string]
$Url,

# If set, will request the URL, even if it has been cached.
[Parameter(ValueFromPipelineByPropertyName)]
[switch]
$Force,

# If set, will use chromium to request the page, and will
[Parameter(ValueFromPipelineByPropertyName)]
[switch]
$UseChromium,

# The path to a chromium browser.
[Parameter(ValueFromPipelineByPropertyName)]
[string]
$ChromiumPath = 'chromium'
)

begin {
if (-not $script:MathMLCache) {
$script:MathMLCache = [Ordered]@{}
}

$mathMlPattern = [Regex]::new('<math[\s\S]+?</math>','IgnoreCase')
}

process {
# If we have no URL
if (-not $PSBoundParameters.Url) {
# get any loaded MathML
$mathMLValues = @($script:MathMLCache.Values.MathML)
if ($mathMLValues) {
# unroll each result
foreach ($value in $mathMLValues) {
if (-not $value) { continue }
# and return non-null values
$value
}
}
return
}

# If we have not yet cached this URL, or we are using the `-Force`
if (-not $script:MathMLCache["$url"] -or $Force) {
# Create a cache object
$script:MathMLCache["$url"] = [Ordered]@{
Response =
# If the URL could be XML
if ($url -as [xml]) {
# use that as the source.
($url -as [xml]).OuterXml
}
# If the URL was actually a file path
elseif (Test-Path $url)
{
# get it's content.
Get-Content -Raw $Url
}
# If we are not using chromium,
elseif (-not $UseChromium)
{
# use Invoke-RestMethod to get the URL
Invoke-RestMethod $url
}
# If we are using chromium
else
{
# Call chromium in headless mode and dump DOM
& $ChromiumPath --headless --disable-gpu --no-sandbox --dump-dom "$url" *>&1 |
# strip out any chromium trace messages
Where-Object { $_ -notmatch '^\[\d+:\d+' } |
# and stringify the whole response.
Out-String -Width 1mb
}
}
}

# If we have a response for this URL, but no MathML yet
if (
$script:MathMLCache["$url"].Response -and -not
$script:MathMLCache["$url"].MathML
) {
$script:MathMLCache["$url"].MathML =
# find any matches for our pattern
@(foreach ($match in $mathMlPattern.Matches("$(
$script:MathMLCache["$url"].Response
)")) {
# and cast them into XML.
$matchXml = $match.Value -as [xml]

if (-not $matchXML) { continue }
# If they do not have the xml namespace
if (-not $matchXML.math.xmlns) {
# add it
$matchXML.math.setAttribute('xmlns', 'http://www.w3.org/1998/Math/MathML')
}
# decorate the return as MathML
$matchXml.pstypenames.insert(0, 'MathML')
# and output it to the cache
$matchXml
})

}

# Last but not least, output any MathML objects in the cache for this URL.
$script:MathMLCache["$url"].MathML
}
}

24 changes: 24 additions & 0 deletions Commands/Import-MathML.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function Import-MathML
{
<#
.SYNOPSIS
Imports MathML
.DESCRIPTION
Imports MathML from a file or URL
.LINK
Get-MathML
#>
[Alias('Restore-MathML')]
param(
# The path to a file or URL that hopefully contains MathML
[Parameter(Mandatory,ValueFromPipelineByPropertyName)]
[string]
$FilePath
)

process {
# This is an extremely light wrapper of Get-MathML.
Get-MathML @PSBoundParameters
}

}
Loading
Loading