aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornatsuoto <[email protected]>2026-07-11 17:38:52 +0530
committernatsuoto <[email protected]>2026-07-11 17:38:52 +0530
commitc7a8a902eb86dfec5dd5c4ec77c532f5b920d3ac (patch)
tree9eaff3968954dc8f5bf079684dba46b6026e2221
parentc7e0fcfbccc3021415a7c5ac170598a7dc6ee7f6 (diff)
downloadedify-c7a8a902eb86dfec5dd5c4ec77c532f5b920d3ac.tar.xz
edify-c7a8a902eb86dfec5dd5c4ec77c532f5b920d3ac.zip
feat(library): add 23 patterns across 12 categories (medical, transport, financial, geo, security, numeric, web, grammar, document, data, contact, software)
-rw-r--r--edify/library/__init__.py45
-rw-r--r--edify/library/contact/__init__.py3
-rw-r--r--edify/library/contact/handle.py20
-rw-r--r--edify/library/data/__init__.py4
-rw-r--r--edify/library/data/orc.py8
-rw-r--r--edify/library/data/parquet.py8
-rw-r--r--edify/library/document/__init__.py4
-rw-r--r--edify/library/document/rtf.py17
-rw-r--r--edify/library/document/tex.py26
-rw-r--r--edify/library/financial/__init__.py5
-rw-r--r--edify/library/financial/routing.py8
-rw-r--r--edify/library/financial/sortcode.py23
-rw-r--r--edify/library/financial/vat.py8
-rw-r--r--edify/library/geo/__init__.py4
-rw-r--r--edify/library/geo/bearing.py33
-rw-r--r--edify/library/geo/mgrs.py33
-rw-r--r--edify/library/grammar/__init__.py3
-rw-r--r--edify/library/grammar/antlr.py26
-rw-r--r--edify/library/medical/__init__.py5
-rw-r--r--edify/library/medical/blood.py21
-rw-r--r--edify/library/medical/dicom.py20
-rw-r--r--edify/library/medical/dosage.py51
-rw-r--r--edify/library/numeric/__init__.py2
-rw-r--r--edify/library/numeric/natural.py8
-rw-r--r--edify/library/security/__init__.py4
-rw-r--r--edify/library/security/nonce.py23
-rw-r--r--edify/library/security/signature.py23
-rw-r--r--edify/library/software/__init__.py2
-rw-r--r--edify/library/software/bump.py22
-rw-r--r--edify/library/transport/__init__.py4
-rw-r--r--edify/library/transport/flight.py18
-rw-r--r--edify/library/transport/plate.py24
-rw-r--r--edify/library/web/__init__.py6
-rw-r--r--edify/library/web/cookie.py28
-rw-r--r--edify/library/web/csp.py43
-rw-r--r--edify/library/web/useragent.py29
36 files changed, 601 insertions, 10 deletions
diff --git a/edify/library/__init__.py b/edify/library/__init__.py
index a115b55..460702b 100644
--- a/edify/library/__init__.py
+++ b/edify/library/__init__.py
@@ -62,6 +62,7 @@ from edify.library.contact import (
address,
email,
fax,
+ handle,
pager,
phone,
username,
@@ -74,6 +75,8 @@ from edify.library.data import (
ini,
json,
msgpack,
+ orc,
+ parquet,
protobuf,
toml,
tsv,
@@ -88,19 +91,23 @@ from edify.library.document import (
pdf,
pptx,
readme,
+ rtf,
svg,
+ tex,
xlsx,
)
-from edify.library.financial import card, crypto, currency, wallet
+from edify.library.financial import card, crypto, currency, routing, sortcode, vat, wallet
from edify.library.geo import (
altitude,
+ bearing,
coordinate,
geohash,
+ mgrs,
place,
plus,
postal,
)
-from edify.library.grammar import abnf, bnf, ebnf, peg, pest
+from edify.library.grammar import abnf, antlr, bnf, ebnf, peg, pest
from edify.library.identifier import (
arn,
asin,
@@ -142,11 +149,12 @@ from edify.library.media import (
regex,
shebang,
)
-from edify.library.medical import medical
+from edify.library.medical import blood, dicom, dosage, medical
from edify.library.numeric import (
fraction,
hash,
integer,
+ natural,
number,
ordinal,
percentage,
@@ -162,12 +170,15 @@ from edify.library.security import (
csr,
der,
keyring,
+ nonce,
pem,
pgp,
+ signature,
ssh,
x509,
)
from edify.library.software import (
+ bump,
cargo,
checksum,
component,
@@ -207,16 +218,19 @@ from edify.library.text import (
unicode,
word,
)
-from edify.library.transport import aircraft, vehicle
+from edify.library.transport import aircraft, flight, plate, vehicle
from edify.library.web import (
apache,
captcha,
+ cookie,
+ csp,
htaccess,
humans,
manifest,
nginx,
robots,
sitemap,
+ useragent,
)
__all__ = [
@@ -227,6 +241,7 @@ __all__ = [
"alpha",
"alphanumeric",
"altitude",
+ "antlr",
"apache",
"apikey",
"arn",
@@ -238,8 +253,11 @@ __all__ = [
"barcode",
"base",
"bearer",
+ "bearing",
"bic",
+ "blood",
"bnf",
+ "bump",
"captcha",
"card",
"cargo",
@@ -251,9 +269,11 @@ __all__ = [
"codec",
"color",
"component",
+ "cookie",
"coordinate",
"cron",
"crypto",
+ "csp",
"csr",
"csrf",
"csv",
@@ -262,12 +282,14 @@ __all__ = [
"date",
"datetime",
"der",
+ "dicom",
"did",
"digest",
"docker",
"docx",
"doi",
"domain",
+ "dosage",
"duration",
"ebnf",
"ein",
@@ -281,6 +303,7 @@ __all__ = [
"fax",
"filename",
"filter",
+ "flight",
"fraction",
"geohash",
"git",
@@ -290,6 +313,7 @@ __all__ = [
"gtin",
"guid",
"hal",
+ "handle",
"hash",
"hdf5",
"hmac",
@@ -324,13 +348,16 @@ __all__ = [
"medical",
"meid",
"mfa",
+ "mgrs",
"mimetype",
"mmsi",
"mnemonic",
"mobi",
"mpn",
"msgpack",
+ "natural",
"nginx",
+ "nonce",
"number",
"numeric",
"oauth",
@@ -338,12 +365,14 @@ __all__ = [
"offset",
"openapi",
"openid",
+ "orc",
"orcid",
"ordinal",
"otp",
"package",
"pager",
"palette",
+ "parquet",
"passkey",
"password",
"path",
@@ -356,6 +385,7 @@ __all__ = [
"phone",
"pin",
"place",
+ "plate",
"plus",
"pmc",
"pmid",
@@ -372,7 +402,9 @@ __all__ = [
"regex",
"robots",
"roman",
+ "routing",
"rss",
+ "rtf",
"saml",
"scientific",
"script",
@@ -381,12 +413,14 @@ __all__ = [
"semver",
"session",
"shebang",
+ "signature",
"signing",
"sitemap",
"sku",
"slug",
"soap",
"socket",
+ "sortcode",
"ssh",
"ssn",
"sso",
@@ -395,6 +429,7 @@ __all__ = [
"svg",
"swagger",
"swatch",
+ "tex",
"time",
"timestamp",
"timezone",
@@ -406,8 +441,10 @@ __all__ = [
"unicode",
"uri",
"url",
+ "useragent",
"username",
"uuid",
+ "vat",
"vehicle",
"version",
"vin",
diff --git a/edify/library/contact/__init__.py b/edify/library/contact/__init__.py
index 58f1017..b4393cd 100644
--- a/edify/library/contact/__init__.py
+++ b/edify/library/contact/__init__.py
@@ -1,8 +1,9 @@
from edify.library.contact.address import address
from edify.library.contact.email import email
from edify.library.contact.fax import fax
+from edify.library.contact.handle import handle
from edify.library.contact.pager import pager
from edify.library.contact.phone import phone
from edify.library.contact.username import username
-__all__ = ["address", "email", "fax", "pager", "phone", "username"]
+__all__ = ["address", "email", "fax", "handle", "pager", "phone", "username"]
diff --git a/edify/library/contact/handle.py b/edify/library/contact/handle.py
new file mode 100644
index 0000000..206ec21
--- /dev/null
+++ b/edify/library/contact/handle.py
@@ -0,0 +1,20 @@
+"""``handle`` — social-media ``@name`` handle shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+handle = (
+ Pattern()
+ .start_of_input()
+ .char("@")
+ .between(1, 30)
+ .any_of()
+ .range("a", "z")
+ .range("A", "Z")
+ .range("0", "9")
+ .char("_")
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a social-media ``@handle`` shape."""
diff --git a/edify/library/data/__init__.py b/edify/library/data/__init__.py
index cea9539..147f2e2 100644
--- a/edify/library/data/__init__.py
+++ b/edify/library/data/__init__.py
@@ -5,6 +5,8 @@ from edify.library.data.html import html
from edify.library.data.ini import ini
from edify.library.data.json import json
from edify.library.data.msgpack import msgpack
+from edify.library.data.orc import orc
+from edify.library.data.parquet import parquet
from edify.library.data.protobuf import protobuf
from edify.library.data.toml import toml
from edify.library.data.tsv import tsv
@@ -19,6 +21,8 @@ __all__ = [
"ini",
"json",
"msgpack",
+ "orc",
+ "parquet",
"protobuf",
"toml",
"tsv",
diff --git a/edify/library/data/orc.py b/edify/library/data/orc.py
new file mode 100644
index 0000000..6c60666
--- /dev/null
+++ b/edify/library/data/orc.py
@@ -0,0 +1,8 @@
+"""``orc`` — Apache ORC file signature shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+orc = Pattern().start_of_input().string("ORC").zero_or_more().any_char().end_of_input()
+"""Callable :class:`Pattern` for an Apache ORC file (``ORC`` magic prefix)."""
diff --git a/edify/library/data/parquet.py b/edify/library/data/parquet.py
new file mode 100644
index 0000000..0d51cfb
--- /dev/null
+++ b/edify/library/data/parquet.py
@@ -0,0 +1,8 @@
+"""``parquet`` — Apache Parquet file signature shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+parquet = Pattern().start_of_input().string("PAR1").zero_or_more().any_char().end_of_input()
+"""Callable :class:`Pattern` for an Apache Parquet file (``PAR1`` magic prefix)."""
diff --git a/edify/library/document/__init__.py b/edify/library/document/__init__.py
index 215845a..4a5142a 100644
--- a/edify/library/document/__init__.py
+++ b/edify/library/document/__init__.py
@@ -5,7 +5,9 @@ from edify.library.document.odt import odt
from edify.library.document.pdf import pdf
from edify.library.document.pptx import pptx
from edify.library.document.readme import readme
+from edify.library.document.rtf import rtf
from edify.library.document.svg import svg
+from edify.library.document.tex import tex
from edify.library.document.xlsx import xlsx
__all__ = [
@@ -16,6 +18,8 @@ __all__ = [
"pdf",
"pptx",
"readme",
+ "rtf",
"svg",
+ "tex",
"xlsx",
]
diff --git a/edify/library/document/rtf.py b/edify/library/document/rtf.py
new file mode 100644
index 0000000..ebaafdf
--- /dev/null
+++ b/edify/library/document/rtf.py
@@ -0,0 +1,17 @@
+"""``rtf`` — Rich Text Format signature shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+rtf = (
+ Pattern()
+ .start_of_input()
+ .string("{\\rtf")
+ .optional()
+ .digit()
+ .zero_or_more()
+ .any_char()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for an RTF document (``{\\rtfN`` prefix)."""
diff --git a/edify/library/document/tex.py b/edify/library/document/tex.py
new file mode 100644
index 0000000..add552b
--- /dev/null
+++ b/edify/library/document/tex.py
@@ -0,0 +1,26 @@
+"""``tex`` — LaTeX / TeX source shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+tex = (
+ Pattern()
+ .start_of_input()
+ .string("\\documentclass")
+ .optional()
+ .group()
+ .char("[")
+ .zero_or_more()
+ .anything_but_chars("]")
+ .char("]")
+ .end()
+ .char("{")
+ .one_or_more()
+ .anything_but_chars("}")
+ .char("}")
+ .zero_or_more()
+ .any_char()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a LaTeX document source (``\\documentclass`` prefix)."""
diff --git a/edify/library/financial/__init__.py b/edify/library/financial/__init__.py
index 9bf261b..ec3f2e8 100644
--- a/edify/library/financial/__init__.py
+++ b/edify/library/financial/__init__.py
@@ -1,6 +1,9 @@
from edify.library.financial.card import card
from edify.library.financial.crypto import crypto
from edify.library.financial.currency import currency
+from edify.library.financial.routing import routing
+from edify.library.financial.sortcode import sortcode
+from edify.library.financial.vat import vat
from edify.library.financial.wallet import wallet
-__all__ = ["card", "crypto", "currency", "wallet"]
+__all__ = ["card", "crypto", "currency", "routing", "sortcode", "vat", "wallet"]
diff --git a/edify/library/financial/routing.py b/edify/library/financial/routing.py
new file mode 100644
index 0000000..2a11763
--- /dev/null
+++ b/edify/library/financial/routing.py
@@ -0,0 +1,8 @@
+"""``routing`` — US ABA routing-number shape (9 digits)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+routing = Pattern().start_of_input().exactly(9).digit().end_of_input()
+"""Callable :class:`Pattern` for a US ABA routing number (9 digits)."""
diff --git a/edify/library/financial/sortcode.py b/edify/library/financial/sortcode.py
new file mode 100644
index 0000000..269a316
--- /dev/null
+++ b/edify/library/financial/sortcode.py
@@ -0,0 +1,23 @@
+"""``sortcode`` — UK sort-code shape (``NN-NN-NN`` or 6 digits)."""
+
+from __future__ import annotations
+
+from edify import Pattern, any_of
+
+_dashed = (
+ Pattern()
+ .start_of_input()
+ .exactly(2)
+ .digit()
+ .char("-")
+ .exactly(2)
+ .digit()
+ .char("-")
+ .exactly(2)
+ .digit()
+ .end_of_input()
+)
+_solid = Pattern().start_of_input().exactly(6).digit().end_of_input()
+
+sortcode = any_of(_dashed, _solid)
+"""Callable :class:`Pattern` for a UK sort code."""
diff --git a/edify/library/financial/vat.py b/edify/library/financial/vat.py
new file mode 100644
index 0000000..faa5882
--- /dev/null
+++ b/edify/library/financial/vat.py
@@ -0,0 +1,8 @@
+"""``vat`` — VAT identification number shape (country prefix + digits)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+vat = Pattern().start_of_input().exactly(2).uppercase().between(6, 12).digit().end_of_input()
+"""Callable :class:`Pattern` for a VAT identification number."""
diff --git a/edify/library/geo/__init__.py b/edify/library/geo/__init__.py
index 624d7b6..1e447bd 100644
--- a/edify/library/geo/__init__.py
+++ b/edify/library/geo/__init__.py
@@ -1,8 +1,10 @@
from edify.library.geo.altitude import altitude
+from edify.library.geo.bearing import bearing
from edify.library.geo.coordinate import coordinate
from edify.library.geo.geohash import geohash
+from edify.library.geo.mgrs import mgrs
from edify.library.geo.place import place
from edify.library.geo.plus import plus
from edify.library.geo.postal import postal
-__all__ = ["altitude", "coordinate", "geohash", "place", "plus", "postal"]
+__all__ = ["altitude", "bearing", "coordinate", "geohash", "mgrs", "place", "plus", "postal"]
diff --git a/edify/library/geo/bearing.py b/edify/library/geo/bearing.py
new file mode 100644
index 0000000..deeb88f
--- /dev/null
+++ b/edify/library/geo/bearing.py
@@ -0,0 +1,33 @@
+"""``bearing`` — compass-bearing shape (0-360 degrees)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+bearing = (
+ Pattern()
+ .start_of_input()
+ .any_of()
+ .subexpression(
+ Pattern().string("360").optional().group().char(".").one_or_more().char("0").end()
+ )
+ .subexpression(
+ Pattern()
+ .any_of()
+ .subexpression(Pattern().char("3").range("0", "5").digit())
+ .subexpression(Pattern().range("1", "2").digit().digit())
+ .subexpression(Pattern().between(1, 2).digit())
+ .end()
+ .optional()
+ .group()
+ .char(".")
+ .one_or_more()
+ .digit()
+ .end()
+ )
+ .end()
+ .optional()
+ .char("°")
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a compass bearing (0-360 degrees)."""
diff --git a/edify/library/geo/mgrs.py b/edify/library/geo/mgrs.py
new file mode 100644
index 0000000..e14322f
--- /dev/null
+++ b/edify/library/geo/mgrs.py
@@ -0,0 +1,33 @@
+"""``mgrs`` — Military Grid Reference System coordinate shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+mgrs = (
+ Pattern()
+ .start_of_input()
+ .between(1, 2)
+ .digit()
+ .any_of()
+ .range("C", "H")
+ .range("J", "N")
+ .range("P", "X")
+ .end()
+ .exactly(2)
+ .uppercase()
+ .any_of()
+ .exactly(2)
+ .digit()
+ .exactly(4)
+ .digit()
+ .exactly(6)
+ .digit()
+ .exactly(8)
+ .digit()
+ .exactly(10)
+ .digit()
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for an MGRS coordinate."""
diff --git a/edify/library/grammar/__init__.py b/edify/library/grammar/__init__.py
index 2b7f067..c31d94b 100644
--- a/edify/library/grammar/__init__.py
+++ b/edify/library/grammar/__init__.py
@@ -1,7 +1,8 @@
from edify.library.grammar.abnf import abnf
+from edify.library.grammar.antlr import antlr
from edify.library.grammar.bnf import bnf
from edify.library.grammar.ebnf import ebnf
from edify.library.grammar.peg import peg
from edify.library.grammar.pest import pest
-__all__ = ["abnf", "bnf", "ebnf", "peg", "pest"]
+__all__ = ["abnf", "antlr", "bnf", "ebnf", "peg", "pest"]
diff --git a/edify/library/grammar/antlr.py b/edify/library/grammar/antlr.py
new file mode 100644
index 0000000..9eb6523
--- /dev/null
+++ b/edify/library/grammar/antlr.py
@@ -0,0 +1,26 @@
+"""``antlr`` — ANTLR grammar-source shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+antlr = (
+ Pattern()
+ .start_of_input()
+ .string("grammar")
+ .one_or_more()
+ .whitespace_char()
+ .letter()
+ .zero_or_more()
+ .any_of()
+ .range("a", "z")
+ .range("A", "Z")
+ .range("0", "9")
+ .char("_")
+ .end()
+ .char(";")
+ .zero_or_more()
+ .any_char()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for an ANTLR grammar source (``grammar Name;`` header + rules)."""
diff --git a/edify/library/medical/__init__.py b/edify/library/medical/__init__.py
index 55f816e..0d1f735 100644
--- a/edify/library/medical/__init__.py
+++ b/edify/library/medical/__init__.py
@@ -1,3 +1,6 @@
+from edify.library.medical.blood import blood
+from edify.library.medical.dicom import dicom
+from edify.library.medical.dosage import dosage
from edify.library.medical.medical import medical
-__all__ = ["medical"]
+__all__ = ["blood", "dicom", "dosage", "medical"]
diff --git a/edify/library/medical/blood.py b/edify/library/medical/blood.py
new file mode 100644
index 0000000..7e05408
--- /dev/null
+++ b/edify/library/medical/blood.py
@@ -0,0 +1,21 @@
+"""``blood`` — ABO/Rh blood-type shape (``A+``, ``AB-``, ``O+``, etc.)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+blood = (
+ Pattern()
+ .start_of_input()
+ .group()
+ .any_of()
+ .string("AB")
+ .char("A")
+ .char("B")
+ .char("O")
+ .end()
+ .end()
+ .any_of_chars("+-")
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for an ABO/Rh blood-type shape."""
diff --git a/edify/library/medical/dicom.py b/edify/library/medical/dicom.py
new file mode 100644
index 0000000..6d80110
--- /dev/null
+++ b/edify/library/medical/dicom.py
@@ -0,0 +1,20 @@
+"""``dicom`` — DICOM UID shape (dotted digits)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+dicom = (
+ Pattern()
+ .start_of_input()
+ .one_or_more()
+ .digit()
+ .one_or_more()
+ .group()
+ .char(".")
+ .one_or_more()
+ .digit()
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a DICOM UID: dotted-integer chain."""
diff --git a/edify/library/medical/dosage.py b/edify/library/medical/dosage.py
new file mode 100644
index 0000000..23df906
--- /dev/null
+++ b/edify/library/medical/dosage.py
@@ -0,0 +1,51 @@
+"""``dosage`` — pharmaceutical dosage shape (``10mg``, ``5.5 ml/kg``)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+
+def _unit() -> Pattern:
+ return (
+ Pattern()
+ .any_of()
+ .string("mg")
+ .char("g")
+ .string("kg")
+ .string("ml")
+ .char("l")
+ .string("mcg")
+ .string("iu")
+ .end()
+ )
+
+
+dosage = (
+ Pattern()
+ .start_of_input()
+ .one_or_more()
+ .digit()
+ .optional()
+ .group()
+ .char(".")
+ .one_or_more()
+ .digit()
+ .end()
+ .optional()
+ .whitespace_char()
+ .subexpression(_unit())
+ .optional()
+ .group()
+ .char("/")
+ .any_of()
+ .string("kg")
+ .string("day")
+ .string("dose")
+ .end()
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a pharmaceutical dosage shape:
+digits with optional decimal + unit (``mg``/``g``/``kg``/``ml``/``l``/``mcg``/``iu``)
+and optional per-``kg``/``day``/``dose`` qualifier.
+"""
diff --git a/edify/library/numeric/__init__.py b/edify/library/numeric/__init__.py
index 1a327ba..d2aba35 100644
--- a/edify/library/numeric/__init__.py
+++ b/edify/library/numeric/__init__.py
@@ -1,6 +1,7 @@
from edify.library.numeric.fraction import fraction
from edify.library.numeric.hash import hash
from edify.library.numeric.integer import integer
+from edify.library.numeric.natural import natural
from edify.library.numeric.number import number
from edify.library.numeric.ordinal import ordinal
from edify.library.numeric.percentage import percentage
@@ -12,6 +13,7 @@ __all__ = [
"fraction",
"hash",
"integer",
+ "natural",
"number",
"ordinal",
"percentage",
diff --git a/edify/library/numeric/natural.py b/edify/library/numeric/natural.py
new file mode 100644
index 0000000..72d1253
--- /dev/null
+++ b/edify/library/numeric/natural.py
@@ -0,0 +1,8 @@
+"""``natural`` — natural-number shape (positive integers, no leading zero)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+natural = Pattern().start_of_input().range("1", "9").zero_or_more().digit().end_of_input()
+"""Callable :class:`Pattern` for a positive integer with no leading zero."""
diff --git a/edify/library/security/__init__.py b/edify/library/security/__init__.py
index f0334f2..8270327 100644
--- a/edify/library/security/__init__.py
+++ b/edify/library/security/__init__.py
@@ -3,8 +3,10 @@ from edify.library.security.certificate import certificate
from edify.library.security.csr import csr
from edify.library.security.der import der
from edify.library.security.keyring import keyring
+from edify.library.security.nonce import nonce
from edify.library.security.pem import pem
from edify.library.security.pgp import pgp
+from edify.library.security.signature import signature
from edify.library.security.ssh import ssh
from edify.library.security.x509 import x509
@@ -14,8 +16,10 @@ __all__ = [
"csr",
"der",
"keyring",
+ "nonce",
"pem",
"pgp",
+ "signature",
"ssh",
"x509",
]
diff --git a/edify/library/security/nonce.py b/edify/library/security/nonce.py
new file mode 100644
index 0000000..20dbcc0
--- /dev/null
+++ b/edify/library/security/nonce.py
@@ -0,0 +1,23 @@
+"""``nonce`` — cryptographic nonce shape (base64/hex-safe alphabet)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+nonce = (
+ Pattern()
+ .start_of_input()
+ .between(16, 256)
+ .any_of()
+ .range("A", "Z")
+ .range("a", "z")
+ .range("0", "9")
+ .char("+")
+ .char("/")
+ .char("=")
+ .char("_")
+ .char("-")
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a cryptographic nonce."""
diff --git a/edify/library/security/signature.py b/edify/library/security/signature.py
new file mode 100644
index 0000000..1a2003e
--- /dev/null
+++ b/edify/library/security/signature.py
@@ -0,0 +1,23 @@
+"""``signature`` — digital-signature payload shape (base64/hex-safe alphabet)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+signature = (
+ Pattern()
+ .start_of_input()
+ .between(64, 4096)
+ .any_of()
+ .range("A", "Z")
+ .range("a", "z")
+ .range("0", "9")
+ .char("+")
+ .char("/")
+ .char("=")
+ .char("_")
+ .char("-")
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a digital-signature payload."""
diff --git a/edify/library/software/__init__.py b/edify/library/software/__init__.py
index aea11f3..b19ef09 100644
--- a/edify/library/software/__init__.py
+++ b/edify/library/software/__init__.py
@@ -1,3 +1,4 @@
+from edify.library.software.bump import bump
from edify.library.software.cargo import cargo
from edify.library.software.checksum import checksum
from edify.library.software.component import component
@@ -12,6 +13,7 @@ from edify.library.software.semver import semver
from edify.library.software.version import version
__all__ = [
+ "bump",
"cargo",
"checksum",
"component",
diff --git a/edify/library/software/bump.py b/edify/library/software/bump.py
new file mode 100644
index 0000000..c213093
--- /dev/null
+++ b/edify/library/software/bump.py
@@ -0,0 +1,22 @@
+"""``bump`` — semver bump keyword shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+bump = (
+ Pattern()
+ .start_of_input()
+ .any_of()
+ .string("major")
+ .string("minor")
+ .string("patch")
+ .string("premajor")
+ .string("preminor")
+ .string("prepatch")
+ .string("prerelease")
+ .string("release")
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a semver bump keyword."""
diff --git a/edify/library/transport/__init__.py b/edify/library/transport/__init__.py
index 0cbd39e..b84fdda 100644
--- a/edify/library/transport/__init__.py
+++ b/edify/library/transport/__init__.py
@@ -1,4 +1,6 @@
from edify.library.transport.aircraft import aircraft
+from edify.library.transport.flight import flight
+from edify.library.transport.plate import plate
from edify.library.transport.vehicle import vehicle
-__all__ = ["aircraft", "vehicle"]
+__all__ = ["aircraft", "flight", "plate", "vehicle"]
diff --git a/edify/library/transport/flight.py b/edify/library/transport/flight.py
new file mode 100644
index 0000000..a14494b
--- /dev/null
+++ b/edify/library/transport/flight.py
@@ -0,0 +1,18 @@
+"""``flight`` — flight-number shape (2-letter airline + 1-4 digits, optional suffix)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+flight = (
+ Pattern()
+ .start_of_input()
+ .exactly(2)
+ .uppercase()
+ .between(1, 4)
+ .digit()
+ .optional()
+ .uppercase()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for an IATA/ICAO flight-number shape."""
diff --git a/edify/library/transport/plate.py b/edify/library/transport/plate.py
new file mode 100644
index 0000000..c97d0b4
--- /dev/null
+++ b/edify/library/transport/plate.py
@@ -0,0 +1,24 @@
+"""``plate`` — vehicle license-plate shape (permissive alphanumeric)."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+plate = (
+ Pattern()
+ .start_of_input()
+ .between(1, 3)
+ .any_of()
+ .range("A", "Z")
+ .range("0", "9")
+ .end()
+ .optional()
+ .any_of_chars("- ")
+ .between(1, 4)
+ .any_of()
+ .range("A", "Z")
+ .range("0", "9")
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a vehicle license-plate shape."""
diff --git a/edify/library/web/__init__.py b/edify/library/web/__init__.py
index 32e29a2..51e7cb9 100644
--- a/edify/library/web/__init__.py
+++ b/edify/library/web/__init__.py
@@ -1,19 +1,25 @@
from edify.library.web.apache import apache
from edify.library.web.captcha import captcha
+from edify.library.web.cookie import cookie
+from edify.library.web.csp import csp
from edify.library.web.htaccess import htaccess
from edify.library.web.humans import humans
from edify.library.web.manifest import manifest
from edify.library.web.nginx import nginx
from edify.library.web.robots import robots
from edify.library.web.sitemap import sitemap
+from edify.library.web.useragent import useragent
__all__ = [
"apache",
"captcha",
+ "cookie",
+ "csp",
"htaccess",
"humans",
"manifest",
"nginx",
"robots",
"sitemap",
+ "useragent",
]
diff --git a/edify/library/web/cookie.py b/edify/library/web/cookie.py
new file mode 100644
index 0000000..6f8e1b7
--- /dev/null
+++ b/edify/library/web/cookie.py
@@ -0,0 +1,28 @@
+"""``cookie`` — HTTP cookie ``name=value`` shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+
+def _value_char() -> Pattern:
+ return Pattern().assert_not_ahead().any_of().whitespace_char().char(";").end().end().any_char()
+
+
+cookie = (
+ Pattern()
+ .start_of_input()
+ .one_or_more()
+ .any_of()
+ .range("a", "z")
+ .range("A", "Z")
+ .range("0", "9")
+ .char("_")
+ .char("-")
+ .end()
+ .char("=")
+ .one_or_more()
+ .subexpression(_value_char())
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for an HTTP ``name=value`` cookie pair."""
diff --git a/edify/library/web/csp.py b/edify/library/web/csp.py
new file mode 100644
index 0000000..449559a
--- /dev/null
+++ b/edify/library/web/csp.py
@@ -0,0 +1,43 @@
+"""``csp`` — Content-Security-Policy directive shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+
+def _directive_value() -> Pattern:
+ return Pattern().assert_not_ahead().char(";").end().any_char()
+
+
+csp = (
+ Pattern()
+ .start_of_input()
+ .one_or_more()
+ .any_of()
+ .range("a", "z")
+ .char("-")
+ .end()
+ .one_or_more()
+ .whitespace_char()
+ .one_or_more()
+ .subexpression(_directive_value())
+ .zero_or_more()
+ .group()
+ .char(";")
+ .zero_or_more()
+ .whitespace_char()
+ .one_or_more()
+ .any_of()
+ .range("a", "z")
+ .char("-")
+ .end()
+ .one_or_more()
+ .whitespace_char()
+ .one_or_more()
+ .subexpression(_directive_value())
+ .end()
+ .optional()
+ .char(";")
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a Content-Security-Policy directive shape."""
diff --git a/edify/library/web/useragent.py b/edify/library/web/useragent.py
new file mode 100644
index 0000000..6996a41
--- /dev/null
+++ b/edify/library/web/useragent.py
@@ -0,0 +1,29 @@
+"""``useragent`` — User-Agent request-header shape."""
+
+from __future__ import annotations
+
+from edify import Pattern
+
+useragent = (
+ Pattern()
+ .start_of_input()
+ .between(4, 1024)
+ .any_of()
+ .range("A", "Z")
+ .range("a", "z")
+ .range("0", "9")
+ .char("/")
+ .char(".")
+ .char("-")
+ .char("(")
+ .char(")")
+ .char(" ")
+ .char(";")
+ .char("+")
+ .char("_")
+ .char(",")
+ .char(":")
+ .end()
+ .end_of_input()
+)
+"""Callable :class:`Pattern` for a permissive User-Agent string."""