本文へ移動
cccskills
無料GitHub で公開

jsdoc

Add or revise source-level JSDoc for Shift APIs. Use this skill before writing or editing documentation comments for exported classes, methods, constructors, domain data structures, render frames, reactive state, or any API where caller intent, side effects, lifetime, ownership, or nullability are easy to misunderstand.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md14.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

/jsdoc — Source API Contracts

Write JSDoc as the stable public contract a caller needs without reading the implementation.

JSDoc comments must sit immediately before the documented symbol and use /** ... */ so tooling can parse them. Follow the standard tag vocabulary from https://jsdoc.app/about-getting-started, adapted for TypeScript source.

Why this matters

  • VS Code hover renders the first line in bold and the rest as body. A one-sentence contract on line 1 is the single highest-leverage thing you can write.
  • TypeScript already encodes shape. JSDoc is for what types can't say: ownership, lifetime, mutation, side effects, side-channel reactivity, nullability semantics, performance class, call ordering.
  • Code review is the second reader. Reviewers should be able to judge a call site against the doc without opening the implementation.

Runbook

  1. Identify the audience: caller, implementer, renderer, tool author, or maintainer.
  2. State the stable contract in one short opening sentence.
  3. Add details only for ownership, lifetime, reactivity, mutation, side effects, nullability, performance, or call ordering. Put long detail under @remarks.
  4. Use tags for callable APIs:
    • Add @param for every public constructor, method, or function parameter, and make the text describe the parameter's role, constraint, ownership, or valid range.
    • Add @returns when a method returns a value, nullable result, created object, snapshot, or read-only view.
    • Add @throws {ErrorType} when … for every observable failure mode (custom error class, semantic Error).
    • Do not add @returns void; describe the side effect in prose instead.
  5. Cross-reference siblings with @see {@link OtherSymbol} (one tag per related symbol).
  6. Add @example only when the intended call flow, ordering, or output is not obvious from the signature.
  7. Re-read the comment and delete implementation trivia, current call-site anecdotes, and unstable examples.

Hard Style Rules

  • One-line contract. First sentence is a verb phrase (Returns…, Applies…, Triggers…), ending with a period. No "This function…".
  • @remarks for the long explanation. If you need more than one sentence of context, demote it under @remarks so the hover summary stays clean.
  • @param name - description documents meaning, not type. For public callable APIs, include the tag and make it earn its place by describing role, constraint, ownership, valid range, or call-order semantics.
  • @returns documents meaning, never "void". Drop the tag entirely for void returns; describe the side effect in the summary instead. Use @returns to clarify ownership ("a fresh array; caller owns it"), nullability semantics ("null when the glyph has no contours, not when it's missing"), or that the result is a snapshot vs a live reactive view.
  • Document side effects, lifetime, and reactivity. TypeScript can't encode "runs after render", "mutates the Glyph signal", "JS-only — does not call NAPI", "transfers ownership of the buffer". That is exactly what JSDoc is for.
  • Stable terms over current implementation names. Document the concept, not today's wiring.
  • No warnings, no scolding. State the contract directly.
  • Do not document private helpers unless they encode a non-obvious invariant.
  • Do not name current callers ("used by FooManager") — rots fast.
  • Never use JSDoc as a TODO list. That belongs in commits, issues, or // TODO comments.

What To Document

Document where the type signature is silent. If the type fully encodes the contract, write nothing. Otherwise, prioritize these dimensions:

  • Effects — purity, mutation of arguments, mutation of shared state, I/O.
  • Ownership — who owns the return value, who may mutate it, aliasing with internal state.
  • Identity vs value — handles/refs/IDs that look like the loaded object but aren't; snapshots vs live views.
  • Nullability semantics — what null / undefined / empty actually means (absent, error, not-yet-loaded, end-of-stream).
  • Resolution semantics — strict vs fallback, find vs find-or-create, exact vs nearest.
  • Lifetime and ordering — preconditions, disposal, idempotence, what makes the result go stale.
  • Failure modes — which errors, under which conditions; whether failure is observable or swallowed.
  • Concurrency and context — thread, render phase, re-entrancy, async cancellation behavior.
  • Performance class — Big-O, hot-path safety, sync-vs-async cost, when a convenient method is wrong.

Pick only the dimensions that apply. Do not force every doc to address all of them.

Tag Reference Card (TS-first)

TagUse it whenExample
@param name - descEvery public param. Document the constraint, not the type.@param glyph - must be loaded (not a GlyphRef)
@returns descNullable / created / snapshot / read-only / non-obvious return.@returns null when no source is active; never throws.
@throws {Err} when …Every observable failure mode. Always type + condition.@throws {GlyphNotLoadedError} when called on a ref-only glyph.
@exampleCall order, setup, or output carries the lesson.See below — fenced ts, imports, // Output: line.
@remarksLong explanation that would bloat the summary.One short paragraph; not multi-paragraph essays.
@see {@link Foo}One tag per related sibling API.@see {@link createDraft}
@deprecated <migration>Always with replacement or removal reason.@deprecated Use draft.setPositions instead — avoids NAPI per frame.
@template T - descGeneric with a semantic constraint that isn't obvious from the signature.@template T - coordinate-space tag; controls bound interpretation.

