<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://speclynx.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://speclynx.com/" rel="alternate" type="text/html" /><updated>2026-09-03T17:56:44+00:00</updated><id>https://speclynx.com/feed.xml</id><title type="html">SpecLynx</title><subtitle>SpecLynx is enterprise-ready API tooling for parsing, validating, transforming, and working with OpenAPI, AsyncAPI, Arazzo, Overlay, and JSON Schema.</subtitle><entry><title type="html">One Overlay, three JSONPaths: should a compliant implementation accept dialects?</title><link href="https://speclynx.com/blog/overlay-jsonpath-dialects/" rel="alternate" type="text/html" title="One Overlay, three JSONPaths: should a compliant implementation accept dialects?" /><published>2026-08-19T08:00:00+00:00</published><updated>2026-08-19T08:00:00+00:00</updated><id>https://speclynx.com/blog/overlay-jsonpath-dialects</id><content type="html" xml:base="https://speclynx.com/blog/overlay-jsonpath-dialects/"><![CDATA[<p>A standards body for the banking industry writes five <a href="https://spec.openapis.org/overlay/v1.1.0.html">OpenAPI Overlays</a>, one per API, to stamp regulatory annotations onto schemas that don’t already carry them. The overlays are tested against a popular CLI and produce exactly the expected output. Then someone runs the same five files through a different Overlay tool, and every one of them fails on the first action:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Error: Invalid JSONPath expression:
  "$.components.schemas.*[?(!@.x-fdx-csdf-account-categories &amp;&amp; !@.x-fdx-csdf-technical)]".
  Syntax error at position 29, expected "[", "*", "_", "0", "-", ":", "!", "(", "@", "$", "-0", ".", "..", "&amp;&amp;", "||"
</code></pre></div></div>

<p>Nothing about the overlays changed. Nothing about the API descriptions changed. What changed is <em>which JSONPath</em> the tool on the other end speaks. That is the subject of this post: when an Overlay implementation is handed an expression written for a different JSONPath dialect, should it try to understand it anyway, or refuse?</p>

<p>Our answer is <strong>refuse, and be helpful about it</strong>. A canonical implementation should be strict about what it consumes. The rest of this post is the reasoning: what the dialects are, what the spec says, what other tools do, the honest case for leniency, and why strictness still wins.</p>

<h2 id="there-is-no-single-jsonpath-until-recently">There is no single JSONPath (until recently)</h2>

<p>JSONPath started as a <a href="https://goessner.net/articles/JsonPath/">2007 blog post by Stefan Gössner</a>. It described a syntax, shipped a JavaScript implementation with <code class="language-plaintext highlighter-rouge">eval()</code> inside, and left plenty unspecified. Every language ecosystem then grew its own interpretation:</p>

<ul>
  <li>
    <p><strong>Goessner-style</strong> libraries (<code class="language-plaintext highlighter-rouge">jsonpath</code> on npm, most Python and Java ports) are the classic. Filter expressions are small scripts handed to the host language, so anything the host can evaluate, including its regex syntax and its comparison operators, “works”.</p>
  </li>
  <li>
    <p><strong>JSONPath Plus</strong> is a popular fork that added selectors the original never had: a parent selector, a property-name selector, and a handful of <code class="language-plaintext highlighter-rouge">@</code>-prefixed helpers and type selectors. Stoplight’s Spectral runs on this dialect: its own Nimma engine supports most JSONPath Plus additions, it falls back to <code class="language-plaintext highlighter-rouge">jsonpath-plus</code> for compatibility, and its docs say it is <a href="https://github.com/stoplightio/spectral/blob/develop/docs/guides/4a-rules.md#given">not yet aligned with RFC 9535</a>. A lot of developers have muscle memory from writing rulesets against exactly this syntax.</p>
  </li>
  <li>
    <p><strong>RFC 9535</strong> is the <a href="https://www.rfc-editor.org/rfc/rfc9535.html">IETF standard</a>, published February 2024. Names in brackets must be quoted, names after a dot are limited to letters, digits and underscores, filters are a real expression grammar rather than host-language code, and regexes and lengths come from a fixed set of functions. For a compliant implementation in JavaScript, see <a href="https://github.com/swaggerexpert/jsonpath"><code class="language-plaintext highlighter-rouge">@swaggerexpert/jsonpath</code></a>.</p>
  </li>
