Skip to content

Commit

Permalink
🚀 [Feature]: Add Get-Uri and Test-Uri function (#3)
Browse files Browse the repository at this point in the history
## Description

This pull request includes several improvements and new features to the
URI handling functions and their corresponding tests. The most important
changes include the introduction of new functions, updates to existing
functions, and enhancements to the test coverage.

### New Functions

* Added a new function `Get-Uri` to convert a string into a
`System.Uri`, `System.UriBuilder`, or a normalized URI string.
* Added a new function `Test-Uri` to validate whether a given string is
a valid URI, with an option to allow relative URIs.

### Updates to Existing Functions

* Updated the `ConvertFrom-UriQueryString` function to improve parameter
handling and pipeline support.

### Enhancements to Test Coverage

* Added comprehensive tests for the new `Test-Uri` function, including
various valid and invalid URI scenarios.
* Added tests for the new `Get-Uri` function, covering default behavior,
different output formats, error handling, pipeline input, and edge
cases.

### Configuration Changes:

* Added a new configuration file for the JSCPD linter to set a threshold
of 0 and ignore test files.
* Updated the linter workflow to include JSON validation. 

## Type of change

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [ ] 📖 [Docs]
- [ ] 🪲 [Fix]
- [ ] 🩹 [Patch]
- [ ] ⚠️ [Security fix]
- [x] 🚀 [Feature]
- [ ] 🌟 [Breaking change]

## Checklist

<!-- Use the check-boxes [x] on the options that are relevant. -->

- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
  • Loading branch information
MariusStorhaug authored Feb 9, 2025
1 parent d1fc3c3 commit fca6eb1
Show file tree
Hide file tree
Showing 6 changed files with 426 additions and 9 deletions.
10 changes: 10 additions & 0 deletions .github/linters/.jscpd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"threshold": 0,
"reporters": [
"consoleFull"
],
"ignore": [
"**/tests/*"
],
"absolute": true
}
1 change: 1 addition & 0 deletions .github/workflows/Linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ jobs:
GITHUB_TOKEN: ${{ github.token }}
VALIDATE_MARKDOWN_PRETTIER: false
VALIDATE_YAML_PRETTIER: false
VALIDATE_JSON_PRETTIER: false
10 changes: 3 additions & 7 deletions src/functions/public/ConvertFrom-UriQueryString.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
back to their normal representation.
.EXAMPLE
ConvertFrom-UriQueryString -QueryString 'name=John%20Doe&age=30&age=40'
ConvertFrom-UriQueryString -Query 'name=John%20Doe&age=30&age=40'
Output:
```powershell
Expand All @@ -25,7 +25,7 @@
values are decoded parameter values.
.EXAMPLE
ConvertFrom-UriQueryString '?q=PowerShell%20URI'
'?q=PowerShell%20URI' | ConvertFrom-UriQueryString
Output:
```powershell
Expand All @@ -44,12 +44,11 @@
param(
# The query string to parse. This can include the leading '?' or just the key-value pairs.
# For example, both "?foo=bar&count=10" and "foo=bar&count=10" are acceptable.
[Parameter(Position = 0, ValueFromPipeline)]
[Parameter(ValueFromPipeline)]
[AllowNull()]
[string] $Query
)

# Early exit if $Query is null or empty.
if ([string]::IsNullOrEmpty($Query)) {
Write-Verbose 'Query string is null or empty.'
return @{}
Expand All @@ -60,9 +59,6 @@
if ($Query.StartsWith('?')) {
$Query = $Query.Substring(1)
}
if ([string]::IsNullOrEmpty($Query)) {
return @{} # return empty hashtable if no query present
}

$result = @{}
# Split by '&' to get each key=value pair
Expand Down
134 changes: 134 additions & 0 deletions src/functions/public/Get-Uri.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
function Get-Uri {
<#
.SYNOPSIS
Converts a string into a System.Uri, System.UriBuilder, or a normalized URI string.
.DESCRIPTION
The Get-Uri function processes a string and attempts to convert it into a valid URI.
It supports three output formats: a System.Uri object, a System.UriBuilder object,
or a normalized absolute URI string. If no scheme is present, "http://" is prefixed
to ensure a valid URI. The function enforces mutual exclusivity between the output
format parameters.
.EXAMPLE
Get-Uri -Uri 'example.com'
Output:
```powershell
AbsolutePath : /
AbsoluteUri : http://example.com/
LocalPath : /
Authority : example.com
HostNameType : Dns
IsDefaultPort : True
IsFile : False
IsLoopback : False
PathAndQuery : /
Segments : {/}
IsUnc : False
Host : example.com
Port : 80
Query :
Fragment :
Scheme : http
OriginalString : http://example.com
DnsSafeHost : example.com
IdnHost : example.com
IsAbsoluteUri : True
UserEscaped : False
UserInfo :
```
Converts 'example.com' into a normalized absolute URI string.
.EXAMPLE
Get-Uri -Uri 'https://example.com/path' -AsUriBuilder
Output:
```powershell
Scheme : https
UserName :
Password :
Host : example.com
Port : 443
Path : /path
Query :
Fragment :
Uri : https://example.com/path
```
Returns a [System.UriBuilder] object for the specified URI.
.EXAMPLE
'example.com/path' | Get-Uri -AsString
Output:
```powershell
http://example.com/path
```
Returns a [string] with the full absolute URI.
.LINK
https://psmodule.io/Uri/Functions/Get-Uri
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSReviewUnusedParameter', 'AsString',
Scope = 'Function',
Justification = 'Present for parameter sets'
)]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSReviewUnusedParameter', 'AsUriBuilder',
Scope = 'Function',
Justification = 'Present for parameter sets'
)]
[OutputType(ParameterSetName = 'UriBuilder', [System.UriBuilder])]
[OutputType(ParameterSetName = 'String', [string])]
[OutputType(ParameterSetName = 'AsUri', [System.Uri])]
[CmdletBinding(DefaultParameterSetName = 'AsUri')]
param(
# The string representation of the URI to be processed.
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
[string] $Uri,

# Outputs a System.UriBuilder object.
[Parameter(Mandatory, ParameterSetName = 'AsUriBuilder')]
[switch] $AsUriBuilder,

# Outputs the URI as a normalized string.
[Parameter(Mandatory, ParameterSetName = 'AsString')]
[switch] $AsString
)

process {
$inputString = $Uri.Trim()
if ([string]::IsNullOrWhiteSpace($inputString)) {
throw 'The Uri parameter cannot be null or empty.'
}

# Attempt to create a System.Uri (absolute) from the string
$uriObject = $null
$success = [System.Uri]::TryCreate($inputString, [System.UriKind]::Absolute, [ref]$uriObject)
if (-not $success) {
# If no scheme present, try adding "http://"
if ($inputString -notmatch '^[A-Za-z][A-Za-z0-9+.-]*:') {
$success = [System.Uri]::TryCreate("http://$inputString", [System.UriKind]::Absolute, [ref]$uriObject)
}
if (-not $success) {
throw "The provided value '$Uri' cannot be converted to a valid URI."
}
}

switch ($PSCmdlet.ParameterSetName) {
'AsUriBuilder' {
return ([System.UriBuilder]::new($uriObject))
}
'AsString' {
return ($uriObject.GetComponents([System.UriComponents]::AbsoluteUri, [System.UriFormat]::SafeUnescaped))
}
'AsUri' {
return $uriObject
}
}
}
}
75 changes: 75 additions & 0 deletions src/functions/public/Test-Uri.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
function Test-Uri {
<#
.SYNOPSIS
Validates whether a given string is a valid URI.
.DESCRIPTION
The Test-Uri function checks whether a given string is a valid URI. By default, it enforces absolute URIs.
If the `-AllowRelative` switch is specified, it allows both absolute and relative URIs.
.EXAMPLE
Test-Uri -Uri "https://example.com"
Output:
```powershell
True
```
Checks if `https://example.com` is a valid URI, returning `$true`.
.EXAMPLE
Test-Uri -Uri "invalid-uri"
Output:
```powershell
False
```
Returns `$false` for an invalid URI string.
.EXAMPLE
"https://example.com", "invalid-uri" | Test-Uri
Output:
```powershell
True
False
```
Accepts input from the pipeline and validates multiple URIs.
.OUTPUTS
[System.Boolean]
.NOTES
Returns `$true` if the input string is a valid URI, otherwise returns `$false`.
.LINK
https://psmodule.io/Uri/Functions/Test-Uri
#>
[OutputType([bool])]
[CmdletBinding()]
param(
# Accept one or more URI strings from parameter or pipeline.
[Parameter(Mandatory, ValueFromPipeline)]
[string] $Uri,

# If specified, allow valid relative URIs.
[Parameter()]
[switch] $AllowRelative
)

process {
# If -AllowRelative is set, try to create a URI using RelativeOrAbsolute.
# Otherwise, enforce an Absolute URI.
$uriKind = if ($AllowRelative) {
[System.UriKind]::RelativeOrAbsolute
} else {
[System.UriKind]::Absolute
}

# Try to create the URI. The out parameter is not used.
$dummy = $null
[System.Uri]::TryCreate($Uri, $uriKind, [ref]$dummy)
}
}
Loading

0 comments on commit fca6eb1

Please sign in to comment.