Avoid in TypeScript

These re-encode information TS already owns. Including them is noise and risks drift.

  • @type, @typedef, @property — TS variable annotations, type, and interface are the source of truth.
  • @class, @constructor, @extends, @implements, @function, @method — the declaration shape says this.
  • {Type} annotations inside @param / @returns — never write @param {string} name. Document meaning; TS owns the type.

Skip in app code

These are doc-generator ceremony for published packages. Shift is not a published package; do not write these in app code.

  • @since, @public, @beta, @alpha, @experimental, @category
  • @author, @version, @copyright
  • date-fns-style @name/@summary/@description triples

Tag Format

In TypeScript files, omit JSDoc type annotations. Let TypeScript own the type; let JSDoc own meaning.

/**
 * Snapshot of state required to redraw the scene layer.
 *
 * Building this frame establishes the reactive dependencies for the scene
 * output. Drawing code consumes the frame as plain data.
 *
 * @param dependencies - Values that invalidate or describe one scene redraw.
 */
constructor(dependencies: SceneFrameDependencies) {}

For functions with multiple parameters, document each parameter by role:

/**
 * Converts a screen-space pointer into editor coordinate spaces.
 *
 * @param screen - Pointer position in canvas pixels.
 * @param drawOffset - Glyph-local offset applied by the current editor view.
 * @returns Coordinates in screen, scene, and glyph-local space.
 */
function resolveCoordinates(
  screen: Point2D,
  drawOffset: Point2D,
): Coordinates {}

When failure paths are observable, document them with @throws:

/**
 * Loads a glyph by handle. Resolves once the source is hydrated.
 *
 * @param handle - identity returned by {@link glyphHandleForUnicode}.
 * @returns the loaded glyph; never a {@link GlyphRef}.
 * @throws {GlyphNotFoundError} when the handle does not resolve in the active font.
 * @see {@link glyphHandleForUnicode}
 */
async function loadGlyph(handle: GlyphHandle): Promise<Glyph> {}

When deprecating, name the replacement:

/**
 * @deprecated Use {@link draft.setPositions} — `bridge.setNodePositions` sends
 *   one NAPI call per point and causes ~450ms frames on dense glyphs.
 */
function setNodePositions(updates: NodePositionUpdate[]): void {}

Examples — the rules