</ul>

<p>For everyday paths (a named operation, all schemas under <code class="language-plaintext highlighter-rouge">components</code>, parameters filtered by <code class="language-plaintext highlighter-rouge">in</code>) all three agree. Then the edges bite:</p>

<div class="table-scroll">

  <table>
    <thead>
      <tr>
        <th>You wrote</th>
        <th>Goessner</th>
        <th>Plus</th>
        <th>RFC 9535</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">$..[?(!@.x-fdx-csdf-technical)]</code></td>
        <td>Silently matches nothing (read as <code class="language-plaintext highlighter-rouge">@.x - fdx - …</code>); the legacy Go engine in the story accepts it</td>
        <td>Error: <code class="language-plaintext highlighter-rouge">fdx is not defined</code></td>
        <td>Parse error at the <code class="language-plaintext highlighter-rouge">-</code>; hyphenated names need brackets: <code class="language-plaintext highlighter-rouge">!@['x-fdx-csdf-technical']</code></td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">$..[?(@.deprecated === true)]</code></td>
        <td>OK (JS <code class="language-plaintext highlighter-rouge">===</code>)</td>
        <td>OK</td>
        <td>Parse error; only <code class="language-plaintext highlighter-rouge">==</code></td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">$..[?(@.name.match(/^x-/))]</code></td>
        <td>OK (host regex)</td>
        <td>OK, if guarded against nodes without <code class="language-plaintext highlighter-rouge">name</code>; throws otherwise</td>
        <td>Parse error; use <code class="language-plaintext highlighter-rouge">match(@.name, "x-.*")</code></td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">$..parameters^</code></td>
        <td>Parse error</td>
        <td>OK (parent selector)</td>
        <td>Parse error; no parent selector</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">$.paths[*]~</code></td>
        <td>Parse error</td>
        <td>OK (property-name selector)</td>
        <td>Parse error</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">$.info[?length(@.title) &gt; 40]</code></td>
        <td>Parse error</td>
        <td>Silently matches nothing</td>
        <td>OK; standard function</td>
      </tr>
      <tr>
        <td><code class="language-plaintext highlighter-rouge">$['paths']['/pets']</code></td>
        <td>OK</td>
        <td>OK</td>
        <td>OK; this is RFC’s <em>normalized path</em> form</td>
      </tr>
    </tbody>
  </table>

</div>

<p><small>Goessner and Plus columns checked against <code class="language-plaintext highlighter-rouge">jsonpath</code> 1.1.1 and <code class="language-plaintext highlighter-rouge">jsonpath-plus</code> 10.x; the RFC 9535 column against <code class="language-plaintext highlighter-rouge">@swaggerexpert/jsonpath</code>.</small></p>

<p>The first row is the shape of the banking overlays from the opening. Position 29 of the original expression is the hyphen in <code class="language-plaintext highlighter-rouge">x-fdx-csdf-account-categories</code>: a member name that RFC 9535’s dot-notation grammar doesn’t allow, and that a lenient parser happily reads through. Same file, two meanings of “valid”.</p>

<h2 id="what-the-overlay-spec-actually-says">What the Overlay spec actually says</h2>

<p>Overlay 1.0.0 (October 2024) defined <code class="language-plaintext highlighter-rouge">target</code> as “a JSONPath expression selecting nodes in the target document” and cited RFC 9535 as a normative reference. The wording was soft, but the intent was clear, and implementers generally read it the same way: RFC 9535 was the JSONPath the spec meant.</p>

<p>Overlay 1.1.0 (January 2026) closed the gap with a dedicated section, <a href="https://spec.openapis.org/overlay/v1.1.0.html#rfc9535-compliance"><em>RFC9535 Compliance</em></a>:</p>

<blockquote>
  <p>A tool or library MUST fully implement RFC9535 when parsing and expanding JSONPath query expressions to be compliant with the Overlay specification.</p>

  <p>Interoperable Overlay Documents MUST use RFC9535 JSONPath query expressions and MUST NOT use tool-specific JSONPath extensions.</p>
