Implement a small feature - #261
Conversation
Implement the "and headers <map>" clause for the respond statement,
allowing WFL programs to send custom HTTP headers in web server responses.
Changes:
- Add `headers` keyword to lexer
- Add `headers: Option<Expression>` to RespondStatement AST
- Update parser to parse "and headers <map_expr>" clause
- Update analyzer to validate headers expression
- Update typechecker to check headers is a map type
- Update interpreter to include headers in HTTP response
- Add parser unit tests for the new syntax
- Fix bug where parse_expression was consuming 'and' as binary operator
(changed to parse_primary_expression for status/content_type/headers)
Syntax: respond to <request> with <content> [and status <code>]
[and content_type <type>] [and headers <map>]
Example:
create map my_headers:
X_Custom_Header is "value"
end map
respond to req with "Hello" and headers my_headers
- debug_report::tests::test_report_failure_message: Skip test when running as root since root can write to read-only directories - interpreter::tests::test_timeout_happy_path: Increase timeout from 1s to 5s and use a simpler test script to avoid flakiness during parallel test execution
|
Claude finished @logbie's task —— View job Pull Request ReviewReviewing the HTTP headers feature implementation for the Review Checklist
Review SummaryThis PR successfully implements custom HTTP headers support for the ✅ Strengths1. Excellent Architecture Consistency
2. Robust Type Safety
3. Comprehensive Parser Implementation
4. Good Test Coverage
|
There was a problem hiding this comment.
Pull request overview
This PR implements support for custom HTTP headers in the respond statement, extending the language's web response capabilities. The feature allows developers to specify custom headers alongside status codes and content types when responding to HTTP requests.
Changes:
- Added
headerskeyword to the lexer and extended therespondstatement syntax to accept an optionalheadersclause - Implemented runtime evaluation of headers expressions in the interpreter, converting map/object values to HTTP headers
- Added static analysis and type checking to validate that headers are provided as map types
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/lexer/token.rs | Added KeywordHeaders token for parsing headers clause |
| src/parser/ast.rs | Extended RespondStatement AST node with optional headers field |
| src/parser/stmt/web.rs | Updated parser to recognize and parse headers clause in respond statements |
| src/parser/tests.rs | Added comprehensive test coverage for respond statements with headers |
| src/analyzer/mod.rs | Added analysis of headers expressions for static analysis |
| src/typechecker/mod.rs | Implemented type checking to validate headers as map types |
| src/interpreter/mod.rs | Implemented runtime evaluation and conversion of headers to HTTP response headers |
| src/interpreter/tests.rs | Improved timeout test reliability for CI environments |
| src/debug_report.rs | Added root user check to skip permission-sensitive test |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Expression::Literal(Literal::Float(n), ..) => n, | ||
| other => panic!("Status should be numeric literal, got: {other:?}"), | ||
| }; | ||
| assert!((status_value - 200.0).abs() < 0.001, "Status should be 200, got: {status_value}"); |
There was a problem hiding this comment.
The magic number 0.001 is used as an epsilon for floating-point comparison without explanation. Consider defining a named constant like const FLOAT_EPSILON: f64 = 0.001; to make the intent clearer and improve maintainability.
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds optional Changes
Sequence DiagramsequenceDiagram
participant Client
participant Lexer
participant Parser
participant Analyzer
participant TypeChecker
participant Interpreter
participant HttpSec as http_security
Client->>Lexer: submit source ("respond ... headers <expr>")
Lexer->>Parser: token stream (includes KeywordHeaders)
Parser->>Analyzer: AST (RespondStatement with headers expr)
Analyzer->>TypeChecker: analyzed AST node
TypeChecker->>Interpreter: type-checked RespondStatement
Interpreter->>Interpreter: evaluate headers expression -> map
Interpreter->>HttpSec: for each (name,value) -> validate_header(name,value)
HttpSec-->>Interpreter: ok / HeaderValidationError
Interpreter->>Client: construct and send HTTP response with validated headers
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 68a12a4dc2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if next_token.token == Token::KeywordStatus { | ||
| self.bump_sync(); // Consume "and" | ||
| self.bump_sync(); // Consume "status" | ||
| status = Some(self.parse_expression()?); | ||
| status = Some(self.parse_primary_expression()?); | ||
| continue; |
There was a problem hiding this comment.
Allow computed status/content_type expressions again
Using parse_primary_expression() for status (and similarly content_type) limits these clauses to atomic values only; any previously valid computed expression (e.g. respond ... and status base_status + 1 or content_type "text/" + subtype) will now fail because the parser stops at the primary and then sees a binary operator. Since status/content_type were parsed with parse_expression() before this change, this is a backward-incompatible regression for programs that build these values dynamically.
Useful? React with 👍 / 👎.
| #[token("status")] | ||
| KeywordStatus, | ||
| #[token("headers")] | ||
| KeywordHeaders, |
There was a problem hiding this comment.
Avoid reserving
headers as a keyword
Adding headers as a lexer keyword makes any existing identifier named headers unparseable (e.g. store headers as ..., display headers, or headers.name), which is a breaking change for prior programs. If headers is only needed as an optional clause after respond, consider treating it like content_type (identifier-based parsing) or allowing KeywordHeaders to be interpreted as an identifier outside the respond clause to preserve backward compatibility.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/interpreter/mod.rs (1)
4312-4464: Prevent hung HTTP requests whenresponderrors mid-wayRight now, any error after extracting
request_id(including the new headers type check) can return early without removing the pending oneshot sender fromself.pending_responses, leaving the warp handler awaiting indefinitely if the interpreter keeps running.Proposed fix: remove the pending sender immediately after request_id extraction
Statement::RespondStatement { request, content, status, content_type, headers, line, column, } => { // Get the request object let request_val = self.evaluate_expression(request, Rc::clone(&env)).await?; let request_id = match &request_val { Value::Object(obj) => { let obj_ref = obj.borrow(); match obj_ref.get("_response_sender") { Some(Value::Text(id)) => id.as_ref().to_string(), _ => { return Err(RuntimeError::new( "Request object missing response sender ID".to_string(), *line, *column, )); } } } _ => { return Err(RuntimeError::new( "Expected request object".to_string(), *line, *column, )); } }; + // Remove sender early so any later error will drop it (unblocks warp receiver) + let sender_arc = { + let mut pending = self.pending_responses.borrow_mut(); + pending.remove(&request_id) + } + .ok_or_else(|| { + RuntimeError::new( + "Request ID not found - response may have already been sent".to_string(), + *line, + *column, + ) + })?; // Evaluate response content let content_val = self.evaluate_expression(content, Rc::clone(&env)).await?; let content_str = match &content_val { Value::Text(text) => text.as_ref().to_string(), Value::Number(n) => n.to_string(), Value::Bool(b) => b.to_string(), _ => format!("{:?}", content_val), }; // ... status/content_type/headers evaluation ... // Create response let response = WflHttpResponse { content: content_str, status: status_code, content_type: content_type_str, headers: headers_map, }; // Send response - let response_sender = { - let mut pending = self.pending_responses.borrow_mut(); - pending.remove(&request_id) - }; - - if let Some(sender_arc) = response_sender { - let mut sender_opt = sender_arc.lock().await; - if let Some(sender) = sender_opt.take() { - if sender.send(response).is_err() { - return Err(RuntimeError::new( - "Failed to send response - client may have disconnected" - .to_string(), - *line, - *column, - )); - } - } else { - return Err(RuntimeError::new( - "Response already sent for this request".to_string(), - *line, - *column, - )); - } - } else { - return Err(RuntimeError::new( - "Request ID not found - response may have already been sent".to_string(), - *line, - *column, - )); - } + let mut sender_opt = sender_arc.lock().await; + if let Some(sender) = sender_opt.take() { + if sender.send(response).is_err() { + return Err(RuntimeError::new( + "Failed to send response - client may have disconnected".to_string(), + *line, + *column, + )); + } + } else { + return Err(RuntimeError::new( + "Response already sent for this request".to_string(), + *line, + *column, + )); + } Ok((Value::Null, ControlFlow::None)) }
♻️ Duplicate comments (1)
src/parser/tests.rs (1)
1543-1595: LGTM! Comprehensive test for all respond options.Good defensive handling of both
Literal::IntegerandLiteral::Floatfor status parsing. The test thoroughly verifies all four optional clauses work together.
🧹 Nitpick comments (1)
src/interpreter/mod.rs (1)
74-79: Consider supporting repeated headers (e.g.,Set-Cookie)
HashMap<String, String>cannot represent multiple values for the same header name, which is commonly needed (Set-Cookie,Warning, etc.). Considerwarp::http::HeaderMap, orVec<(String, String)>to preserve duplicates/order.Also applies to: 4043-4046, 4423-4429
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/analyzer/mod.rssrc/debug_report.rssrc/interpreter/mod.rssrc/interpreter/tests.rssrc/lexer/token.rssrc/parser/ast.rssrc/parser/stmt/web.rssrc/parser/tests.rssrc/typechecker/mod.rs
🧰 Additional context used
📓 Path-based instructions (6)
src/lexer/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
Lexer tokenization must use the Logos crate for high-performance implementation
Use the Logos crate for high-performance tokenization in the Lexer component
Files:
src/lexer/token.rs
**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.rs: Use snake_case for function and file names
Use CamelCase for type and trait names
Use SCREAMING_SNAKE_CASE for constants
Format all Rust code using cargo fmt with .rustfmt.toml configuration
Run cargo clippy with all targets and features with -D warnings flag to enforce linting
**/*.rs: Use snake_case naming convention for functions and file names
Use CamelCase naming convention for types and traits
Use SCREAMING_SNAKE_CASE naming convention for constants
Format all Rust code usingcargo fmt --allas configured in.rustfmt.toml
Ensure all code passescargo clippy --all-targets --all-features -- -D warningslinting checks
Never break backward compatibility with existing WFL programs; all TestPrograms/ must pass after any changes
Review SECURITY.md for security considerations; avoid logging secrets and use zeroization for sensitive data
Files:
src/lexer/token.rssrc/parser/tests.rssrc/interpreter/tests.rssrc/parser/stmt/web.rssrc/analyzer/mod.rssrc/typechecker/mod.rssrc/interpreter/mod.rssrc/parser/ast.rssrc/debug_report.rs
src/parser/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
Parser must use recursive descent pattern with natural language constructs and maintain contextual keyword handling
Implement recursive descent parser with natural language constructs and error recovery, maintaining contextual keyword handling for natural language syntax
Files:
src/parser/tests.rssrc/parser/stmt/web.rssrc/parser/ast.rs
src/interpreter/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
src/interpreter/**/*.rs: Interpreter must be async-capable using Tokio runtime and include subprocess handling with security sanitization
Web server support must be integrated via the warp crate with HTTP request/response handlingImplement async-capable direct AST execution using Tokio runtime, with subprocess handling featuring security sanitization and web server support via warp integration for HTTP request/response handling
Files:
src/interpreter/tests.rssrc/interpreter/mod.rs
src/analyzer/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Implement semantic validation and static analysis in the Analyzer component
Files:
src/analyzer/mod.rs
src/typechecker/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Implement static type analysis with intelligent inference in the Type Checker component
Files:
src/typechecker/mod.rs
🧠 Learnings (7)
📚 Learning: 2026-01-12T16:06:33.931Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T16:06:33.931Z
Learning: Applies to src/lexer/**/*.rs : Lexer tokenization must use the Logos crate for high-performance implementation
Applied to files:
src/lexer/token.rs
📚 Learning: 2026-01-12T16:07:01.897Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T16:07:01.897Z
Learning: Applies to src/lexer/**/*.rs : Use the Logos crate for high-performance tokenization in the Lexer component
Applied to files:
src/lexer/token.rs
📚 Learning: 2026-01-12T16:06:33.931Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T16:06:33.931Z
Learning: Applies to src/interpreter/**/*.rs : Interpreter must be async-capable using Tokio runtime and include subprocess handling with security sanitization
Applied to files:
src/interpreter/tests.rssrc/interpreter/mod.rs
📚 Learning: 2026-01-12T16:07:01.897Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T16:07:01.897Z
Learning: Applies to src/interpreter/**/*.rs : Implement async-capable direct AST execution using Tokio runtime, with subprocess handling featuring security sanitization and web server support via warp integration for HTTP request/response handling
Applied to files:
src/interpreter/tests.rssrc/interpreter/mod.rs
📚 Learning: 2025-08-12T17:35:32.346Z
Learnt from: logbie
Repo: WebFirstLanguage/wfl PR: 150
File: tests/file_io_modes_test.rs:0-0
Timestamp: 2025-08-12T17:35:32.346Z
Learning: In the WFL project tests, file_io_execution_test.rs contains tests that actually execute WFL code through the interpreter and create real files, while file_io_modes_test.rs contains parser-only tests that don't execute code or create files during parsing.
Applied to files:
src/interpreter/tests.rs
📚 Learning: 2026-01-12T16:06:33.931Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T16:06:33.931Z
Learning: Applies to src/interpreter/**/*.rs : Web server support must be integrated via the warp crate with HTTP request/response handling
Applied to files:
src/parser/stmt/web.rssrc/typechecker/mod.rssrc/interpreter/mod.rs
📚 Learning: 2026-01-12T16:07:01.897Z
Learnt from: CR
Repo: WebFirstLanguage/wfl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T16:07:01.897Z
Learning: Applies to src/analyzer/**/*.rs : Implement semantic validation and static analysis in the Analyzer component
Applied to files:
src/analyzer/mod.rs
🔇 Additional comments (9)
src/debug_report.rs (1)
432-436: LGTM! Appropriate root user detection for permission-based test.The approach correctly handles the case where root bypasses filesystem permissions, which would cause false negatives in CI environments running as root (e.g., some Docker containers).
src/analyzer/mod.rs (1)
1362-1385: LGTM! Headers analysis follows established patterns.The
headersfield is correctly integrated into theRespondStatementanalysis, following the same pattern asstatusandcontent_typeoptional fields. The semantic analyzer properly delegates expression analysis without performing type checking (which is handled separately by the typechecker).src/interpreter/tests.rs (1)
131-148: LGTM! Test reliability improvements are well-implemented.Good changes for CI stability:
- Increased timeout (5s) accommodates variable CI load without making the test flaky
- Enhanced error reporting aids debugging when tests fail
- Direct
awaitwith proper error handling is cleaner than the previous approachsrc/parser/ast.rs (1)
437-445: LGTM! AST extension for headers is well-structured.The
headers: Option<Expression>field follows the established pattern for optional response modifiers (status,content_type), maintaining consistency in the AST design. TheExpressiontype allows for dynamic header values that will be evaluated at runtime.src/lexer/token.rs (1)
146-147: LGTM! Token addition follows established patterns.The
KeywordHeaderstoken is correctly added using the Logos crate. Note that there's also aKeywordHeader(singular) at line 357 — this distinction appears intentional (singular for accessing individual headers, plural for the headers map in respond statements).#!/bin/bash # Verify the distinct usage of KeywordHeader vs KeywordHeaders in the parser rg -n -C2 'KeywordHeader[s]?' --type=rust src/parser/src/parser/tests.rs (1)
1501-1541: LGTM! Well-structured test for headers parsing.The test correctly validates parsing of
respondstatement with an optional headers clause. It verifies:
- Content is parsed as string literal
- Headers is parsed as a variable reference
- Status and content_type remain
Nonewhen not specifiedsrc/typechecker/mod.rs (1)
1493-1511: LGTM! Type checking for headers is well-implemented.The validation logic correctly accepts:
- Any
Map<_, _>type (allowing flexibility in key/value types)Unknowntype (for forward compatibility with type inference)Errortype (to avoid cascading errors)The error message clearly states the requirement and provides the ideal
Map<Text, Text>as the expected type.src/parser/stmt/web.rs (1)
103-111: RespondStatement construction includes all fields.The
headersfield is correctly added to the statement constructor alongside existing fields.src/interpreter/mod.rs (1)
4391-4422: Validate and sanitize HTTP headers to prevent response smugglingThe current header handling allows arbitrary hop-by-hop and framing headers (e.g.,
Content-Length,Transfer-Encoding,Connection) without validation. This creates a security risk: if user code setsContent-Lengthwhile the HTTP library also sets one automatically, it results in duplicate headers—a known HTTP response smuggling vector per RFC 7230. Additionally, header names and values are not validated against HTTP syntax rules.Apply the proposed fix:
- Denylist hop-by-hop headers:
content-length,transfer-encoding,connection,keep-alive,proxy-connection,upgrade,te,trailer- Enforce text-only values (reject numbers/booleans converted to strings)
- Validate header names and values using
warp::http::header::{HeaderName, HeaderValue}before insertionAlso applies to: 4423-4429
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
…ment Add comprehensive HTTP header security validation to prevent injection attacks: Security Features: - RFC 7230 token validation for header names (only valid characters) - CRLF injection prevention in header values - Control character rejection (NUL, DEL, etc.) - Header name/value length limits (256/8192 chars) - Forbidden header blocking (Host, Connection, Content-Length, etc.) - Specific error messages identifying which header caused the issue Performance Improvements: - Pre-allocate HashMap with known capacity - Reject invalid value types early with clear error messages New Files: - src/interpreter/http_security.rs: Security validation module with 8 tests - TestPrograms/web_server_custom_headers_demo.wfl: Demo/documentation program
|
Claude finished @logbie's task —— View job Pull Request ReviewReviewing the HTTP headers feature implementation for the Review Checklist
Review SummaryThis PR successfully implements custom HTTP headers support for the ✅ Strengths1. Excellent Architecture Consistency
2. Robust Security Implementation
3. Robust Type Safety
4. Comprehensive Parser Implementation
5. Good Test Coverage
|
|
Claude finished @logbie's task —— View job Pull Request ReviewReviewing the HTTP headers feature implementation for the Review Checklist
Review SummaryThis PR successfully implements custom HTTP headers support for the ✅ Strengths1. Excellent Architecture Consistency
2. Robust Security Implementation
3. Robust Type Safety
4. Comprehensive Parser Implementation
5. Good Test Coverage
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
TestPrograms/web_server_custom_headers_demo.wfl:1
- The header names use underscores (X_Request_ID, X_Api_Version, X_Cache_Control) but HTTP headers conventionally use hyphens (X-Request-ID, X-Api-Version, X-Cache-Control). This inconsistency may confuse users about the expected format.
// Web Server Custom Headers Demo
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let status_value = match status.unwrap() { | ||
| Expression::Literal(Literal::Integer(n), ..) => n as f64, | ||
| Expression::Literal(Literal::Float(n), ..) => n, | ||
| other => panic!("Status should be numeric literal, got: {other:?}"), | ||
| }; |
There was a problem hiding this comment.
The conversion of integer to f64 and subsequent floating-point comparison introduces unnecessary complexity. Consider matching the exact type expected by the parser instead of converting to f64.
| assert!( | ||
| (status_value - 200.0).abs() < 0.001, | ||
| "Status should be 200, got: {status_value}" | ||
| ); |
There was a problem hiding this comment.
Floating-point comparison with epsilon is unnecessarily complex for testing an HTTP status code that should be an exact integer value. Use direct equality check instead.
Added explicit "Before Committing" section requiring Claude to run cargo fmt --all and cargo clippy before every commit.
|
Claude finished @logbie's task —— View job Pull Request ReviewReviewing the HTTP headers feature implementation for the Review Checklist
Review SummaryThis PR successfully implements custom HTTP headers support for the ✅ Strengths1. Excellent Architecture Consistency
2. Robust Security Implementation
3. Robust Type Safety
4. Comprehensive Parser Implementation
5. Good Test Coverage
|
This pull request adds support for custom HTTP headers to the
respondstatement in the language, allowing users to specify headers when sending HTTP responses. The changes include updates to the lexer, parser, interpreter, analyzer, and typechecker to recognize, parse, validate, and process the newheadersclause. Additional tests have been added to ensure correct parsing and evaluation of headers.Language feature: Respond statement with headers
headersclause in therespondstatement, updating the AST (Statement::RespondStatement) and parser logic to recognize and parseheadersas an expression. ([[1]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-b78363c945458ba512de20a9df6c5b2536b373fd115e181701f89ee0e7acf6d3R442),[[2]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-1a22aa23e1f3d8616af9dbbfa59a86c95d9797a9a53eea5220d9063014d7f7d9L57-R63),[[3]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-1a22aa23e1f3d8616af9dbbfa59a86c95d9797a9a53eea5220d9063014d7f7d9L88-R95),[[4]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-1a22aa23e1f3d8616af9dbbfa59a86c95d9797a9a53eea5220d9063014d7f7d9R108),[[5]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-d417470a8403d56521df4a86a0be785c8970dac490fc17e1a06f8da43ea32d91R146-R147))[src/parser/tests.rsR1500-R1595](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-c54f4e08d059f1024ca5e747cbca8619272070de27cfcd4d65ccfa41d951116aR1500-R1595))Interpreter and runtime behavior
headersexpression, validate its type, and include the resulting map in the HTTP response. Returns an error if headers is not a map/object. ([[1]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-849d01a231ce0b9e847a37cad519583e4eb79882965aa20ddef613660222e615R4317),[[2]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-849d01a231ce0b9e847a37cad519583e4eb79882965aa20ddef613660222e615R4391-R4428))Static analysis and type checking
headersexpression (if provided) is a map type, reporting a type error if not. ([[1]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-32ee40a5078f81e665bed3ef43709b58a5aa576c42483732747f804c78dc6113R1444),[[2]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-32ee40a5078f81e665bed3ef43709b58a5aa576c42483732747f804c78dc6113R1493-R1511))headersexpression for static analysis. ([[1]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-b25b8464bbe8a4f9efde0cd9035c9235affa56fc190f1bb625aa133a67ccb17cR1367),[[2]](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-b25b8464bbe8a4f9efde0cd9035c9235affa56fc190f1bb625aa133a67ccb17cR1381-R1384))Testing and CI improvements
[src/interpreter/tests.rsL133-R147](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-4a6142a72fb984c1e582e2b3ec14e730c62cce1dc523c07bf67640084ce766f3L133-R147))[src/debug_report.rsR432-R437](https://github.com/WebFirstLanguage/wfl/pull/261/files#diff-b3029fb5dbaca31f91ae5c3cd9b4cb5808891beee31ea3cee33cdb03857ab342R432-R437))Summary by CodeRabbit
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.