Skip to content

Commit aa49e16

Browse files
Jeremiclaude
andcommitted
docs: add comprehensive Programs concept page
- Create programs.md with detailed coverage of: - Program structure and components - Target types (individual vs group) - Program managers and their roles - Program lifecycle (active/ended) - Membership states and transitions - Key operations (import, verify, enroll, deduplicate) - Entitlements and their states - Common program types (UCT, CCT, emergency, agricultural) - Data model overview with mermaid ER diagram - Troubleshooting FAQ - Restore cel_lexer.py extension (was accidentally deleted) - Add _ext directory to sys.path in conf.py for custom extensions Content based on V2 spp_programs module code for accuracy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ddcf7f5 commit aa49e16

File tree

3 files changed

+565
-3
lines changed

3 files changed

+565
-3
lines changed

docs/_ext/cel_lexer.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
"""
2+
CEL (Common Expression Language) Pygments Lexer for OpenSPP
3+
4+
This lexer provides syntax highlighting for CEL expressions used in OpenSPP
5+
eligibility rules, entitlement formulas, and other configuration expressions.
6+
7+
Based on the CodeMirror implementation in spp_cel_widget.
8+
"""
9+
10+
from pygments.lexer import RegexLexer, bygroups, words
11+
from pygments.token import (
12+
Comment,
13+
Keyword,
14+
Name,
15+
Number,
16+
Operator,
17+
Punctuation,
18+
String,
19+
Text,
20+
Whitespace,
21+
)
22+
23+
__all__ = ["CelLexer"]
24+
25+
26+
class CelLexer(RegexLexer):
27+
"""
28+
Lexer for CEL (Common Expression Language) expressions.
29+
30+
CEL is used in OpenSPP for eligibility rules and entitlement formulas.
31+
"""
32+
33+
name = "CEL"
34+
aliases = ["cel"]
35+
filenames = ["*.cel"]
36+
mimetypes = ["text/x-cel"]
37+
38+
# CEL keywords
39+
keywords = (
40+
"and",
41+
"or",
42+
"not",
43+
"in",
44+
)
45+
46+
# Boolean and null literals
47+
constants = (
48+
"true",
49+
"false",
50+
"null",
51+
)
52+
53+
# CEL built-in functions from OpenSPP
54+
builtins = (
55+
"age_years",
56+
"today",
57+
"now",
58+
"days_ago",
59+
"months_ago",
60+
"years_ago",
61+
"between",
62+
"exists",
63+
"count",
64+
"head",
65+
"has_role",
66+
"contains",
67+
"startswith",
68+
"endswith",
69+
"metric",
70+
"program",
71+
"has_tag",
72+
"date",
73+
"days_since",
74+
"hours_since",
75+
"is_business_day",
76+
"min",
77+
"max",
78+
"sum",
79+
"avg",
80+
"abs",
81+
"size",
82+
"matches",
83+
"filter",
84+
"map",
85+
"all",
86+
"exists_one",
87+
"type",
88+
"string",
89+
"int",
90+
"uint",
91+
"double",
92+
"bool",
93+
"duration",
94+
"timestamp",
95+
)
96+
97+
tokens = {
98+
"root": [
99+
# Whitespace
100+
(r"\s+", Whitespace),
101+
# Comments (// style)
102+
(r"//.*$", Comment.Single),
103+
# Strings (double-quoted)
104+
(r'"', String.Double, "string-double"),
105+
# Strings (single-quoted)
106+
(r"'", String.Single, "string-single"),
107+
# Numbers (integers and floats)
108+
(r"-?\d+\.\d+", Number.Float),
109+
(r"-?\d+", Number.Integer),
110+
# Boolean and null constants
111+
(words(constants, suffix=r"\b"), Keyword.Constant),
112+
# Keywords
113+
(words(keywords, suffix=r"\b"), Keyword),
114+
# Built-in functions (followed by parenthesis)
115+
(
116+
r"(" + "|".join(builtins) + r")(\s*)(\()",
117+
bygroups(Name.Builtin, Whitespace, Punctuation),
118+
),
119+
# Function calls (identifier followed by parenthesis)
120+
(r"([a-zA-Z_][a-zA-Z0-9_]*)(\s*)(\()", bygroups(Name.Function, Whitespace, Punctuation)),
121+
# Property access (after dot)
122+
(r"(\.)([a-zA-Z_][a-zA-Z0-9_]*)", bygroups(Punctuation, Name.Attribute)),
123+
# Comparison operators (must be before single char operators)
124+
(r"==|!=|>=|<=|&&|\|\|", Operator),
125+
# Single char operators
126+
(r"[<>=!+\-*/%]", Operator),
127+
# Punctuation
128+
(r"[.,\(\)\[\]\{\}:]", Punctuation),
129+
# Identifiers (variables)
130+
(r"[a-zA-Z_][a-zA-Z0-9_]*", Name.Variable),
131+
# Catch-all for other characters
132+
(r".", Text),
133+
],
134+
"string-double": [
135+
(r'\\[\\"]', String.Escape),
136+
(r'[^"\\]+', String.Double),
137+
(r'"', String.Double, "#pop"),
138+
],
139+
"string-single": [
140+
(r"\\[\\']", String.Escape),
141+
(r"[^'\\]+", String.Single),
142+
(r"'", String.Single, "#pop"),
143+
],
144+
}
145+
146+
147+
def setup(app):
148+
"""
149+
Sphinx extension setup function.
150+
151+
Registers the CEL lexer with Pygments so it can be used in code blocks.
152+
"""
153+
from sphinx.highlighting import lexers
154+
155+
lexers["cel"] = CelLexer(startinline=True)
156+
157+
return {
158+
"version": "1.0",
159+
"parallel_read_safe": True,
160+
"parallel_write_safe": True,
161+
}

docs/conf.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020
# add these directories to sys.path here. If the directory is relative to the
2121
# documentation root, use os.path.abspath to make it absolute, like shown here.
2222
#
23-
# import os
24-
# import sys
25-
# sys.path.insert(0, os.path.abspath("."))
23+
# Add _ext directory to sys.path for custom extensions (e.g., cel_lexer)
24+
sys.path.insert(0, os.path.abspath("_ext"))
2625

2726

2827

0 commit comments

Comments
 (0)