Conversation
Changes Made crates/compiler/src/resolver.rs: 1. Added project_root: Option<PathBuf> field to the Resolver struct 2. Set project_root on the first resolve() call (main source file's directory) 3. Removed the early rejection of paths containing .. 4. Changed the containment check from source_dir to project_root - this allows cross-directory includes like include "../src/lib/helper" as long as the resolved path stays within the project root crates/compiler/Cargo.toml: - Added tempfile as a dev-dependency for testing New tests added: - test_cross_directory_include_allowed - verifies .. paths work within project - test_cross_directory_include_outside_project_rejected - verifies .. paths escaping the project root are rejected - test_project_root_set_on_first_resolve - verifies project root is set correctly - test_dotdot_within_same_directory_structure - verifies deep paths with .. work The fix enables the SeqLisp use case from issue #102 where tests can include source files from sibling directories: project/ src/ tokenizer.seq tests/ test.seq ← can now do: include "../src/tokenizer"
PR Review: Issue #102 - Cross-Directory Include SupportSummaryThis PR successfully addresses issue #102 by allowing include paths with Code Quality ✅Strengths
Minor Suggestionsresolver.rs:336-337 - Fallback logic could be simplified: // Current:
let source_dir_buf = source_dir.to_path_buf();
let root = self.project_root.as_ref().unwrap_or(&source_dir_buf);
// Consider:
let root = self.project_root.as_ref().unwrap_or(source_dir);This avoids the temporary allocation since Security Review 🔒Excellent Security Practices
Security Considerations ✅
No security concerns identified. Potential Bugs 🔍Edge Case: First File in Non-Existent Directoryresolver.rs:86-89 - If let source_dir = source_path.parent().ok_or_else(||
format!("Source path '{}' has no parent directory", source_path.display())
)?;However, this is likely academic since Edge Case: Empty Relative PathWhat happens with if rel_path.is_empty() {
return Err("Include path cannot be empty".to_string());
}Question: Absolute Path Error Messageresolver.rs:314 - The error says "paths cannot be absolute" but the documentation (INCLUDE_SYSTEM.md:39) says "No absolute paths allowed". Consider being more specific about why: "Include path '{}' is invalid: relative paths only (absolute paths not supported)"Performance Considerations ⚡Minor Performance Notes
No performance concerns for typical use cases. Test Coverage ✅Excellent Test CoverageThe 4 new tests cover:
Additional Test Suggestions
#[test]
fn test_symlink_escape_blocked() {
// Create project/link -> /tmp/outside
// Verify include via symlink is blocked
}
#[test]
fn test_project_at_filesystem_root() {
// Verify behavior when project_root is filesystem root
}
#[test]
fn test_dotslash_and_dotdot_normalization() {
// include "./foo" and "bar/../baz"
}
#[test]
fn test_error_message_shows_resolved_path() {
// When blocked, error should show what the path resolved to
}Architectural Considerations 🏗️Design Questions
Documentation 📚Suggestions
## Rules
3. **Quoted string** - Path relative to the including file
- No absolute paths allowed
- Paths can use `..` to reference parent directories
- All resolved paths must stay within the project root
- Example: `include "../src/lib/helpers"` (from tests directory)
Alignment with Issue #102 ✅The implementation perfectly addresses the issue:
RecommendationAPPROVE with minor suggestions ✅ This is a well-implemented feature with excellent test coverage. The security model is sound, the code is clean, and it solves the stated problem. The suggestions above are minor improvements, not blockers. Before Merge
Great work! This significantly improves the developer experience for organizing patch-seq projects. Review generated with assistance from Claude Code |
Agreed and implemented:
1. Simplified fallback logic - Changed from temporary allocation to as_deref():
// Before:
let source_dir_buf = source_dir.to_path_buf();
let root = self.project_root.as_ref().unwrap_or(&source_dir_buf);
// After:
let root = self.project_root.as_deref().unwrap_or(source_dir);
2. Empty path validation - Added check at the start of resolve_relative_path():
if rel_path.is_empty() {
return Err("Include path cannot be empty".to_string());
}
3. Documentation update - Updated docs/INCLUDE_SYSTEM.md:
- Added .. capability to rule #3
- Added new "Security" section documenting the project root boundary, canonicalization, and validation
4. New test - test_empty_include_path_rejected
Not implemented (and why):
- Symlink test - The existing canonicalization already handles this correctly; an additional test would be platform-specific and doesn't add much value
- Root directory edge case - Academic case; unlikely in practice since the project root is derived from the source file
- Error message improvements - The current messages are clear enough
Pull Request Review - Issue #102: Cross-Directory Include SupportSummaryThis PR successfully implements project-root-relative include path resolution, allowing test files to include source files from sibling directories using Code Quality & Best Practices ✅Strengths:
Minor observations:
Potential Bugs or Issues
|
for #102
Changes Made
crates/compiler/src/resolver.rs:
crates/compiler/Cargo.toml:
New tests added:
The fix enables the SeqLisp use case from issue #102 where tests can include source files from sibling directories:
project/
src/ tokenizer.seq tests/ test.seq ← can now do: include "../src/tokenizer"