</blockquote>

<p>So the spec answers half the question: a compliant implementation <strong>must</strong> speak RFC 9535, and a portable overlay <strong>must not</strong> rely on anything else. What it doesn’t say is whether an implementation <em>may</em> also accept other dialects as a courtesy.</p>

<h2 id="what-the-ecosystem-actually-does">What the ecosystem actually does</h2>

<p>A quick survey of open-source Overlay tooling, as of this writing:</p>

<ul>
  <li><a href="https://github.com/lornajane/openapi-overlays-js"><code class="language-plaintext highlighter-rouge">openapi-overlays-js</code></a> (Lorna Mitchell’s reference-style implementation) depends on the <code class="language-plaintext highlighter-rouge">jsonpath</code> package: the Goessner dialect.</li>
  <li><a href="https://github.com/bump-sh/cli">Bump.sh CLI</a> runs its overlay support on <code class="language-plaintext highlighter-rouge">jsonpathly</code>, which since version 3 is an RFC 9535 implementation.</li>
  <li><a href="https://github.com/speakeasy-api/openapi/tree/main/overlay">Speakeasy</a> picks the dialect by Overlay version: a 1.0.0 document is evaluated with its legacy, Goessner-inspired <code class="language-plaintext highlighter-rouge">yaml-jsonpath</code> engine by default (with a warning on expressions that aren’t valid RFC 9535, and an opt-in <code class="language-plaintext highlighter-rouge">x-speakeasy-jsonpath: rfc9535</code> extension), while a 1.1.0 document gets RFC 9535 by default with an opt-out back to legacy. It also ships an upgrade helper that moves an overlay from 1.0.0 to 1.1.0.</li>
  <li><a href="/cli/">SpecLynx CLI</a> and <a href="https://github.com/speclynx/apidom/tree/main/packages/apidom-overlay"><code class="language-plaintext highlighter-rouge">@speclynx/apidom-overlay</code></a> evaluate targets with <code class="language-plaintext highlighter-rouge">@speclynx/apidom-json-path</code>, which is RFC 9535-only for every Overlay version.</li>
</ul>

<p>So the picture isn’t simply “Goessner tools vs. RFC tools”. The same <code class="language-plaintext highlighter-rouge">target</code> string can be evaluated by a Goessner engine, an RFC engine, or either one depending on the <code class="language-plaintext highlighter-rouge">overlay:</code> version field at the top of the file, and the spec says only one of those behaviours is compliant. The banking overlays from the opening were Overlay 1.0.0 documents, so the first CLI read them with its legacy engine, where hyphenated dot-names are fine. The second CLI read them as RFC 9535, where they aren’t.</p>

<h2 id="the-case-for-being-lenient-a-fair-hearing">The case for being lenient: a fair hearing</h2>

<p>It’s a real case, so let’s make it honestly.</p>

<p><strong>Existing overlays.</strong> People wrote overlays before 1.1.0 made the rule explicit, against whatever their tool accepted. Rejecting those files is friction on day one: five failing overlays and a bug report, in the story above.</p>

<p><strong>Postel’s law.</strong> “Be conservative in what you send, liberal in what you accept” is the oldest instinct in protocol design. Accepting Goessner and Plus syntax alongside RFC 9535 would mean more overlays Just Work.</p>

<p><strong>Adoption.</strong> Overlays are still early. A tool that says “no” to a working file is a tool people route around.</p>

<p>The strongest form of this argument is the one Speakeasy actually built: don’t guess, <em>version-gate</em>. Treat the <code class="language-plaintext highlighter-rouge">overlay: 1.0.0</code> header as permission to use the old engine, warn loudly when an expression wouldn’t survive RFC 9535, make the standard the default the moment the author writes <code class="language-plaintext highlighter-rouge">1.1.0</code>, and give them a one-command upgrade. That is leniency with a migration path designed in, and it’s a reasonable way to carry an existing user base across the line.</p>

<h2 id="why-strict-wins">Why strict wins</h2>

