Skip to content

feat(scripts): add type-bearing JSDoc hygiene gate for .ts source (SD-673)#3511

Merged
caio-pizzol merged 5 commits into
mainfrom
caio-pizzol/SD-jsdoc-hygiene-scanner
May 26, 2026
Merged

feat(scripts): add type-bearing JSDoc hygiene gate for .ts source (SD-673)#3511
caio-pizzol merged 5 commits into
mainfrom
caio-pizzol/SD-jsdoc-hygiene-scanner

Conversation

@caio-pizzol

Copy link
Copy Markdown
Contributor

Adds a new check:public:superdoc stage (jsdoc-hygiene-ts) that enforces TypeScript-as-single-source on .ts source under packages/superdoc/src/ and packages/super-editor/src/. Companion to the existing jsdoc-ratchet stage which covers .js files; together they enforce that each language's source files use the right type system without one polluting the other.

Scope is TS-source hygiene in the public packages, not a reachability-filtered public-surface scan. Every .ts file under those roots is scanned (excluding *.d.ts, *.test.ts, *.spec.ts, and dev/, __mocks__/, __fixtures__/ directories). The rule is "TS source uses TS syntax for shape, prose-only JSDoc for documentation" - it applies uniformly, not only to declarations that reach the emitted facade.

This is the scanner + baseline PR. Cleanup of the 85 baseline entries comes next in a separate PR; the zero-baseline flip is a third PR after that. Same ratchet pattern as jsdoc-debt-snapshot.json.

Detection model (positive, on tag name):

  • ALWAYS_FLAG_TAGS: @type, @typedef, @callback, @template, @implements, @extends, @augments, @enum. Each has a native TS equivalent.
  • FLAG_WHEN_TYPED_TAGS: @param, @returns, @return, @this. Only flagged when tag.typeExpression is set (the {Type} brace). Prose-only @param name description passes.
  • Every other tag ignored: @deprecated, @example, @throws, @see, @typeParam, etc.

AST-based, not regex. Uses ts.getJSDocTags + tag.typeExpression so prose containing the literal text @type {Foo} (e.g. docstring examples that escape the closing comment with *\/) doesn't false-positive. De-duped per (file, pos, end, tag) so tags surfaced via multiple parent walks count once.

Stable baseline key: file::enclosingSymbol::tagName::class::occurrenceIndex. Line numbers are not part of the key - the baseline survives unrelated edits that shift line numbers. Verified empirically: inserting 3 blank lines at the top of SuperDoc.ts (shifting ~40 grandfathered violations down) produces zero stale/new churn.

enclosingSymbol handles private identifiers, named declarations, string/numeric property keys. Private methods like #applyDocumentMode anchor to #applyDocumentMode, not to their enclosing class. The identifier-only resolver previously collapsed 10 private-method violations onto SuperDoc; the fix correctly distributes them.

Classification. Each violation is tagged as declaration-doc-type, inline-fake-cast, or typedef-style so the cleanup PR can group fixes by type.

Baseline. jsdoc-hygiene-ts-baseline.json records the 85 existing violations grandfathered at PR time. Tag distribution: 31 @template, 23 @param, 22 @returns, 5 @type (inline fake casts), 2 @typedef, 1 @extends, 1 @implements. Concentrated in SuperDoc.ts, EventEmitter.ts, Mark.ts, Node.ts, OxmlNode.ts.

Scanner tests (check-jsdoc-hygiene-ts.test.cjs) protect against silent false-positives and false-negatives. 13 in-memory fixtures including a negative control (prose-only JSDoc + TS types -> zero hits) and a mixed-tag block (@deprecated + typed @param + prose @returns -> exactly one hit).

Policy doc at packages/superdoc/scripts/type-hygiene.md explains the rule, the fix pattern for each violation class, and the scope. The gate's failure message links to it.

Wrapper docs updated for the 11-stage chain: AGENTS.md (CLAUDE.md symlinks to it), scripts/check-public-contract.mjs header, packages/superdoc/scripts/README.md (new row for check-jsdoc-hygiene-ts.cjs + updated wrapper-stages paragraph).

