prettier-plugin-sieve
v0.3.0
Published
Prettier plugin for Sieve email filtering scripts (RFC 5228)
Maintainers
Readme
prettier-plugin-sieve
A Prettier plugin for formatting Sieve email filtering scripts (RFC 5228).
Features
- Formats
.sieve/.sivfiles via Prettier - Hand-rolled Peggy.js PEG grammar for RFC 5228 core language
- Supports:
require,if/elsif/else, all standard tests (address,header,envelope,allof,anyof,not,size,exists,true,false), all standard actions (fileinto,redirect,keep,discard,stop,reject,vacation,addflag,setflag,removeflag) - Idempotent — formatting twice gives the same result
- Works with Prettier 3.x
- IntelliJ IDEA + VS Code Prettier extension compatible
Installation
npm install --save-dev prettier prettier-plugin-sieveConfiguration
.prettierrc
{
"plugins": ["prettier-plugin-sieve"]
}VS Code (settings.json)
{
"prettier.documentSelectors": ["**/*.sieve", "**/*.siv"],
"[sieve]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
}IntelliJ IDEA
Go to Settings → Languages & Frameworks → JavaScript → Prettier:
- Enable "Run on save"
- Add
**/*.sieveto the "Run for files" glob
Usage
# Format all .sieve files
npx prettier --write "**/*.sieve"
# Check formatting without writing
npx prettier --check "**/*.sieve"Example
Input (messy):
require ["fileinto","reject","vacation"];
if anyof(header :contains "Subject" "URGENT",address :is "From" "[email protected]"){fileinto "Priority";}
elsif header:contains "Subject" "[SPAM]"{discard;}
else{keep;}Output (formatted):
require ["fileinto", "reject", "vacation"];
if anyof (
header :contains "Subject" "URGENT",
address :is "From" "[email protected]"
) {
fileinto "Priority";
} elsif header :contains "Subject" "[SPAM]" {
discard;
} else {
keep;
}Project Structure
prettier-plugin-sieve/
├── src/
│ ├── index.ts # Plugin entry: languages, parsers, printers
│ ├── types.ts # Full TypeScript AST node interfaces
│ ├── printer.ts # Prettier Doc builder / printer
│ └── parser/
│ ├── index.ts # parse(), locStart(), locEnd() exports
│ └── sieve.pegjs # Peggy PEG grammar for RFC 5228
├── tests/
│ └── format.test.ts # Jest end-to-end formatting tests
├── package.json
└── tsconfig.jsonArchitecture
1 · Grammar (src/parser/sieve.pegjs)
A Peggy PEG grammar that directly encodes RFC 5228 syntax. Each grammar rule returns a typed AST node with a loc (source location) property. The grammar is compiled at runtime the first time parse() is called (or can be pre-compiled via npm run generate-parser for production builds).
2 · Parser adapter (src/parser/index.ts)
Wraps Peggy's parse() to:
- Return a
Scriptroot node - Expose
locStart/locEndso Prettier can attach comments - Surface grammar errors with human-readable messages
3 · Printer (src/printer.ts)
Converts the Sieve AST into Prettier's Doc IR using the doc.builders API:
| Doc primitive | Where used |
| ------------- | -------------------------------------------------------------------- |
| hardline | Between top-level commands and block contents |
| softline | Inside string lists, test argument lists |
| group | All commands and tests — allows line-breaking when over printWidth |
| indent | Block bodies, multi-line list arguments |
| join | Comma-separated string lists and test lists |
Building
# Compile TypeScript → dist/
npm run build
# Optionally pre-compile the Peggy grammar to JS for faster startup
npm run generate-parserTesting
npm testExtending
To add support for Sieve extensions (e.g. RFC 5232 sieve-imap-flags, RFC 5230 vacation):
- Add new rules to
src/parser/sieve.pegjs - Add new AST interfaces to
src/types.ts - Add
casebranches toprintAction/printTestinsrc/printer.ts
License
MIT