<p>And here’s why, for all that, the lenient case loses for a <em>canonical</em> implementation, the one meant to define what “correct” means.</p>

<p><strong>An overlay is a portable artifact, not a script.</strong> Its whole value is that the same file can be applied by your docs tool, your SDK generator, and your CI gate and produce the same result. Every dialect an implementation accepts, even deliberately and with warnings, is a file that will break the moment it meets an implementation that doesn’t. Leniency doesn’t remove the interoperability problem; it moves it downstream, to someone who didn’t write the overlay and can’t see why it fails. That’s exactly how five overlays that “worked” arrived at a tool that couldn’t read them: the version gate kept them working in one place and tool-specific everywhere else.</p>

<p><strong>Postel’s law has a known failure mode.</strong> The IETF itself revisited the robustness principle in <a href="https://www.rfc-editor.org/rfc/rfc9413.html">RFC 9413, <em>Maintaining Robust Protocols</em></a> (2023): tolerating deviations lets them harden into de-facto requirements, and the ecosystem ossifies around the most lenient implementation instead of the standard. JSONPath’s two decades of dialect drift <em>are</em> that failure mode. RFC 9535 exists to end it, and an Overlay implementation that re-admits the dialects undoes the work.</p>

<p><strong>Ambiguity is worse than an error.</strong> Some expressions parse in more than one dialect with different meanings. A lenient implementation has to guess which one the author meant. Guessing wrong doesn’t error; it edits the wrong node. For a tool whose job is to modify API contracts, a loud parse error is the kinder outcome.</p>

<p><strong>“Strict input” still leaves room to help.</strong> Strictness is about what the implementation <em>applies</em>, not about how it treats the person. An error that names the offending expression and the exact position, plus a hint toward the RFC form, turns a rejection into a minutes-long fix. A linter or converter for legacy overlays can be a separate, honest tool; it doesn’t have to live inside <code class="language-plaintext highlighter-rouge">apply</code>.</p>

<h2 id="where-speclynx-landed">Where SpecLynx landed</h2>

<p>SpecLynx is RFC 9535 only, because the Overlay specification requires it and because we think that’s the right answer for a canonical implementation: <code class="language-plaintext highlighter-rouge">@speclynx/apidom-json-path</code> is fully RFC 9535 compliant, and <a href="/cli/">SpecLynx CLI</a> evaluates every <code class="language-plaintext highlighter-rouge">target</code> with it, whatever the overlay’s version field says:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npx @speclynx/cli overlay apply overlay.yaml openapi.yaml
</code></pre></div></div>

<p>An expression that isn’t valid RFC 9535 is rejected with a parse error that points at the offending position and lists what the grammar would have accepted there (the message at the top of this post is SpecLynx’s) rather than guessed at. The other common way an overlay silently does nothing is a target that matches no nodes at all; <code class="language-plaintext highlighter-rouge">--strict</code> turns that into a failure too:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npx @speclynx/cli overlay apply overlay.yaml openapi.yaml <span class="nt">--strict</span>
</code></pre></div></div>

<p>The opening story is real: <a href="https://github.com/speclynx/speclynx-cli/issues/127">speclynx-cli#127</a>. The fix on the overlay side was mechanical (bracket the hyphenated names) and the author had all five working the same day.</p>

<h3 id="migrating-an-existing-overlay">Migrating an existing overlay</h3>

<p>If you maintain overlays written against a Goessner or JSONPath Plus tool, the migration usually is that mechanical: quote bracketed names and anything with a hyphen, replace host-language regexes with <code class="language-plaintext highlighter-rouge">match()</code>/<code class="language-plaintext highlighter-rouge">search()</code>, and rewrite parent/property selectors as explicit paths. The table above covers most of what we’ve seen. The <a href="https://github.com/swaggerexpert/jsonpath#validation"><code class="language-plaintext highlighter-rouge">@swaggerexpert/jsonpath</code> validator</a> and <a href="https://jsonpath.com/">jsonpath.com</a> (in its RFC 9535 mode; it also offers a JSONPath Plus mode, which is the whole point of this post) will tell you whether an expression is valid RFC 9535 before you run anything.</p>