Verified: scanner tests -> 13 passed; baseline scan -> 85 grandfathered; canary fixture (@param {string} added) -> correctly fails; line-shift canary (3 blank lines prepended to SuperDoc.ts) -> zero baseline churn; private-identifier rendering verified single-#; pnpm check:public:superdoc --skip-build -> PASS (10 ran with --skip-build, 1 skipped, 138.5s). The sibling pnpm check:jsdoc continues to enforce the .js side unchanged.

…-673)

Adds a new check:public:superdoc stage (jsdoc-hygiene-ts) that
enforces TypeScript-as-single-source on the .ts public contract
surface. Companion to the existing jsdoc-ratchet stage, which covers
.js files; together they enforce that each language's source files
use the right type system (TS syntax in .ts, JSDoc + @ts-check in .js)
without one polluting the other.

Scanner (check-jsdoc-hygiene-ts.cjs):
- Walks .ts source under packages/superdoc/src and
  packages/super-editor/src (excludes test/.d.ts files).
- Positive detection on tag name. ALWAYS_FLAG_TAGS: @type, @typedef,
  @callback, @template, @implements, @extends, @Augments, @enum.
  FLAG_WHEN_TYPED_TAGS: @param, @returns, @return, @this (only flagged
  when tag.typeExpression is set, so prose-only @param name description
  passes). Every other tag is ignored, including @deprecated, @example,
  @throws, @see, @typeparam.
- AST-based via ts.getJSDocTags + tag.typeExpression presence check;
  no regex on raw comment text. De-dupes per (file, pos, end, tag) so
  tags surfaced through multiple parent nodes count once.
- Classifies each violation as declaration-doc-type, inline-fake-cast,
  or typedef-style so the future cleanup PR can group fixes by type.

Baseline (jsdoc-hygiene-ts-baseline.json) records the 85 existing
violations grandfathered at PR time. The ratchet fails on net-new
entries or stale baseline entries (file cleaned up, snapshot still
records it). Refresh with --write after intentional cleanup. Goal is
to drain to zero, then flip to 'zero allowed' in a separate PR.

