Skip to main content

add-documentation

Use when adding or updating XML documentation for any public API in DynamicData, including new operators, changed behavior, batch documentation passes, or PR reviewer requests for improved docs. Covers extension methods, public classes, interfaces, enums, and any member visible in the published API reference.

소스 정보

저장소
reactivemarbles/DynamicData
최근 소스 활동
2026년 4월 17일 16:52
감지된 SKILL.md 언어
영어
스타
1,906
포크
193

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
add-documentation
description
Use when adding or updating XML documentation for any public API in DynamicData, including new operators, changed behavior, batch documentation passes, or PR reviewer requests for improved docs. Covers extension methods, public classes, interfaces, enums, and any member visible in the published API reference.
# Add Documentation ## Overview Write publication-quality XML documentation for DynamicData public APIs. Every behavioral claim must be traced from the implementation source, not guessed from naming conventions. The documentation will be extracted as HTML and published on the ReactiveUI docs site. ## When to Use - New operator or public API added - Existing operator's behavior changed - Batch documentation pass across a file - PR reviewer requests improved documentation - Any public type, interface, enum, or member needs docs ## Core Rule: Additive Only Never remove existing useful information from comments. After making changes, diff against main to confirm nothing substantive was lost. ## Unified Template Start from this template for any primary overload. Delete sections that do not apply. ```xml /// <summary> /// [1-3 sentences: what it does, why you'd use it. No behavioral details.] /// </summary> /// <typeparam name="TObject">The type of items.</typeparam> /// <typeparam name="TKey">The type of the key.</typeparam> /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> to [verb: filter, transform, sort, etc.].</param> /// <param name="exampleParam">An <see cref="IComparer{TObject}"/> that determines sort order.</param> /// <returns>[What it emits and what each emission represents.]</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="source"/> is <c>null</c>.</exception> /// <remarks> /// <para>[When to use. How it differs from alternatives. Multiple paragraphs fine.]</para> /// /// <!-- SINGLE-SOURCE CHANGESET OPERATOR: one event table --> /// <!-- MULTI-SOURCE OPERATOR: separate labeled tables per source (see below) --> /// <!-- MUTATION HELPER: table describes what changeset is PRODUCED --> /// <!-- NON-CHANGESET OUTPUT: table describes how source events affect subscriptions --> /// /// <list type="table"> /// <listheader><term>Event</term><description>Behavior</description></listheader> /// <!-- Cache operators --> /// <item><term>Add</term><description>[specific outcome, bold output reasons]</description></item> /// <item><term>Update</term><description>[specific outcome]</description></item> /// <item><term>Remove</term><description>[specific outcome, mention cleanup]</description></item> /// <item><term>Refresh</term><description>[specific outcome, trace carefully]</description></item> /// <!-- List operators: also include these --> /// <item><term>AddRange</term><description>[specific outcome]</description></item> /// <item><term>Replace</term><description>[list equivalent of Update]</description></item> /// <item><term>RemoveRange</term><description>[specific outcome]</description></item> /// <item><term>Moved</term><description>[specific outcome]</description></item> /// <item><term>Clear</term><description>[specific outcome]</description></item> /// <!-- All operators --> /// <item><term>OnError</term><description>[forwarded? swallowed? conditional?]</description></item> /// <item><term>OnCompleted</term><description>[immediate? waits for children?]</description></item> /// </list> /// /// <!-- MULTI-SOURCE: use this pattern instead of the single table above --> /// <para><b>Source changeset handling (parent events):</b></para> /// <list type="table"> /// <listheader><term>Event</term><description>Behavior</description></listheader> /// <item><term>Add</term><description>[subscribes to child / creates state]</description></item> /// <item><term>Update</term><description>[disposes old, subscribes to new]</description></item> /// <item><term>Remove</term><description>[disposes, emits downstream removes]</description></item> /// <item><term>Refresh</term><description>[no effect / re-evaluates]</description></item> /// </list> /// <para><b>Per-item observable handling:</b></para> /// <list type="table"> /// <listheader><term>Emission</term><description>Behavior</description></listheader> /// <item><term>First value</term><description>[what appears downstream]</description></item> /// <item><term>Subsequent values</term><description>[updates? replacements?]</description></item> /// <item><term>Error</term><description>[terminates? swallowed?]</description></item> /// <item><term>Completed</term><description>[freezes? removed?]</description></item> /// </list> /// /// <para><b>Worth noting:</b> [Non-obvious behavior, edge cases, disposal semantics.]</para> /// </remarks> /// <seealso cref="[OtherOverloadsInSet]"/> /// <seealso cref="[SafeOrAsyncVariant]"/> /// <seealso cref="[SimilarOperator]"/> /// <seealso cref="[ComplementaryOperator]"/> ``` For **secondary overloads** in an overload set: ```xml <!-- When the overload delegates to the primary (simpler signature, fewer params): --> /// <inheritdoc cref="[PrimarySignature]"/> /// <param name="[delta]">A <see cref="[Type]"/> that [specific difference].</param> /// <remarks>This overload [what differs]. Delegates to <see cref="[Primary]"/>.</remarks> <!-- When the overload has a different implementation (different input type, different behavior): --> <!-- Use the full unified template above. It needs its own complete documentation. --> <!-- Still link to the other overloads via seealso for discoverability. --> ``` ## Process ### 1. Analyze the Implementation Read the actual source code. Trace each code path for every change reason the operator handles. Key questions: - What does each change reason produce downstream? Name the exact output. - Are there conditional outcomes? (e.g., Filter's Update has four possible results) - Does the operator create per-item subscriptions? When created/disposed? - Are errors from child subscriptions forwarded or swallowed? - Does OnCompleted wait for child subscriptions? Refresh behavior varies significantly between operators: some re-evaluate (Filter), some forward as-is (Transform by default), some drop (FilterImmutable), some convert to other change types. But all change reasons deserve the same careful tracing. ### 2. Choose What to Include | The method... | Template sections to use | |---|---| | Extends `IObservable<IChangeSet>`, produces `IObservable<IChangeSet>` | Single event table (cache or list rows) | | Has multiple input sources or per-item observables | Multi-source tables (parent + child) | | Extends `ISourceCache`/`ISourceList`, returns void | Single table, framed as "produced" | | Produces non-changeset output (`IObservable<T>`, `bool`, etc.) | Single table, framed as subscription lifecycle | | Is a class, interface, enum, or non-extension member | Summary, params, returns, remarks (no event table) | ### 3. Apply Quality Rules **Params**: Every `<param>` must read as natural English with the type linked via `<see cref="..."/>` woven into the sentence. No type is exempt from linking (including enums, `Optional`, `Change`, `IChangeSet`, standard library types like `IComparer`, `TimeSpan`, `IScheduler`). Use `<see langword="true"/>` / `<see langword="false"/>` / `<see langword="null"/>` for C# keywords. Param writing rules: - **Reads as English.** Read it aloud. If it sounds wrong, it IS wrong. - **Starts with an article** ("The", "A", "An") or a condition ("When", "If"). - **Links the actual parameter type** from the method signature. Use `<see cref="..."/>`. Get the generic type arguments right (e.g., `IComparer{TObject}` not `IComparer{T}` when the param type is `IComparer<TObject>`). - **Describes the purpose**, not just the type. Every param description must answer: "what does the caller use this for?" - **No redundancy with the type name.** The type `IChangeSet` already says "changeset", so don't add "changeset stream" after it. The type `IObservable` already says "observable", so don't add "observable" after it. The type `IComparer` already says "comparer", so don't add "comparer" after it. - **No double articles.** "The source [type] the left stream" has two articles fighting each other. - **Combined nested crefs** for observable changeset types. Write `IObservable{IChangeSet{TObject, TKey}}` as one cref. NEVER split into `IObservable{T}` + "of" + `IChangeSet{...}`. - **For deeply nested generics** (3+ nesting levels), use `{T}` in the cref and describe the actual type in prose. - **For `params` array parameters**, do not include `[]` in the cref. - **For `Optional.None`**, use `<see cref="Optional.None{T}"/>`. ```xml <!-- ======================== BAD EXAMPLES ======================== --> <!-- BAD: split type into two parts --> /// <param name="source">The source <see cref="IObservable{T}"/> of <see cref="IChangeSet{TObject, TKey}"/>.</param> <!-- BAD: redundant "changeset stream" after IChangeSet type --> /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> changeset stream.</param> <!-- BAD: no purpose, just the type name --> /// <param name="comparer">The <see cref="IComparer{TObject}"/>.</param> <!-- BAD: echoes the type name ("comparer" after IComparer) --> /// <param name="comparer">The <see cref="IComparer{TObject}"/> comparer used for sorting.</param> <!-- BAD: double article ("The source ... the left") --> /// <param name="left">The source <see cref="IObservable{IChangeSet{TLeft, TLeftKey}}"/> the left input.</param> <!-- ======================== GOOD EXAMPLES ======================== --> <!-- source params: "The source [type] to [operator verb]." --> /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> to filter.</param> /// <param name="source">The source <see cref="IObservable{IChangeSet{TObject, TKey}}"/> to transform.</param> /// <param name="source">The source <see cref="IObservable{ISortedChangeSet{TObject, TKey}}"/> to bind.</param> /// <param name="source">The <see cref="ISourceCache{TObject, TKey}"/> to add items to.</param> <!-- join left/right params --> /// <param name="left">The left <see cref="IObservable{IChangeSet{TLeft, TLeftKey}}"/> to join.</param> /// <param name="right">The right <see cref="IObservable{IChangeSet{TRight, TRightKey}}"/> to join.</param>
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기