Skip to content

Support deprecated - #136

Merged
jdesrosiers merged 14 commits into
hyperjump-io:mainfrom
Suyog241005:support-deprecated
Oct 13, 2026
Merged

jdesrosiers merged 14 commits into
hyperjump-io:mainfrom
Suyog241005:support-deprecated

Conversation

@Suyog241005

@Suyog241005 Suyog241005 commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR adds support for the standard deprecated keyword and VS Code's custom deprecationMessage and markdownDeprecationMessage keywords. It was rebuilt on top of #139 and follows its split between location annotations and value annotations.

What changed

  • Registered deprecationMessage and markdownDeprecationMessage in the vscode vocabulary, with meta-schema entries.
  • JsonSchemaAnnotation gets a deprecated() accessor for the standard keyword. VscodeAnnotation adds deprecationMessage() and markdownDeprecationMessage(), and overrides deprecated() so a message deprecates on its own. Schemas that don't use the vocabulary still work through the unknown# annotations.
  • A small findDeprecated helper picks the deprecated annotation that carries a message, so every feature below applies the same rule.
  • Hover: appends ⚠️ **Deprecated:** <message>, or ⚠️ **Deprecated** when only deprecated: true is set. Hovering a key uses location annotations; hovering a value adds value annotations, the same way descriptions already work.
  • Diagnostics: new DeprecatedDiagnosticsProvider reports a Warning tagged Deprecated. A deprecated location is marked on the property key, a deprecated value is marked on the value, and both are marked when both apply.
  • Property completions: tagged Deprecated with the message as documentation, based on location annotations only. A property whose values are only conditionally deprecated is not tagged.
  • Value completions: tagged based on each completion's own annotations, so a deprecated anyOf alternative is tagged while values of a deprecated location are not.

Screenshots

Deprecated locations are marked on the key, deprecated values on the value. foo is a deprecated location, "a" is a deprecated value, baz and "c" are both.

Screenshot 2026-10-08 at 2 50 25 PM

A value of a deprecated location isn't deprecated unless z, and "legacy" remain marked.

Screenshot 2026-10-08 at 2 51 33 PM

Value completions are tagged per value. "a" is deprecatedentation, "b" is not.

Screenshot 2026-10-08 at 2 53 02 PM

Closes #97
Closes #86

@Suyog241005

Copy link
Copy Markdown
Contributor Author

Hi @jdesrosiers, this is ready for review whenever you have time.

@jdesrosiers jdesrosiers left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As I described in #139, you're going to have to do this again. But, this time you'll have the right foundation to do it right. Sorry for the churn.

@Suyog241005

Copy link
Copy Markdown
Contributor Author

@jdesrosiers No problem, done. Rebuilt on top of #139 using the location vs value annotation split. The anyOf case from #86 now works too, since completions carry their own annotations. Description and screenshots are updated. Ready for another look.

@jdesrosiers jdesrosiers left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I pushed a couple bug fixes and some additional tests. There are a few additional things inline for you to look into.

Comment thread language-server/src/features/Hover.ts Outdated
Comment on lines +53 to +58
const deprecated = findDeprecated(annotations);
if (deprecated) {
const message = deprecated.markdownDeprecationMessage();
lines.push(message ? `⚠️ **Deprecated:** ${message}` : "⚠️ **Deprecated**");
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We don't want deprecated messaging in Hover. The deprecated diagnostic already displays the message on hover, so this just duplicates it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed, along with its tests.

Comment on lines +9 to +14
// The annotation that deprecates a location or value, preferring one that
// says why. Undefined if none of them deprecate it.
export const findDeprecated = (annotations: Annotation[]): Annotation | undefined => {
const deprecated = annotations.filter((annotation) => annotation.deprecated());
return deprecated.find((annotation) => annotation.markdownDeprecationMessage() !== undefined) ?? deprecated[0];
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Using find here is problematic because there could be multiple subschemas that applied to the location that include deprecation annotations. We need to take all of them into account similar to how we handle multiple title/description keywords in Hover.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Replaced with filtering every annotation that deprecates the location or value. Diagnostics join all the messages, and completion documentation does the same. Added tests for two allOf branches each contributing a message.

Comment on lines +67 to +70
const message = deprecated.markdownDeprecationMessage();
if (message) {
completionItem.documentation = { kind: MarkupKind.Markdown, value: message };
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The way markdownDeprecationMessage is implemented, you might get back the non-markdown deprecationMessage, but you're using MarkupKind.Markdown in either case. The non-markdown case should use Markup.PlainText.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. markdownDeprecationMessage no longer falls back to deprecationMessage, so the documentation kind is PlainText unless at least one annotation has a markdown message. Tests cover plain, markdown, and mixed.

@Suyog241005
Suyog241005 force-pushed the support-deprecated branch 2 times, most recently from 3b1156a to 0135a8d Compare October 11, 2026 07:40
@Suyog241005

Copy link
Copy Markdown
Contributor Author

Thanks for the fixes and extra tests. Addressed all three comments:

  • Hover no longer shows deprecation.
  • Every schema that deprecates a location or value contributes its message instead of picking one.
  • Completion documentation is plain text unless a markdownDeprecationMessage is present.

Suyog241005 and others added 14 commits October 13, 2026 13:34
Registers deprecationMessage and markdownDeprecationMessage in the vscode
vocabulary. JsonSchemaAnnotation gets a deprecated accessor for the
standard keyword and VscodeAnnotation adds the message accessors, which
also deprecate on their own. Hover shows a notice after the description.
A deprecated property is marked on its key no matter what its value is.
A value deprecated by the schema branch that matched it, such as an anyOf
alternative, is marked on the value.
Uses the location annotations of the candidate property, so a property
whose values are only conditionally deprecated isn't tagged.
Uses the annotations of each completion value, so values of a deprecated
location aren't tagged unless they're deprecated themselves.
walkNodes doesn't visit properties without a value node, so a deprecated
key was never reported while the property was still being typed. Check
properties from their object instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ated tag

Without the deprecated tag, the client can't strike through deprecated
text, so the diagnostics would just be noise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cover invalid values, nested properties, deprecation reached through
$ref, allOf, oneOf, and not, deprecated type alternatives,
intersections, and properties deprecated in an alternative of their
parent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The deprecated diagnostic already shows the message on hover.
More than one schema can deprecate the same location, so all of their
messages are reported instead of just one. Completion documentation is
plain text unless a markdownDeprecationMessage is present.
The diagnostic used the empty string as its message instead of falling
back to "Deprecated", while hover and completions treated it as no
message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
deprecated is an unknown keyword in draft-04/06/07, so its annotation
was only found under the unknown keyword URI. VS Code's JSON support
honors it in those dialects too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
getPointerForNode walks up to the root and looks up array indexes with
indexOf, so calling it for every node made deprecated diagnostics and
collectIncompleteLocations quadratic in the size of large arrays.
walkNodes now passes each node's pointer to the callback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When any deprecation message is markdown, completion documentation is
markdown, so plain text messages joined with it were rendered as markup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jdesrosiers
jdesrosiers merged commit 5470552 into hyperjump-io:main Oct 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support deprecationMessage custom keyword Support "deprecated"

2 participants