<p>For a larger batch, the prompt below does the conversion with any AI assistant, and is the one we handed over in that issue:</p>

<details>
  <summary>Migration prompt for an AI assistant</summary>

  <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You are a JSONPath migration assistant. Convert the JSONPath expression below so that it is valid under RFC 9535 (the standard implemented by @swaggerexpert/jsonpath), while preserving its exact meaning.

Apply these rules:
1. Never write a dot directly before a bracket. `a.[...]` must become `a[...]`.
2. Dot-notation member names may only contain letters, digits, `_` and non-ASCII characters. Any name containing a hyphen, space, or other punctuation must be written in bracket notation with a quoted string, e.g. `@.x-foo-bar` -&gt; `@['x-foo-bar']`, `$.some key` -&gt; `$['some key']`.
3. Filters use `?` inside brackets: `[?&lt;expr&gt;]`. Parentheses around the whole expression are optional (`[?(expr)]` and `[?expr]` are both fine); keep them if present.
4. `!@...` / `@...` are existence tests (key present or not), not truthiness tests. Keep them as existence tests unless the original clearly compares values.
5. Comparisons must be `==`, `!=`, `&lt;`, `&lt;=`, `&gt;`, `&gt;=` between singular queries or literals; use `&amp;&amp;`, `||`, `!` for logic. Replace non-standard operators (`=~`, `in`, `nin`, `size`, `empty`, `contains`) with `match()`, `search()`, `length()`, `value()`, `count()` or equivalent comparisons, and say so explicitly.
6. Replace non-standard shorthands: `$..*` is fine, but script filters `[(@.length-1)]` become `[-1]`, `@.length` becomes `length(@)`, and `$.a.b.[*]` becomes `$.a.b[*]`.
7. Do not change what the expression selects. If a fully equivalent RFC 9535 form does not exist, say so and give the closest alternative with the difference explained.

Output:
- The migrated expression on its own line in a code block.
- A short bullet list of each change and why.
- If possible, a second, shorter equivalent form.

Expression to migrate:
&lt;PASTE EXPRESSION HERE&gt;
</code></pre></div>  </div>

</details>

<h2 id="the-short-version">The short version</h2>

<ul>
  <li>Overlay <code class="language-plaintext highlighter-rouge">target</code> is JSONPath, and since Overlay 1.1.0 that means <strong>RFC 9535</strong>, for tools <em>and</em> for overlays that want to be portable.</li>
  <li>Dialects agree on the easy paths and diverge on filters, regexes, hyphenated names, and selector extensions, exactly where copy-pasted expressions live.</li>
  <li>A canonical implementation should be <strong>strict about what it consumes and generous about how it says no</strong>: clear errors and migration help, not silent dialect guessing.</li>
</ul>

<p><em>Further reading:</em> <a href="https://spec.openapis.org/overlay/v1.1.0.html">Overlay Specification 1.1.0</a> · <a href="https://www.rfc-editor.org/rfc/rfc9535.html">RFC 9535</a> · <a href="https://www.rfc-editor.org/rfc/rfc9413.html">RFC 9413</a> · <a href="/cli/">SpecLynx CLI</a> · <a href="https://github.com/speclynx/apidom/tree/main/packages/apidom-overlay"><code class="language-plaintext highlighter-rouge">@speclynx/apidom-overlay</code></a></p>]]></content><author><name>Vladimír Gorej</name></author><summary type="html"><![CDATA[OpenAPI Overlay targets are JSONPath expressions, but which JSONPath? The same overlay can apply cleanly in one tool and fail in the next. Here's why, how the dialects diverge in practice, and why a canonical implementation should be strict about what it consumes.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://speclynx.com/assets/images/blog/overlay-jsonpath-dialects.webp" /><media:content medium="image" url="https://speclynx.com/assets/images/blog/overlay-jsonpath-dialects.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">We just open-sourced SpecLynx ApiDOM</title><link href="https://speclynx.com/blog/open-sourcing-apidom/" rel="alternate" type="text/html" title="We just open-sourced SpecLynx ApiDOM" /><published>2025-12-23T09:00:00+00:00</published><updated>2025-12-23T09:00:00+00:00</updated><id>https://speclynx.com/blog/open-sourcing-apidom</id><content type="html" xml:base="https://speclynx.com/blog/open-sourcing-apidom/"><![CDATA[<p>We just open-sourced SpecLynx <strong>ApiDOM</strong>.</p>

<p>Think of it as <em>Babel.js, but for API specifications</em>.</p>

<p>ApiDOM is the semantic core behind SpecLynx. It powers every layer of the stack: the <a href="/language-service/">Language Service</a>, <a href="/openapi-toolkit/">VS Code extension</a>, <a href="https://editor.speclynx.com">browser editor</a>, and <a href="/cli/">CLI</a>.</p>

<p>It parses OpenAPI, AsyncAPI, JSON Schema, Arazzo, and Overlay specs into a unified semantic tree you can traverse, transform, and serialize back out.</p>

<p>The goal is simple:</p>

<blockquote>
  <p>Let developers work with API specs programmatically without losing the structure, style, and intent of the original file.</p>
</blockquote>

<p>Because that part matters.</p>

<p>You should be able to modify a spec and get back something that still looks like <strong>your</strong> file, not a machine-generated rewrite.</p>

<h2 id="what-you-can-build-on-it">What you can build on it</h2>

<p>SpecLynx ApiDOM is Apache-2.0 licensed, and you can use it to build your own:</p>

<ul>
  <li>✅ Linters</li>
  <li>✅ Transforms</li>
  <li>✅ Code generators</li>
  <li>✅ Migration tools</li>
  <li>✅ Spec-aware automation</li>
</ul>

<h2 id="what-we-did-to-make-it-ready">What we did to make it ready</h2>

<ul>
  <li><strong>Tree-sitter based parsing</strong>: so tooling stays useful even while specs are incomplete</li>
  <li>A <strong>semantic data model</strong>: not generic objects, but one that understands OpenAPI Operations and Schema Objects</li>
  <li><strong>Lossless roundtrip</strong>: comments, indentation, and key ordering are preserved across transformations</li>
  <li>Performance and memory efficiency for <em>large specs</em></li>
</ul>

<h2 id="why-open-source-it">Why open source it</h2>

<p>We open-sourced ApiDOM to build trust. Every line of source code is now auditable and viewable, which also makes it usable in regulated environments where that’s not a nice-to-have but a requirement.</p>

<h2 id="try-it">Try it</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install</span> @speclynx/apidom-reference
</code></pre></div></div>

<p>Parse an API specification and access its data model right away:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">parse</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@speclynx/apidom-reference</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">toValue</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@speclynx/apidom-core</span><span class="dl">'</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">parse</span><span class="p">(</span><span class="dl">'</span><span class="s1">/path/to/openapi.json</span><span class="dl">'</span><span class="p">);</span>

<span class="nx">toValue</span><span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nx">api</span><span class="p">.</span><span class="nx">info</span><span class="p">.</span><span class="nx">title</span><span class="p">);</span>   <span class="c1">// document title</span>
<span class="nx">toValue</span><span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nx">api</span><span class="p">.</span><span class="nx">info</span><span class="p">.</span><span class="nx">version</span><span class="p">);</span> <span class="c1">// document version</span>
</code></pre></div></div>

<h2 id="get-started">Get started</h2>

<ul>
  <li>GitHub: <a href="https://github.com/speclynx/apidom">speclynx/apidom</a></li>
  <li>Documentation: <a href="/apidom/">speclynx.com/apidom</a></li>
</ul>

<p>If you’ve ever had to parse, rewrite, or generate API specs: <em>what broke first?</em> <a href="https://github.com/orgs/speclynx/discussions">Tell us in the discussions</a> 👇</p>]]></content><author><name>Vladimír Gorej</name></author><summary type="html"><![CDATA[Think of it as Babel.js, but for API specifications. ApiDOM is the semantic core behind SpecLynx, now Apache-2.0 licensed, fully auditable, and ready to power your own spec tooling.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://speclynx.com/assets/images/blog/open-sourcing-apidom.webp" /><media:content medium="image" url="https://speclynx.com/assets/images/blog/open-sourcing-apidom.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>