Examples must be runnable assertions, not decoration.

  • Always fenced and language-tagged with ```ts. VS Code highlights inside fences.
  • Self-contained. Include imports. The reader should be able to paste the snippet and have it compile.
  • Show expected output with a // Output: or // => comment when the value carries the lesson.
  • Short. 8–12 lines is the typical good length; 25 is the ceiling. If it doesn't fit, the example is the wrong shape.
  • One concept per @example. Multiple @example blocks are fine and better than one mega-block.

A good example for a Shift API:

/**
 * Begins a JS-only edit of the active glyph. Pair with {@link GlyphDraft.finish}
 * to persist, or {@link GlyphDraft.discard} to revert.
 *
 * @returns a draft scoped to the active glyph; `null` when no glyph is loaded.
 *
 * @example
 * ```ts
 * const draft = editor.createDraft();
 * if (!draft) return;
 *
 * for (const update of dragFrame) {
 *   draft.setPositions(update); // JS-only; no NAPI
 * }
 *
 * draft.finish("translate");    // syncs once, records undo
 * ```
 */
createDraft(): GlyphDraft | null {}

When TS inference is non-obvious, annotate the type position inline (Effect pattern):

/**
 * @example
 * ```ts
 * //      ┌─── Option<Glyph>
 * //      ▼
 * const result = font.glyphForUnicode(0x41);
 * ```
 */

Avoid examples that depend on hidden setup, test fixtures, or implicit globals.

Overloads

  • Per-overload JSDoc when parameter meanings differ. (This is the TS standard-library convention.) Copy the contract on each signature; do not put one block on the implementation signature.
  • Top-overload JSDoc only when the contract is identical and only the type shape differs. The implementation signature stays bare.
/**
 * Resolves a glyph from its Unicode codepoint.
 * @param codepoint - the Unicode scalar value.
 */
function glyphFor(codepoint: number): Glyph | null;
/**
 * Resolves a glyph from its handle.
 * @param handle - identity from a prior lookup; cheaper than codepoint resolution.
 */
function glyphFor(handle: GlyphHandle): Glyph | null;
function glyphFor(arg: number | GlyphHandle): Glyph | null {
  /* impl */
}

Anti-Patterns (bad → good)

@returns void

// ❌
/** @returns void */
clear(): void {}

// ✅ describe the side effect; drop @returns entirely
/** Clears all queued render frames. Idempotent. */
clear(): void {}

Re-stating the signature in prose

// ❌
/**
 * @param glyph - the glyph
 * @param index - the index
 */

// ✅ document the constraint
/**
 * @param glyph - must be loaded (not a {@link GlyphRef}).
 * @param index - zero-based contour index; -1 selects the outer hull.
 */

Multi-paragraph summary

// ❌ VS Code hover becomes a wall of text
/**
 * This function is used to set positions. It is part of the GlyphDraft API and
 * is used during drag operations. It does not call NAPI. It must be paired
 * with either finish() or discard().
 */

// ✅ one-line contract + @remarks
/**
 * Updates JS-side glyph positions; pair with {@link finish} or {@link discard}.
 *
 * @remarks
 * JS-only — does not call NAPI. Use during drag hot path; call `finish()` once
 * at gesture end to sync to Rust, or `discard()` to revert.
 */

Naming current callers

// ❌ rots fast
/** Called by GlyphSidebar and TransformPanel. */

// ✅ describe what it produces
/** Returns the active glyph's tight bounds, accounting for sidebearings. */

Bare @deprecated

// ❌
/** @deprecated */
function oldThing() {}

// ✅ name the replacement or the reason
/** @deprecated Use {@link newThing} — removes the legacy 2D-only path. */
function oldThing() {}

@example for trivial calls

// ❌ noise
/**
 * @example
 * ```ts
 * const id = glyph.id;
 * ```
 */
get id(): string {}

// ✅ no @example; the name is the whole story
get id(): string {}

Examples that depend on hidden setup

// ❌ what is `editor`?
/** @example editor.commit(); */

// ✅ self-contained
/**
 * @example
 * ```ts
 * const editor = createTestEditor();
 * await editor.loadGlyph("A");
 * editor.commit();
 * ```
 */

General "do not" list

  • API dumps covering every accessor.
  • Long examples that obscure the method being documented.
  • Compat wrappers or aliases that hide which API should be used.
  • Rewriting behavior while documenting unless the user requested the API fix too.
  • Describing bugs, migrations, or "currently used by X" in API docs.
  • Listing concrete state variants as examples when the actual contract is broader.
  • Documenting private helpers with full @param/@returns/@example blocks — a one-line summary is enough.
  • Mixing {Type}-style JSDoc with TSDoc tags in the same module; pick one (in TS, drop {Type}).

Quick Checklist

Before saving, scan your doc against this list:

  • First line is one sentence, verb-phrase, ends with a period.
  • No @type, @typedef, or {Type} annotations.
  • No @returns void. Side effect described in summary.
  • Every observable failure has @throws {Type} when ….
  • @example (if present) has imports, is fenced ```ts, and shows output when it carries the lesson.
  • No current-caller name-drops, no migration notes, no TODOs.
  • No ceremony tags (@since, @public, @category, @author).
  • If deprecated, the replacement or reason is named.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

commit

無料

Canonical rules for writing git commits in the Shift codebase. Use whenever the user asks to commit, stage and commit, create a pull request that requires commits, or draft a commit message. Enforces Conventional Commits, release-note quality, concise subjects, and logical commit boundaries.

日本語の概要は準備中です。原文の説明を表示しています。

shift-editor/shift3502026年10月11日 更新

dead-code

無料

Find and remove dead code (unused files, exports, class members) using Knip as a candidate generator, then verify each candidate through AST-level analysis and interface tracing before removing anything. Use when the user asks to clean up unused code, find dead code, or reduce the codebase.

日本語の概要は準備中です。原文の説明を表示しています。

shift-editor/shift3502026年10月11日 更新

docs

無料

Update or create DOCS.md files for Shift subsystems. Use this skill whenever the user asks to update docs, refresh documentation, create a DOCS.md, write module documentation, or says "update docs for X". Also trigger after completing a large feature when Claude.md says to update docs — check if any DOCS.md in the affected subsystem needs refreshing.

日本語の概要は準備中です。原文の説明を表示しています。

shift-editor/shift3502026年10月11日 更新

Adversarially fact-check DOCS.md files against the actual source code, verifying every concrete claim rather than trusting structure checks. Use when the user asks to audit docs, verify documentation accuracy, check whether docs are still true, or on a scheduled documentation review. This is the semantic layer the mechanical checkers cannot cover.

日本語の概要は準備中です。原文の説明を表示しています。

shift-editor/shift3502026年10月11日 更新

issue

無料

Canonical rules for finding, creating, and updating Shift GitHub issues. Use whenever the user asks to file, create, open, update, triage, or search for an issue, or when substantial work needs an issue before a pull request. Prevents duplicates and defines acceptance criteria and pull-request closure semantics.

日本語の概要は準備中です。原文の説明を表示しています。

shift-editor/shift3502026年10月11日 更新

perf

無料

How to find and fix performance problems in Shift's desktop app. Use when something is slow, choppy, janky, or laggy (scrubbing, dragging, editing, undo, opening fonts), when profiling or measuring, when adding or reviewing perf tests, and before claiming a change made something faster.

日本語の概要は準備中です。原文の説明を表示しています。

shift-editor/shift3502026年10月11日 更新

shift-editor のスキルをすべて見る

このスキルの問題を報告する