Scanner tests (check-jsdoc-hygiene-ts.test.cjs) protect against two
failure modes: silent false-positives (flagging legitimate doc tags)
and silent false-negatives (scanner produces nothing and looks like
it's working). 13 in-memory fixtures including a negative control
(prose-only JSDoc + TS types -> zero hits) and a mixed-tag block
(@deprecated + typed @param + prose @returns -> exactly one hit).

Policy doc at packages/superdoc/scripts/type-hygiene.md explains the
rule, the fix patterns for each violation class, and the scope. The
gate's failure message links to this doc so contributors hit a clear
path forward rather than a cryptic CI error.

Verified: scanner tests -> 13 passed, 0 failed; baseline scan -> 85
grandfathered, no net-new; canary fixture (added typed @param) ->
correctly fails with the new violation surfaced; pnpm
check:public:superdoc --skip-build -> PASS (10 ran, 1 skipped,
139.4s). Sibling pnpm check:jsdoc continues to enforce the .js side
unchanged.
…pdate wrapper docs

Three follow-ups to the initial scanner commit, all addressing review
feedback:

Baseline key was file:line:tag, which churned under unrelated edits.
Inserting 3 blank lines at the top of SuperDoc.ts (verified empirically)
would have produced one stale + one new baseline entry per
grandfathered violation in that file - ~40 false-positive ratchet
failures from a no-op edit. New key shape:

  file::enclosingSymbol::tagName::class::occurrenceIndex

Line stays in the violation record for human-readable display in
failure messages, but is NOT part of the identity tuple. Verified
that inserting 3 blank lines at the top of SuperDoc.ts now produces
zero stale/new churn (85 still grandfathered).

enclosingSymbol is the nearest named-declaration ancestor (function,
method, class, interface, type alias, variable). occurrenceIndex
disambiguates multiple same-name tags on the same symbol (e.g. two
@param tags on the same method).

Wrapper docs updated to reflect the 11-stage check:public:superdoc:
- AGENTS.md (CLAUDE.md symlinks to it): stage list + count.
- scripts/check-public-contract.mjs header: inserted stage 4
  (jsdoc-hygiene-ts), renumbered 5-11.

@typedef test fixture comment corrected: only @typedef fires
(ts.getJSDocTags does not surface @Property as a top-level tag); the
parent @typedef is the violation and the cleanup fix takes its
@Property lines with it.

Verified: 13/13 scanner tests pass; check:public:superdoc --skip-build
PASS (10 ran with --skip-build, 1 skipped, 126.6s); line-shift canary
on SuperDoc.ts produces no baseline churn.
…EADME

Three follow-ups addressing review feedback on the scanner PR:

enclosingSymbolName() only recognized Identifier names, so private
methods like `#privateMethod` collapsed onto their enclosing class's
key. Verified empirically: the previous baseline had 12 SuperDoc::
entries (6 distinct `SuperDoc::param` with occurrenceIndex 0-5), but
the SuperDoc class itself only carries @extends and @implements
JSDoc. The other 10 were private methods (#applyDocumentMode,
#abortUpgrade, etc.) all keyed as SuperDoc, which would have churned
unrelated indexes when any one of them was edited.

Fix:
- renderName() helper recognizes ts.isPrivateIdentifier (returns
  #name via nameNode.text so the leading # is preserved without
  depending on escapedText escape rules across TS versions) and
  string/numeric literal property names alongside identifiers.
- enclosingSymbolName() uses renderName() for direct .name, variable
  declarations, and variable statements.

Regenerated baseline. SuperDoc::SuperDoc:: entries dropped from 12 to
2 (the legit class-level @extends and @implements); 13 private-method
entries now anchor to their actual #name. Total count unchanged at
85 — same violations, more honest keys.

packages/superdoc/scripts/README.md updated with a row for
check-jsdoc-hygiene-ts.cjs alongside check-jsdoc.cjs, and the
wrapper-stages paragraph now lists jsdoc-hygiene-ts alongside the
other policy gates.

Scanner failure-message scope wording aligned with reality: was
"public contract surface," now "packages/superdoc/src or
packages/super-editor/src," matching the actual scan scope.

Verified: 13/13 scanner tests pass; check:public:superdoc --skip-build
PASS (10 ran, 1 skipped, 138.5s); single-# rendering on private
identifiers confirmed in baseline output.
…ublic summary

Two doc tweaks following review:

README.md wrapper-stages paragraph was correct in its count but the
prose ('Of these, six run as wrapper stages ... after [parenthetical
including public-method-coverage] and build: [list of five post-build
stages]') could be parsed as a mismatch. Rewrote to break public-
method-coverage out as 'runs alongside the cheap policy gates' so the
'five post-build' list reads cleanly as a subset rather than as the
total.

AGENTS.md check:public summary bullet listed every other gate but
omitted the new ts-jsdoc hygiene one; added it alongside 'jsdoc
ratchet'. The detailed check:public:superdoc bullet was already
correct.

Verified: file diffs only, no script changes; baseline + scanner
tests unchanged.
@caio-pizzol
caio-pizzol requested a review from a team as a code owner May 26, 2026 17:20
@linear-code

linear-code Bot commented May 26, 2026

Copy link
Copy Markdown

SD-673

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 7 files

Re-trigger cubic

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 89e75fbde5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/superdoc/scripts/check-jsdoc-hygiene-ts.cjs
…s vitest discovery on #3511)

CI failure on this PR: the unit-tests (other-packages) job runs vitest
across all non-superdoc packages, and the @superdoc package's vitest
config picked up packages/superdoc/scripts/check-jsdoc-hygiene-ts.test.cjs
via the *.test.* glob. The file is a standalone Node runner (not a
vitest suite), so vitest fails with:

  Error: No test suite found in file
  packages/superdoc/scripts/check-jsdoc-hygiene-ts.test.cjs
  Test Files  1 failed | 284 passed (285)

Local check:public:superdoc didn't catch this because it doesn't run
the broader vitest sweep.

Two-part fix:
- Rename check-jsdoc-hygiene-ts.test.cjs -> check-jsdoc-hygiene-ts-tests.cjs.
  The new name doesn't match vitest's *.test.* glob.
- Wire the self-tests in as wrapper stage 4 (jsdoc-hygiene-ts-test),
  running immediately before jsdoc-hygiene-ts. Self-tests had been
  manual-only; AST drift would have surfaced as a silent zero-result
  downstream. The stage runs the standalone Node script and asserts
  13 in-memory fixtures pass.

File header updated to reflect the rename and the stage wiring.
AGENTS.md / CLAUDE.md (symlinked) and scripts/check-public-contract.mjs
header now show 12 stages (was 11) with stage 4 = jsdoc-hygiene-ts-test.
packages/superdoc/scripts/README.md row updated for the rename plus the
wrapper-stages paragraph now includes the new stage.

Verified:
- pnpm check:types -> PASS
- node check-jsdoc-hygiene-ts-tests.cjs -> 13/13 pass
- pnpm check:public:superdoc --skip-build -> PASS (11 ran, 1 skipped,
  131.1s; was 10 before this commit added the test stage)
- pnpm --filter superdoc test --run -> PASS (1054/1054, 77 files;
  was 1 file failing before the rename)
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@caio-pizzol
caio-pizzol merged commit 8a3e40b into main May 26, 2026
71 checks passed
@caio-pizzol
caio-pizzol deleted the caio-pizzol/SD-jsdoc-hygiene-scanner branch May 26, 2026 20:14
caio-pizzol added a commit that referenced this pull request May 26, 2026
…(SD-673)

Drains the jsdoc-hygiene-ts baseline from 85 entries to 0. Companion
to the scanner PR (#3511) that grandfathered these entries; this is
the bulk mechanical cleanup. The zero-baseline flip lands in a third
PR after this.

declaration-doc-type (78 entries):
- @param {T} name description -> @param name description (drop braces,
  keep prose).
- @returns {T} description -> @returns description (drop braces, keep
  prose).
- @template T - description -> @typeparam T - description.
  TSDoc-canonical replacement; prose preserved (16 entries across
  Mark / Node / OxmlNode / defineMark / defineNode / Extension /
  EventEmitter / helpers).
- @extends {Base} / @implements {Iface} -> deleted (TS has native
  extends / implements syntax on the declaration).
- Empty @returns tags removed (10 dead documentation lines across
  both EventEmitters and PresentationEditor where the brace strip
  left a tag carrying no information).

inline-fake-cast (6 entries: 5 from original baseline + 1 new on
Editor.ts:219 that landed post-#3511):
- #abortUpgrade, readyEditors, pendingCollaborationSaves: the @type
  was redundant next to the TS field annotation. Dropped the tag,
  kept the prose.
- /** @type {RuntimeDocument} */ ... and /** @type {string} */ doc.id
  in SuperDoc.ts: real-intent casts that did nothing in .ts.
  Converted to 'as RuntimeDocument' and 'as string'.
- /** @type {YMapEvent<unknown>} */ on a Yjs observe callback param
  in SuperDoc.ts: converted to a TS param annotation
  (event: Y.YMapEvent<unknown>).
- /** @type {Mark[]} */ on insertionMarks in Editor.ts:219 (new in
  main since the scanner PR): converted to a TS local var
  annotation (PmMark[] is already imported).
- The InternalConfig doc example in types/index.ts was teaching the
  /** @type */ cast pattern explicitly. Rewrote to teach
  '(value as Type)' instead.

typedef-style (2 entries): rewrites. The @typedef tags lived inside
@example blocks in defineMark.ts / defineNode.ts teaching JS
consumers how to type-hint. Replaced literal /** @typedef */ syntax
with prose describing the pattern; preserves teaching value without
triggering the scanner.

Verified:
- node check-jsdoc-hygiene-ts.cjs -> OK, 0 violations
- node check-jsdoc-hygiene-ts-tests.cjs -> 13/13 pass
- pnpm check:types -> PASS
- pnpm check:public:superdoc --skip-build -> PASS (11 ran, 1 skipped,
  135.3s)
- pnpm --filter superdoc test --run -> PASS (1064/1064, 79 files)
caio-pizzol added a commit that referenced this pull request May 26, 2026
…jsdoc-hygiene-ts

Two pre-review trims on the strict-zero scanner:

- occurrenceIndex / occurrenceCounter were the stable-baseline-key
  mechanism. With strict-zero, there's no key — failure messages
  only need (file, line, tag, class, symbol) for display. Dropped
  the counter, the per-finding occurrenceIndex field, and the sort
  comparator that used it. Sort now keys on (file, line, tag) which
  is the natural display order for a scanner failure.

- Removed '#3513'/'#3511' from source/doc prose. PR numbers belong
  in PR bodies, not long-lived files. The scanner header and
  type-hygiene.md now use timeless wording ('no baseline,
  grandfathering, or --write mode').

No behavior change. Scanner output, exit codes, and the canary case
all match the previous commit.
superdoc-bot Bot pushed a commit that referenced this pull request May 29, 2026
### Bug Fixes

- copy-pasted text in suggestion mode (#3576)
- center virtualized matches after mount in find nav (SD-3315)
- stop find navigation jumping to the reverted caret (SD-3315)
- honor the focus() contract + fix dangling docs reference (SD-3312)
- don't re-center visible matches on find navigation (SD-3315)
- report 'zoom' not 'mixed' for a zoom repaint (SD-3311)
- wire pointer-source tracking on all init paths; update export snapshot
- reset state on unload, dedupe + export payload types, add core tests
- skip empty block SDT content selection
- type modules.contentControls exactly (no pass-through index)
- allow block SDT wrapper deletion to follow lock rules
- promote image-bearing inline SDT wrappers to inline-block
- keep block sdt fill behind content
- hide block sdt fills in output modes
- paint block SDT background on chrome layer
- use logical inset for inline SDT label position
- anchor inline SDT label to start of chrome
- route smartTag through export and preserve smartTagPr in SDT flatten (SD-2647)
- include inline SDT chrome width in block SDT bounds
- keep block SDT chrome at full fragment width
- render and round-trip w:smartTag content (SD-2647)
- decouple base64 image helper imports
- preserve block ids during metadata updates
- ignore covered sdt label clicks
- sync block sdt label selection updates
- show empty SDT placeholder text in viewing and print modes
- skip empty sdt scan on arrow right
- preserve permission-only sdt placeholders
- preserve comment-only sdt placeholders
- preserve empty sdt bookmark placeholders
- collapse hidden sdt placeholder text
- keep sdt placeholder pm range atomic
- trust empty sdt paragraph conversion
- keep vanished sdt paragraph side effects
- preserve vanished block sdt paragraphs
- suppress hidden block sdt chrome
- keep remeasured sdt placeholder atomic
- transform sdt placeholder measure
- remeasure sdt placeholders
- hide sdt placeholders in print
- hide sdt placeholders in viewing
- ignore collapsed inline sdt cut
- expose block sdt appearance
- hide empty block sdt placeholder
- align empty block sdt caret
- use measured width for empty SDT placeholders
- size SDT block labels to content width
- collapse selection on sdtContentLocked delete
- allow history transactions through sdt lock
- drop unreachable move fallback
- target marker-only textblock end
- ignore empty block sdt key targets
- cap block sdt label width
- handle sdt marker gaps and block atoms
- skip hidden field annotations in sdt navigation
- skip hidden metadata sdt markers
- skip hidden block sdt markers
- handle marker-only sdt paragraphs
- keep visible atoms in sdt navigation
- skip hidden sdt navigation markers
- target nearest sdt cursor position
- respect inline atoms in sdt navigation
- handle empty block sdt navigation
- avoid restoring dragged block to its source position
- exclude sdt chrome labels from caret position lookup
- keep text-align enabled in locked SDT paragraphs
- block disabled toolbar execution
- guard unlisted locked toolbar commands
- block locked sdt toolbar execution
- reject malformed base64 image data URIs
- reuse colliding data uri media targets
- enforce upload byte cap for data uris
- avoid non-image data uri extensions
- reject raw raster data uri dimensions
- validate oversized async svg images
- register preset raster data uris in place
- narrow sdt metadata overrides
- normalize image data uri extensions
- centralize image data url policy
- reuse target image relationships
- validate in-place svg payloads
- validate field annotation data uri exports
- reject malformed data uri files
- avoid duplicate image rids
- block raw raster data uri exports
- reject malformed svg data uri payloads
- warn on skipped image exports
- reject separatorless data uri files
- block non-image data uri exports
- read svg data uri dimensions
- share data uri media parsing
- skip invalid data uri image targets
- normalize svg data uri filenames
- validate in-place svg image data
- guard non-base64 data uri exports
- export field annotation svgs as svg
- allow non-base64 SVG data URLs in image rendering
- mirror in-place image media to parent
- decode non-base64 data URI exports
- extract shared hash helpers
- reuse data URI image exports
- support non-base64 data URI images in registration
- scope inline SDT placeholder to structuredContent metadata
- register sized SVG data URI images without canvas processing
- persist data URI images set via setPresetContent
- share SDT lock predicates
- version inline image metadata
- align RTL SDT chrome to text
- size SDT chrome for justified lines
- honor ancestor image SDT locks
- dirty inline image SDT changes
- align SDT chrome within paragraph width
- preserve SDT chrome continuation offsets
- offset block SDT chrome for indents
- suppress SDT pseudo hover in viewing mode
- allow top-aligned inline images
- fit block SDT chrome to actual content width
- bottom-align text on lines with inline images
- keep block SDT chrome and inline images out of paragraph geometry
- disable image resize inside content-locked SDTs
- detect inline image run changes in paragraph diff
- mark block SDT selected when contained image is selected
- select inline SDT content as text on Delete
- intercept beforeinput insertText at inline SDT boundaries
- delete contentLocked SDT wrapper in one step
- bump sdBlockRev on ancestors of inline edits
- select inline SDT content as text on Backspace
- select inline SDT on Backspace at start of following run (SD-3165)
- share structured content chrome label set
- resolve block labels at node boundary
- use contract label selectors
- clear label gesture state on cancel
- scope label clicks to owning editor
- defer label selection to mouseup so native drag still fires
- share structured content label classes
- avoid deferred block label retry
- select labels with active editor
- focus editor after label selection
- correct cursor placement and label interactions for structured content
- handle cell-level SDT in vMerge column lookup (SD-3289)
- preserve cell-level SDT wrapping table cells (SD-3289)
- preserve recipient identity attrs on replay (SD-3279)
- accept legacy fingerprints in compare/apply (SD-3279)
- drop misleading pnpm run type-check hint from audit
- structural-fail on missing dist + sync check-jsdoc header
- strip session-local sdBlockId from diff fingerprint (SD-3279)
- autoFit table width overflow from cell preferences (#3522)
- flip public-method-coverage to strict-zero gate (SD-673)
- flip jsdoc-hygiene-ts to strict-zero gate (SD-673)
- rename jsdoc-hygiene-ts self-tests + wire into CI (fixes vitest discovery on #3511)
- jsdoc-hygiene-ts handles private-identifier symbols + README
- more bugs
- add ui for overlapping delete, other fixes
- replacement pair
- remaining collab bugs
- coalesce tracked inserts across run gaps
- restore tracked change comment interactions
- expose tracked mark predicate option
- more cases
- tc fixes
- collab mode bug
- floating comments fixes
- make jsdoc-hygiene-ts baseline key line-independent + update wrapper docs
- preserve tab underline via runProperties fallback in collab

### Changes

- Merge branch 'main' into caio/sd-3315-find-replace-scroll
- Merge pull request #3509 from superdoc-dev/artem/SD-3232
- Merge pull request #3555 from superdoc-dev/luccas/delete-image-content-locked-sdt
- Merge branch 'main' into artem/SD-3159
- Merge pull request #3550 from superdoc-dev/luccas/sd-3302-bug-sdt-in-template-builder-shows-grey-background-highlight
- Merge branch 'main' into artem/SD-3159
- SD-2676 - fix: table selection not providing a feedback (#3508)
- Merge pull request #3549 from superdoc-dev/luccas/left-align-inline-sdt-label
- Merge pull request #3546 from superdoc-dev/caio/sd-2647-bug-render-and-round-trip-content-wrapped-in-wsmarttag
- Merge remote-tracking branch 'origin/stable' into sync/stable-to-main-20260527-230540
- Merge pull request #3539 from superdoc-dev/caio-pizzol/sd-3289-preserve-cell-level-sdt
- Merge pull request #3527 from superdoc-dev/caio-pizzol/sd-3279-strip-sdblockid-from-diff-fingerprint
- Merge branch 'main' into caio-pizzol/SD-js-contract-owner-audit
- Merge pull request #3531 from superdoc-dev/caio-pizzol/SD-docs-snippet-typecheck-2
- Merge pull request #3526 from superdoc-dev/caio-pizzol/SD-runtime-payload-tests
- Merge pull request #3521 from superdoc-dev/caio-pizzol/SD-public-method-coverage-strict-zero
- Merge branch 'stable'
- Merge pull request #3485 from superdoc-dev/artem/SD-3200
- Merge pull request #3517 from superdoc-dev/caio-pizzol/SD-jsdoc-hygiene-zero-flip
- Merge pull request #3513 from superdoc-dev/caio-pizzol/SD-jsdoc-hygiene-cleanup
- Merge branch 'stable'
- Merge pull request #3511 from superdoc-dev/caio-pizzol/SD-jsdoc-hygiene-scanner
- Merge pull request #3435 from superdoc-dev/nick/sd-3220-overlapping-suggestion-contract
- Merge pull request #3429 from superdoc-dev/artem/underlined-tab-collab

### Documentation

- note content controls in entityAt hit types (SD-3313)
- clarify data uri buffer conversion
- document image data uri helpers
- clarify image registration comments
- sync README exit semantics for js contract-owner audit
- clarify wrapper-stages prose + add ts-jsdoc to check:public summary

### Features

- add ui.contentControls.focus to place the caret in a control (SD-3312)
- add ui.viewport.observe geometry-invalidation signal (SD-3311)
- add ui.contentControls.scrollIntoView (SD-3310)
- add activePath (full active stack) to content-control:active-change
- expose public sdt events
- select adjacent block SDT content at textblock boundaries
- inherit run styles in empty block SDT placeholders
- render placeholder text for empty SDTs
- move caret into following block sdt on delete
- move caret into preceding block sdt on backspace
- disable mutation toolbar controls inside content-locked SDTs
- render empty inline SDTs as a visible placeholder
- add modules.contentControls.chrome
- js contract-owner audit, report-only (SD-673)
- add snippet typecheck for editor/superdoc/** + fix stale examples (SD-673)
- add non-hover field color for sdt (#3506)
- comments and tc on small screen (#3446)
- overlapping tracked changes
- add type-bearing JSDoc hygiene gate for .ts source (SD-673)
- add anchored metadata orphan status

### Tests

- resolve handleBase64 source path from package or repo root
- cover locked block SDT Delete selection
- cover nested block SDT boundary selection
- update SDT keymap chain coverage
- cover contentControlsChrome plumbing; clarify chrome-none comment
- assert chrome-none hover suppression and cascade order
- add v2 bridge unit + round-trip behavior coverage (SD-2647)
- assert smartTag child text survives export round-trip (SD-2647)
- cover nested block sdt navigation
- roundtrip mixed image block sdts
- cover image data uri length boundary
- repaint saved sdt images through painter
- cover structured content image edges
- cover inline image diff fields
- cover locked inline SDT beforeinput
- cover inline SDT Cmd+X selection
- cover inline SDT content Delete flow
- clarify inline SDT boundary lock comment
- cover two-step inline SDT Backspace
- cover inline SDT selection meta escape
- use real production payload for list-definitions-change bridge (SD-673)
- tighten list-definitions-change bridge assertion (SD-673)
- pin list-definitions-change bridge and DELETED comments shape (SD-673)
- pin runtime event payload shapes (SD-673)

### Refactoring

- consolidate type imports in dom painter
- share block sdt navigation helpers
- share box model between block and inline sdt labels
- share structured content predicates
- wrap shared tryDecodeDataUriText re-export
- reuse shared data uri export policy
- share image relationship export lookup
- centralize image data uri parsing
- share data uri text decoding
- trim data uri metadata fields
- extract CHECKED_FILES to shared module + drop audit from wrapper
- drop list-item fragment renderer (SD-2851) (#3269)
- drain 85 type-bearing JSDoc entries from .ts source (SD-673)

### Performance

- avoid scanning data uri media

### Chores

- 1.37.0 [skip ci]
- fix import breaking delinstrtext orphans (#3535)
- fix tests (#3533)
- fixes
- more fixes
- run generate:all and fixes
- more fixes
- soec fixes
- type fixes
- ui and more
- fix regression
- type fixes
- more fixes
- more fixes
- ci fixes
- type fixes
- add dispatch test for collab bug
- review fix, type fix
- add tests for metadata issue
- tests for review issues
@superdoc-bot

superdoc-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in superdoc-cli v0.15.0

The release is available on GitHub release

@superdoc-bot

superdoc-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in superdoc-sdk v1.14.0

@superdoc-bot

superdoc-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in @superdoc-dev/mcp v0.10.0

The release is available on GitHub release

@superdoc-bot

superdoc-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in superdoc v1.38.0

The release is available on GitHub release

@superdoc-bot

superdoc-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in @superdoc-dev/react v1.9.0

The release is available on GitHub release

@superdoc-bot

superdoc-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in vscode-ext v2.10.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants