Skip to content

Commit 3f1d76b

Browse files
committed
feat: initial ContinuousDelphi.Tools module with Test-NonAsciiContent command
Initial release of the ContinuousDelphi.Tools PowerShell module. Includes: - Test-NonAsciiContent command for detecting non-ASCII characters in files - Comment-based help and documentation - Pester test suite with isolated filesystem tests - Module manifest and auto-loading module structure - CI workflow for automated test execution - Documentation for the command under docs/Tools Repository structure established for future PowerShell tooling.
1 parent f65372c commit 3f1d76b

12 files changed

Lines changed: 877 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
workflow_dispatch:
11+
12+
jobs:
13+
test:
14+
runs-on: ubuntu-slim
15+
permissions:
16+
contents: read
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Install Pester and PSScriptAnalyzer
23+
run: |
24+
pwsh -Command "Install-Module Pester -MinimumVersion 5.7.0 -Force -Scope CurrentUser"
25+
pwsh -Command "Install-Module PSScriptAnalyzer -Force -Scope CurrentUser"
26+
27+
- name: Run tests
28+
run: pwsh tests/run-tests.ps1

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# PowerShell
2+
*.log
3+
*.psd1.lock.json
4+
5+
# OS
6+
.DS_Store
7+
Thumbs.db
8+
9+
# VSCode
10+
.vscode/

