Skip to content

feat: Add opt-in JSON-LD schema support - #1375

Open
dev-geddy wants to merge 1 commit into
acacode:mainfrom
dev-geddy:feat/add-jsonld-schema-support
Open

feat: Add opt-in JSON-LD schema support#1375
dev-geddy wants to merge 1 commit into
acacode:mainfrom
dev-geddy:feat/add-jsonld-schema-support

Conversation

@dev-geddy

@dev-geddy dev-geddy commented Aug 26, 2025

Copy link
Copy Markdown

Adds optional JSON-LD support. Off by default, no effect on existing specs.

  • Enable with --jsonld (or jsonLdOptions.enabled)
  • Schemas opt in with the x-jsonld extension
  • Entities get typed @context, @type, @id and extend a shared JsonLdEntity
  • A x-jsonld-type schema with no properties becomes a string union alias
  • Modular output adds jsonld-entity and jsonld-utils, re-exported from data-contracts
  • generateUtils: false emits plain interfaces with no shared module

Problem

If your API returns JSON-LD, the generated types don't mean much. @context becomes object, nothing connects the JSON-LD fields across entities, and there are no shared types for things like @graph or node references:

export interface Person {
  "@context"?: object;
  "@type": "Person" | "https://schema.org/Person";
  "@id"?: string;
  name: string;
}

So you end up writing those types by hand next to the generated file.

Solution

Two things must both be true for anything to change: the schema declares x-jsonld (or x-jsonld-context / x-jsonld-type / x-jsonld-id), and you pass --jsonld. Otherwise output is identical to before.

Under the hood this adds two schema types, jsonld-entity and jsonld-type, as MonoSchemaParser subclasses dispatched from getInternalSchemaType — the same way enum, object and array already work. No new pipeline stage.

An entity now looks like:

import type { JsonLdContext, JsonLdEntity } from "./jsonld-utils";

/** JSON-LD Entity: Person */
export interface Person extends JsonLdEntity {
  "@context"?: JsonLdContext;
  "@type": "https://schema.org/Person";
  "@id"?: string;
  name: string;
}

And a type-only schema becomes an alias, staying in data-contracts with the other aliases:

export type PersonType = "Person" | "Patient";

A few choices worth flagging:

  • Detection is explicit. I didn't auto-detect from @context/@type/@id property names, since those are valid property names in a normal spec and it would change output for people who never asked for it.
  • The input document is never modified.
  • Only entities move to their own file in modular mode, and data-contracts re-exports them. Route modules import models from data-contracts only, so without the re-export their imports would break.
  • @context uses JsonLdContext rather than a structural type. object or (string | object)[] isn't assignable to JsonLdEntity["@context"], so the generated file wouldn't compile. Literal string contexts keep their literal type.

Verification

bun run build, bun run format:check and bun run test pass — 293 tests, no type errors.

tests/spec/jsonld-basic/ covers single-file output, the disabled default, modular output (including that route module imports still resolve), the generateUtils: false path, a mixed JSON-LD/plain spec, and the type alias case.

I also compiled the real generated output rather than only snapshotting it: for all three modes the emitted files pass tsc --noEmit --strict with the generated // @ts-nocheck header removed, so the check isn't suppressed.

Notes

Rebased onto current main and squashed to one commit. The rebase surfaced that the project had moved to es-toolkit, which this now uses.

An earlier version had a generateContext option with its own parser and template. They're gone: nothing could produce a jsonld-context schema type, so the option did nothing and the code was unreachable. Happy to build a real context output if that's wanted, but it should be deliberate rather than dead code.

@changeset-bot

changeset-bot Bot commented Aug 26, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: aa0de6a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
swagger-typescript-api Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@smorimoto

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@dev-geddy
dev-geddy force-pushed the feat/add-jsonld-schema-support branch from 6de32e5 to 2c0e0b7 Compare September 3, 2025 20:04
@smorimoto

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@smorimoto

Copy link
Copy Markdown
Collaborator

@codex review

chatgpt-codex-connector[bot]

This comment was marked as outdated.

@smorimoto smorimoto added the enhancement New feature or request label Sep 16, 2025
@dev-geddy

Copy link
Copy Markdown
Author

@codex fix comments

@chatgpt-codex-connector

This comment was marked as off-topic.

@dev-geddy
dev-geddy force-pushed the feat/add-jsonld-schema-support branch from 314f0e3 to 045fe31 Compare September 24, 2025 21:50
@smorimoto

Copy link
Copy Markdown
Collaborator

@codex review

chatgpt-codex-connector[bot]

This comment was marked as outdated.

@smorimoto

Copy link
Copy Markdown
Collaborator

@codex review

@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.

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting

Comment thread src/jsonld-schema-resolver.ts Outdated
@dev-geddy
dev-geddy force-pushed the feat/add-jsonld-schema-support branch from f3d7d0d to a8db0f0 Compare October 14, 2025 18:57
@dev-geddy
dev-geddy force-pushed the feat/add-jsonld-schema-support branch from a8db0f0 to da101f1 Compare July 29, 2026 12:57
Schemas that declare the `x-jsonld` extension (or one of `x-jsonld-context`,
`x-jsonld-type`, `x-jsonld-id`) are parsed as JSON-LD when the new
`jsonLdOptions.enabled` option is set (CLI: `--jsonld`).

Entities get typed `@context`, `@type` and `@id` members and extend a shared
`JsonLdEntity` interface. A property-less `x-jsonld-type` schema becomes a
string-literal type alias and stays in `data-contracts` alongside the other
aliases. In modular output entities are emitted as `jsonld-entity` and the
shared interfaces as `jsonld-utils`, both re-exported from `data-contracts`
so route modules keep importing their models from a single place. Setting
`jsonLdOptions.generateUtils` to `false` emits standalone entity interfaces
instead.

Detection is explicit — no auto-discovery from `@context`/`@type`/`@id`
property names — and the input document is never mutated, so specs without
the extension and runs without `--jsonld` produce unchanged output.

Tests cover single-file and modular output, the disabled default, the
`generateUtils` opt-out, mixed JSON-LD/plain specs, and the type-alias path.
Generated output for all three modes type-checks under `--strict`.
@dev-geddy
dev-geddy force-pushed the feat/add-jsonld-schema-support branch from da101f1 to aa0de6a Compare July 29, 2026 14:56
@dev-geddy dev-geddy changed the title feat: add jsonld schema support feat: Add opt-in JSON-LD schema support Jul 29, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants