Skip to content

Commit 876bbee

Browse files
committed
[AI] Add guidelines for Junie
1 parent 11ac7a3 commit 876bbee

1 file changed

Lines changed: 270 additions & 0 deletions

File tree

.junie/guidelines.md

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
# RevitExtensions Guidelines
2+
3+
## 1. Project Structure
4+
5+
### 1.1. Solution Organization
6+
7+
* **`/source`**: Core library project.
8+
* `Nice3point.Revit.Extensions`: Extension methods for Revit API types.
9+
* **`/tests`**: Testing projects.
10+
* `Nice3point.Revit.Extensions.Tests`: Unit tests executed in Revit context using Nice3point.TUnit.Revit.
11+
* **Root Level**:
12+
* Configuration files: `Directory.Build.props`, `Directory.Packages.props`
13+
* Documentation: `Readme.md`, `Changelog.md`
14+
* CI/CD: `.github/workflows`
15+
16+
## 2. Architecture Principles
17+
18+
### 2.1. Core Design Goals
19+
20+
* **Fluent API:** Enable method chaining for better readability.
21+
* **Type Safety:** Utilize generics and nullable reference types.
22+
* **Performance:** Minimize allocations, use optimized Revit API patterns.
23+
* **Analyzers:** Use JetBrains.Annotations for static code analysis.
24+
* **Backward Compatibility:** Never break existing public APIs.
25+
26+
## 3. Strict C# Production Style
27+
28+
### 3.1. General Principles
29+
30+
* **C# 14 Extension Syntax:** Use `extension(Type type) { }` blocks instead of static methods with `this`.
31+
* **Method Chaining:** All `void` methods should return the source object for fluent API.
32+
* **Pure Functions:** Mark read-only operations with `[Pure]` attribute.
33+
* **Explicit over Implicit:** Code should be self-explanatory.
34+
35+
### 3.2. Naming Conventions
36+
37+
* **Clarity is King:** Names must be descriptive.
38+
* **Revit API Patterns:** Follow Revit API naming conventions.
39+
* Passive voice for operations on object: `CanBeDeleted`, `CanBeMirrored`, `CanBeConvertedToFaceHostBased`
40+
* Active voice for object performing action: `CanElementCutElement`
41+
* **No Abbreviations:**
42+
*`elem`, `doc`, `param`
43+
*`element`, `document`, `parameter`
44+
* **ElementId Overloads:** Methods accepting `Document document` parameter should have descriptive names when context is ambiguous:
45+
*`elementId.MoveGlobalParameterUpOrder(document)`
46+
*`elementId.MoveUpOrder(document)` - too generic
47+
48+
### 3.3. Extension Method Structure
49+
50+
* **File-Scoped Namespaces:** Always use `namespace Nice3point.Revit.Extensions;` with the comment `// ReSharper disable once CheckNamespace`
51+
* **PublicAPI Attribute:** Mark all extension classes with `[PublicAPI]`.
52+
* **Extension Blocks:** Group related extensions using `extension(Type type) { }`, `extension<T>(Type<T> type) { }` or `extension(Type) { }` syntax.
53+
* **XML Documentation:** Document all public methods with `<summary>` block(it should be copied from Revit API documentation for Revit API wrappers).
54+
55+
### 3.4. Method Chaining Pattern
56+
57+
All mutation methods should return the source object istead of void type:
58+
59+
```csharp
60+
extension(Element element)
61+
{
62+
public Element JoinGeometry(Element secondElement)
63+
{
64+
JoinGeometryUtils.JoinGeometry(element.Document, element, secondElement);
65+
return element; // Enable chaining
66+
}
67+
}
68+
```
69+
70+
### 3.5. ElementId Overload Pattern
71+
72+
For methods using `element.Document` and `element.Id`, provide ElementId overloads:
73+
74+
```csharp
75+
extension(Element element)
76+
{
77+
public bool CanBeDeleted()
78+
{
79+
return DocumentValidation.CanDeleteElement(element.Document, element.Id);
80+
}
81+
}
82+
83+
extension(ElementId elementId)
84+
{
85+
public bool CanBeDeleted(Document document)
86+
{
87+
return DocumentValidation.CanDeleteElement(document, elementId);
88+
}
89+
}
90+
```
91+
92+
### 3.6. Error Handling
93+
94+
* **Revit Exceptions:** Document Revit API exceptions in XML comments.
95+
* **No Swallowing:** Let Revit exceptions propagate to caller.
96+
* **Validation:** Validate inputs for custom logic only.
97+
98+
### 3.7. Compilation Directives
99+
100+
* **Revit Version Support:** Use `#if REVIT2024_OR_GREATER` for version-specific APIs.
101+
* **Consistent Patterns:** Apply directives consistently across related methods.
102+
103+
## 4. Backward Compatibility
104+
105+
### 4.1. Obsolete Attribute Pattern
106+
107+
**NEVER** delete existing public APIs. Mark them as obsolete instead:
108+
109+
```csharp
110+
[Obsolete("Use CanBeMirrored() instead")]
111+
[CodeTemplate(
112+
searchTemplate: "$expr$.CanMirrorElement()",
113+
Message = "CanMirrorElement is obsolete, use CanBeMirrored instead",
114+
ReplaceTemplate: "$expr$.CanBeMirrored()",
115+
ReplaceMessage = "Replace with CanBeMirrored()")]
116+
public bool CanMirrorElement()
117+
{
118+
return ElementTransformUtils.CanMirrorElement(element.Document, element.Id);
119+
}
120+
```
121+
122+
### 4.2. Obsolete Guidelines
123+
124+
* **Message:** Clear explanation with replacement method name.
125+
* **CodeTemplate:** Provide JetBrains ReSharper auto-conversion pattern.
126+
* **Implementation:** Obsolete method must call **original Revit API**, not the new method (avoid recursion).
127+
* **No EditorBrowsable:** Do NOT add `[EditorBrowsable(EditorBrowsableState.Never)]` for Element extension obsolete methods.
128+
129+
### 4.3. Breaking Changes
130+
131+
* **Method Signature:** Never change existing method signatures (only if renaming is required).
132+
* **Return Type:** Never change return types (except `void` → source object for chaining).
133+
* **Parameters:** Add optional parameters only at the end.
134+
* **Renaming:** Use Obsolete pattern, keep old method functional.
135+
136+
## 5. Documentation Requirements
137+
138+
### 5.1. Readme.md
139+
140+
* **Add Examples:** Every new extension category must have usage examples.
141+
* **ElementId Examples:** When adding ElementId overloads, add examples in existing sections:
142+
```csharp
143+
// Element extension
144+
element.Copy(new XYZ(1, 1, 0));
145+
146+
// ElementId extension (add to same section)
147+
elementId.Copy(document, new XYZ(1, 1, 0));
148+
```
149+
* **No New Sections:** Don't create new sections for ElementId variants(if extension has the method for an element), add to existing sections.
150+
151+
### 5.2. Changelog.md
152+
153+
* **Version Sections:** Update the current preview/release version section.
154+
* **Categories:**
155+
* **New Features:** New extension methods, ElementId overloads.
156+
* **Breaking Changes:** Renamed methods, changed behavior.
157+
* **Improvements:** Performance, refactoring.
158+
* **Bug Fixes:** Corrections to existing functionality.
159+
* **Migration Examples:** Show at the end.
160+
* **Complete Documentation:** Document ALL changes, not just major ones.
161+
162+
### 5.3. XML Documentation
163+
164+
* **Summary:** Describe what the method does.
165+
* **Parameters:** Document each parameter with context.
166+
* **Returns:** Describe return value meaning.
167+
* **Exceptions:** Document all possible Revit API exceptions.
168+
169+
## 6. Testing Strategy
170+
171+
### 6.1. Test Scope
172+
173+
* **Custom Logic Only:** Test extensions with user-defined logic, NOT simple wrappers over Revit Utils.
174+
* **Examples:**
175+
* ✅ Test: `BoundingBox.Contains()` - custom containment logic
176+
* ✅ Test: `Line.Distance()` - custom distance calculation
177+
* ✅ Test: `ToOrderedElements()` - custom ordering logic
178+
* ❌ Skip: `element.Copy()` - simple wrapper over `ElementTransformUtils.CopyElement`
179+
* ❌ Skip: `element.JoinGeometry()` - simple wrapper over `JoinGeometryUtils.JoinGeometry`
180+
181+
### 6.2. Test Framework
182+
183+
* **Framework:** TUnit with Nice3point.TUnit.Revit for Revit context execution.
184+
* **Location:** `tests/Nice3point.Revit.Extensions.Tests`.
185+
* **Execution:** Tests run inside Revit process using `[TestExecutor<RevitThreadExecutor>]`.
186+
187+
### 6.3. Test Data Pattern
188+
189+
Use `MethodDataSource` to test against all Revit sample files:
190+
191+
```csharp
192+
private static readonly string SamplesPath = $@"C:\Program Files\Autodesk\Revit {Application.VersionNumber}\Samples";
193+
194+
[Before(Class)]
195+
public static void ValidateSamples()
196+
{
197+
if (!Directory.Exists(SamplesPath))
198+
{
199+
Skip.Test($"Samples folder not found at {SamplesPath}");
200+
return;
201+
}
202+
203+
if (!Directory.EnumerateFiles(SamplesPath, "*.rfa").Any())
204+
{
205+
Skip.Test($"No .rfa files found in {SamplesPath}");
206+
}
207+
}
208+
209+
public static IEnumerable<string> GetSampleFiles()
210+
{
211+
if (!Directory.Exists(SamplesPath))
212+
{
213+
yield return string.Empty;
214+
yield break;
215+
}
216+
217+
foreach (var file in Directory.EnumerateFiles(SamplesPath, "*.rfa")) yield return file;
218+
}
219+
220+
[Test]
221+
[TestExecutor<RevitThreadExecutor>]
222+
[MethodDataSource(nameof(GetSampleFiles))]
223+
public async Task MyExtension_ValidFile_ReturnsExpectedResult(string filePath)
224+
{
225+
Document? document = null;
226+
227+
try
228+
{
229+
document = Application.OpenDocumentFile(filePath);
230+
231+
// Test logic here
232+
233+
await Assert.That(result).IsNotNull();
234+
}
235+
finally
236+
{
237+
document?.Close(false);
238+
}
239+
}
240+
```
241+
242+
### 6.4. Test Coverage
243+
244+
* **Edge Cases:** Null inputs, empty collections, boundary values.
245+
* **Revit API Constraints:** Test against actual Revit objects, not mocks.
246+
247+
### 6.5. UI Extensions
248+
249+
* **No Testing:** Skip UI-related extensions (Ribbon, ContextMenu, UIApplication).
250+
251+
## 7. Performance Guidelines
252+
253+
### 7.1. Revit API Optimization
254+
255+
* **Batch Operations:** Prefer batch APIs over individual calls.
256+
* **Transactions:** Minimize transaction scope.
257+
258+
### 7.2. Memory Allocation
259+
260+
* **Avoid LINQ:** For hot paths, use traditional loops instead of LINQ.
261+
* **Collection Sizing:** Pre-allocate collections when size is known.
262+
* **String Operations:** Use `StringBuilder` for complex concatenations.
263+
264+
## 8. Package Management
265+
266+
* **Centralized:** All versions are defined in `Directory.Packages.props`.
267+
* **Multi-targeting:** Support Revit 2019-2026 configurations (Debug.R19-R26, Release.R19-R26).
268+
* **Dependencies:**
269+
* `JetBrains.Annotations` - Code analysis attributes
270+
* **Conditional Compilation:** Use `#if REVIT2024_OR_GREATER` and similar for API changes.

0 commit comments

Comments
 (0)