README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Continuous-Delphi PowerShell Tools
2+
3+
![Status](https://img.shields.io/badge/status-incubator-orange)
4+
![License](https://img.shields.io/github/license/continuous-delphi/cd-tool-pwsh)
5+
![CI](https://github.com/continuous-delphi/cd-tool-pwsh/actions/workflows/ci.yml/badge.svg)
6+
![Continuous Delphi](https://img.shields.io/badge/org-continuous--delphi-red)
7+
8+
This repository contains PowerShell utilities used across the
9+
**Continuous-Delphi** ecosystem.
10+
11+
The goal of these tools is to support consistent, automated workflows
12+
for maintaining healthy code repositories.
13+
14+
## TL;DR
15+
16+
Quick start:
17+
18+
```powershell
19+
git clone https://github.com/continuous-delphi/cd-tool-pwsh
20+
Import-Module ./src/ContinuousDelphi.Tools
21+
Test-NonAsciiContent -FileSpec *.md -Recurse
22+
```
23+
24+
------------------------------------------------------------------------
25+
26+
# First Tool: Test-NonAsciiContent
27+
28+
The first utility provided by this repository is the PowerShell command:
29+
30+
`Test-NonAsciiContent`
31+
32+
This command scans files for characters outside the ASCII range
33+
(0x00--0x7F) and reports their location.
34+
35+
Detecting non-ASCII characters is useful for:
36+
37+
- preventing encoding problems
38+
- avoiding copy-paste typography issues
39+
- keeping source repositories portable across tools and platforms
40+
- enforcing consistent text standards in long-lived codebases
41+
42+
Typical use cases include:
43+
44+
- validating repository content
45+
- pre-commit checks
46+
- CI pipeline validation
47+
- enforcing ASCII-only policies in source files
48+
49+
Example usage:
50+
51+
``` powershell
52+
Test-NonAsciiContent -Path . -FileSpec *.pas,*.ps1,*.md -Recurse
53+
```
54+
55+
The command returns objects describing each match, allowing results to
56+
be filtered, exported, or inspected using standard PowerShell pipelines.
57+
58+
------------------------------------------------------------------------
59+
60+
# Repository Scope
61+
62+
This repository will contain PowerShell tools that support the
63+
**Continuous-Delphi** ecosystem, including utilities for:
64+
65+
- repository validation
66+
- content linting
67+
- CI workflow helpers
68+
- developer tooling for Delphi projects
69+
70+
Commands in this repository are intended to be:
71+
72+
- PowerShell-native (Verb-Noun)
73+
- pipeline-friendly
74+
- automation-ready
75+
- compatible with PowerShell 7+
76+
77+
------------------------------------------------------------------------
78+
79+
# Installation (Development)
80+
81+
Until a packaged distribution is provided, the module can be loaded
82+
directly from the repository:
83+
84+
``` powershell
85+
Import-Module ./ContinuousDelphi.Tools
86+
```
87+
88+
Once imported, the commands become available in the current session.
89+
90+
---
91+
92+
## Part of Continuous Delphi
93+
94+
This repository follows the `Continuous Delphi` organization taxonomy. See
95+
[cd-meta-org](https://github.com/continuous-delphi/cd-meta-org) for navigation and governance.
96+
97+
- `docs/org-taxonomy.md` -- naming and tagging conventions
98+
- `docs/versioning-policy.md` -- release and versioning rules
99+
- `docs/repo-lifecycle.md` -- lifecycle states and graduation criteria
100+

docs/Tools/Test-NonAsciiContent.md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# Test-NonAsciiContent
2+
3+
## Synopsis
4+
5+
Tests files for characters outside the ASCII range (0x00-0x7F).
6+
7+
## Description
8+
9+
`Test-NonAsciiContent` scans files and reports any lines containing
10+
characters outside the standard ASCII range. This helps detect encoding
11+
issues and unintended characters that may appear from copy/paste
12+
operations, rich text editors, or inconsistent file encodings.
13+
14+
The command returns objects describing each match so that results can be
15+
inspected, filtered, or exported using normal PowerShell pipeline
16+
behavior.
17+
18+
Typical scenarios include:
19+
20+
- repository validation
21+
- CI pipeline checks
22+
- pre-commit validation
23+
- enforcing ASCII-only repository policies
24+
25+
The command is designed to behave like a native PowerShell command and
26+
works well with pipeline input.
27+
28+
------------------------------------------------------------------------
29+
30+
## Syntax
31+
32+
``` powershell
33+
Test-NonAsciiContent [-Path <string>] -FileSpec <string[]> [-Recurse] [-Quiet]
34+
```
35+
36+
``` powershell
37+
Test-NonAsciiContent -InputObject <object[]> [-Quiet]
38+
```
39+
40+
``` powershell
41+
Test-NonAsciiContent -Version
42+
```
43+
44+
------------------------------------------------------------------------
45+
46+
## Parameters
47+
48+
### Path
49+
50+
Directory to search for files.
51+
52+
Defaults to the current working directory if not specified.
53+
54+
### FileSpec
55+
56+
One or more file patterns used to select files to scan.
57+
58+
Multiple patterns may be provided as a comma-separated list.
59+
60+
Example:
61+
62+
``` powershell
63+
-FileSpec *.pas,*.ps1,*.md
64+
```
65+
66+
### Recurse
67+
68+
Optional switch to Search subdirectories recursively.
69+
70+
Defaults to non-recursive search.
71+
72+
### InputObject
73+
74+
Optional parameter to accept pipeline input of file paths or objects
75+
with a `FullName` property, such as those returned by `Get-ChildItem`.
76+
77+
### Quiet
78+
79+
Optional switch to suppresses match output and returns a Boolean value.
80+
81+
Returns:
82+
83+
```text
84+
True - Non-ASCII content detected
85+
False - No non-ASCII content found
86+
```
87+
88+
### Version
89+
90+
Displays the command's current version.
91+
92+
------------------------------------------------------------------------
93+
94+
## Output
95+
96+
By default, the command outputs one object per match with the following
97+
properties:
98+
99+
| Property | Description |
100+
|------------|---------------------------------|
101+
| Path | File path |
102+
| LineNumber | Line containing the match |
103+
| Line | Full line content |
104+
| Match | The first non-ASCII character detected|
105+
106+
Example output object:
107+
108+
``` text
109+
Path : C:\repo\file.md
110+
LineNumber : 12
111+
Line : Example text with smart quote “
112+
Match : “
113+
```
114+
115+
------------------------------------------------------------------------
116+
117+
## Examples
118+
119+
### Scan current repository
120+
121+
``` powershell
122+
Test-NonAsciiContent -FileSpec *.pas,*.ps1,*.md -Recurse
123+
```
124+
125+
### Scan specific directory
126+
127+
``` powershell
128+
Test-NonAsciiContent -Path C:\code -FileSpec *.pas -Recurse
129+
```
130+
131+
### Use pipeline input
132+
133+
``` powershell
134+
Get-ChildItem -Path . -Filter *.md -Recurse |
135+
Test-NonAsciiContent
136+
```
137+
138+
### CI validation example
139+
140+
``` powershell
141+
if (Test-NonAsciiContent -Path . -FileSpec *.pas,*.ps1,*.md -Recurse -Quiet) {
142+
Write-Error "Non-ASCII content detected."
143+
exit 2
144+
}
145+
```
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@{
2+
RootModule = 'ContinuousDelphi.Tools.psm1'
3+
ModuleVersion = '0.1.0'
4+
GUID = '9e6d3f3e-6c6c-4b1c-9c7a-3c4d4c9a7b11'
5+
6+
Author = 'Darian Miller'
7+
CompanyName = 'Continuous-Delphi'
8+
Copyright = '(c) 2026 Continuous-Delphi'
9+
Description = 'PowerShell developer tools used across the Continuous-Delphi ecosystem.'
10+
11+
PowerShellVersion = '7.0'
12+
CompatiblePSEditions = @('Core')
13+
14+
FunctionsToExport = @(
15+
'Test-NonAsciiContent'
16+
)
17+
18+
CmdletsToExport = @()
19+
VariablesToExport = @()
20+
AliasesToExport = @()
21+
22+
PrivateData = @{
23+
PSData = @{
24+
Tags = @(
25+
'continuous-delphi',
26+
'powershell',
27+
'pwsh',
28+
'developer-tools',
29+
'linting',
30+
'ascii',
31+
'encoding'
32+
)
33+
34+
ProjectUri = 'https://github.com/continuous-delphi/cd-tool-pwsh'
35+
LicenseUri = 'https://github.com/continuous-delphi/cd-tool-pwsh/blob/main/LICENSE'
36+
}
37+
}
38+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#requires -Version 7.0
2+
#requires -PSEdition Core
3+
4+
Set-StrictMode -Version Latest
5+
6+
$publicPath = Join-Path $PSScriptRoot 'Public'
7+
$privatePath = Join-Path $PSScriptRoot 'Private'
8+
9+
if (Test-Path -LiteralPath $privatePath -PathType Container) {
10+
$privateScripts = Get-ChildItem -LiteralPath $privatePath -Filter *.ps1 -File |
11+
Sort-Object -Property Name
12+
13+
foreach ($script in $privateScripts) {
14+
. $script.FullName
15+
}
16+
}
17+
18+
if (Test-Path -LiteralPath $publicPath -PathType Container) {
19+
$publicScripts = Get-ChildItem -LiteralPath $publicPath -Filter *.ps1 -File |
20+
Sort-Object -Property Name
21+
22+
foreach ($script in $publicScripts) {
23+
. $script.FullName
24+
}
25+
26+
Export-ModuleMember -Function $publicScripts.BaseName
27+
}
28+
else {
29+
Export-ModuleMember -Function @()
30+
}

src/ContinuousDelphi.Tools/Private/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)