Repository: nodejs/nodejs.dev
Pull request #2911 (2022-10-11 03:05:00)

feat(api): add link to json docs
<!--
Please read the [Code of Conduct](https://github.com/nodejs/nodejs.dev/blob/main/CODE_OF_CONDUCT.md) and the [Contributing Guidelines](https://github.com/nodejs/nodejs.dev/blob/main/CONTRIBUTING.md) before opening a pull request.
-->

## Description

This PR adds links to the JSON version of API doc pages by mirroring the `EditLink` component visually and using the `title` and `version` to build a link to the JSON docs hosted on nodejs.org.

## Related Issues

#2894

### Check List

- [x] I have read the [Contributing Guidelines](https://github.com/nodejs/nodejs.dev/blob/main/CONTRIBUTING.md) and made commit messages that follow the guideline.
- [x] I have run `npm run lint:js -- --fix` and/or `npm run lint:md -- --fix` for my JavaScript and/or Markdown changes.
  - This is important as most of the cases your code changes might not be correctly linted
- [x] I have run `npm run test` to check if all tests are passing, and/or `npm run test -- -u` to update snapshots if I created and/or updated React Components.
- [x] I have checked that the build works locally and that `npm run build` work fine.
- [x] I've covered new added functionality with unit tests if necessary.


github-actions[bot]: Please find a preview at: https://staging.nodejs.dev/2911/
sethetter: @ovflowd let me know if there's anything to address here! Also if you don't mind throwing the `hacktoberfest-accepted` label on this (if it meets standards of course) I'd greatly appreciate it :)
codecov-commenter: # [Codecov](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
Base: **66.02**% // Head: **67.53**% // Increases project coverage by **`+1.51%`** :tada:
> Coverage data is based on head [(`d4d0e12`)](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) compared to base [(`fd57b87`)](https://codecov.io/gh/nodejs/nodejs.dev/commit/fd57b871c2b1ad2f6fb812ed066dec074d76db22?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).
> Patch has no changes to coverable lines.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #2911      +/-   ##
==========================================
+ Coverage   66.02%   67.53%   +1.51%     
==========================================
  Files         118      130      +12     
  Lines        1351     1491     +140     
  Branches      342      366      +24     
==========================================
+ Hits          892     1007     +115     
- Misses        422      444      +22     
- Partials       37       40       +3     
```


| [Impacted Files](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [src/\_\_fixtures\_\_/hooks.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL19fZml4dHVyZXNfXy9ob29rcy50c3g=) | `100.00% <ø> (ø)` | |
| [src/\_\_fixtures\_\_/page.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL19fZml4dHVyZXNfXy9wYWdlLnRzeA==) | `94.11% <ø> (-5.89%)` | :arrow_down: |
| [src/components/Alert/index.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbXBvbmVudHMvQWxlcnQvaW5kZXgudHN4) | `50.00% <ø> (ø)` | |
| [src/components/AnimatedPlaceholder/index.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbXBvbmVudHMvQW5pbWF0ZWRQbGFjZWhvbGRlci9pbmRleC50c3g=) | `100.00% <ø> (ø)` | |
| [...components/ApiComponents/Components/ApiHeading.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbXBvbmVudHMvQXBpQ29tcG9uZW50cy9Db21wb25lbnRzL0FwaUhlYWRpbmcudHN4) | `100.00% <ø> (+100.00%)` | :arrow_up: |
| [...rc/components/ApiComponents/Components/ApiLink.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbXBvbmVudHMvQXBpQ29tcG9uZW50cy9Db21wb25lbnRzL0FwaUxpbmsudHN4) | `100.00% <ø> (+100.00%)` | :arrow_up: |
| [...ents/ApiComponents/Components/SourceLink/index.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbXBvbmVudHMvQXBpQ29tcG9uZW50cy9Db21wb25lbnRzL1NvdXJjZUxpbmsvaW5kZXgudHN4) | `50.00% <ø> (+50.00%)` | :arrow_up: |
| [...ApiComponents/Components/VersionSelector/index.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbXBvbmVudHMvQXBpQ29tcG9uZW50cy9Db21wb25lbnRzL1ZlcnNpb25TZWxlY3Rvci9pbmRleC50c3g=) | `100.00% <ø> (+100.00%)` | :arrow_up: |
| [src/components/ApiComponents/index.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbXBvbmVudHMvQXBpQ29tcG9uZW50cy9pbmRleC50c3g=) | `100.00% <ø> (+100.00%)` | :arrow_up: |
| [src/components/Article/index.tsx](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2NvbXBvbmVudHMvQXJ0aWNsZS9pbmRleC50c3g=) | `95.45% <ø> (-4.55%)` | :arrow_down: |
| ... and [103 more](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/nodejs/nodejs.dev/pull/2911?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).

ovflowd: Hey @sethetter I haven't had time to review this PR yet and to check the preview. Will do asap 🙃
benhalverson: Just need to resolve the conflict. Thanks for working on this issue 👍🏻 
sethetter: @ovflowd @benhalverson alright I think everything is addressed and ready to merge!
ovflowd: @sethetter I believe you still forgot to move the component to the `src/components/ApiComponents/Components` folder 👀 and export it on `src/components/ApiComponents/Components/index.ts`
github-actions[bot]: Please find a preview at: https://staging.nodejs.dev/2911/
sethetter: @ovflowd alright, feedback addressed!

Patch:
diff --git a/apiUrls.js b/apiUrls.js
index 407cb0b7..0e263788 100644
--- a/apiUrls.js
+++ b/apiUrls.js
@@ -7,4 +7,6 @@ module.exports = {
   nodeReleaseData: 'https://nodejs.org/dist/index.json',
   nodeBannersData:
     'https://raw.githubusercontent.com/nodejs/nodejs.org/main/locale/en/site.json',
+  jsonLink: (fileName, version) =>
+    `https://nodejs.org/docs/latest-${version}.x/api/${fileName}.json`,
 };
diff --git a/src/components/ApiComponents/Components/JsonLink/index.module.scss b/src/components/ApiComponents/Components/JsonLink/index.module.scss
new file mode 100644
index 00000000..ff648446
--- /dev/null
+++ b/src/components/ApiComponents/Components/JsonLink/index.module.scss
@@ -0,0 +1,29 @@
+.json {
+  display: flex;
+  flex-wrap: wrap;
+
+  a {
+    color: var(--color-text-secondary);
+    font-family: var(--sans-serif);
+    font-size: 1.4rem;
+    font-weight: var(--font-weight-regular);
+    margin-left: 0;
+    text-decoration: none !important;
+    text-transform: uppercase;
+    vertical-align: middle;
+
+    span {
+      font-weight: var(--font-weight-regular);
+      vertical-align: middle;
+    }
+
+    &:hover {
+      color: var(--brand-light);
+    }
+
+    svg {
+      margin-left: 0.5rem;
+      vertical-align: middle;
+    }
+  }
+}
diff --git a/src/components/ApiComponents/Components/JsonLink/index.tsx b/src/components/ApiComponents/Components/JsonLink/index.tsx
new file mode 100644
index 00000000..d3cafb47
--- /dev/null
+++ b/src/components/ApiComponents/Components/JsonLink/index.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faRobot } from '@fortawesome/free-solid-svg-icons';
+import { jsonLink } from '../../../../../apiUrls';
+import styles from './index.module.scss';
+
+interface Props {
+  fileName: string;
+  version: string;
+}
+
+const JsonLink = ({ fileName, version }: Props): JSX.Element | null => (
+  <div className={styles.json}>
+    <a href={jsonLink(fileName, version)}>
+      <FormattedMessage id="components.jsonLink.title" tagName="span" />
+      <FontAwesomeIcon icon={faRobot} />
+    </a>
+  </div>
+);
+
+export default JsonLink;
diff --git a/src/components/ApiComponents/Components/index.tsx b/src/components/ApiComponents/Components/index.tsx
index fd77b827..a9674c48 100644
--- a/src/components/ApiComponents/Components/index.tsx
+++ b/src/components/ApiComponents/Components/index.tsx
@@ -4,4 +4,5 @@ export { default as SourceLink } from './SourceLink';
 export { default as Changes } from './Changes';
 export { default as VersionSelector } from './VersionSelector';
 export { default as Span } from './Span';
+export { default as JsonLink } from './JsonLink';
 export * from './ApiHeading';
diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index 09c901bd..0ef9e1fa 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -21,6 +21,7 @@
   "components.downloadToggle.lts": "LTS",
   "components.downloadToggle.recommendation": "{selected, select, LTS {Recommended for most users}other {With the latest features}}",
   "components.editLink.title": "Edit this page on GitHub",
+  "components.jsonLink.title": "View as JSON",
   "components.footer.links.trademark": "Trademark Policy",
   "components.footer.links.privacy": "Privacy Policy",
   "components.footer.links.codeOfConduct": "Code of Conduct",
diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json
index 09c901bd..0ef9e1fa 100644
--- a/src/i18n/locales/es.json
+++ b/src/i18n/locales/es.json
@@ -21,6 +21,7 @@
   "components.downloadToggle.lts": "LTS",
   "components.downloadToggle.recommendation": "{selected, select, LTS {Recommended for most users}other {With the latest features}}",
   "components.editLink.title": "Edit this page on GitHub",
+  "components.jsonLink.title": "View as JSON",
   "components.footer.links.trademark": "Trademark Policy",
   "components.footer.links.privacy": "Privacy Policy",
   "components.footer.links.codeOfConduct": "Code of Conduct",
diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json
index 8f6b1442..f15b8252 100644
--- a/src/i18n/locales/fr.json
+++ b/src/i18n/locales/fr.json
@@ -21,6 +21,7 @@
   "components.downloadToggle.lts": "LTS",
   "components.downloadToggle.recommendation": "{selected, select, LTS {Recommended for most users}other {With the latest features}}",
   "components.editLink.title": "Modifier cette page sur GitHub",
+  "components.jsonLink.title": "Afficher en JSON",
   "components.footer.links.trademark": "Politique en matière de marques",
   "components.footer.links.privacy": "Politique de confidentialité",
   "components.footer.links.codeOfConduct": "Code de conduite",
diff --git a/src/i18n/locales/zh-cn.json b/src/i18n/locales/zh-cn.json
index d245a375..08964556 100644
--- a/src/i18n/locales/zh-cn.json
+++ b/src/i18n/locales/zh-cn.json
@@ -21,6 +21,7 @@
   "components.downloadToggle.lts": "LTS",
   "components.downloadToggle.recommendation": "{selected, select, LTS {Recommended for most users}other {With the latest features}}",
   "components.editLink.title": "在 GitHub 上编辑此页面",
+  "components.jsonLink.title": "View as JSON",
   "components.footer.links.trademark": "商标政策",
   "components.footer.links.privacy": "隐私政策",
   "components.footer.links.codeOfConduct": "行为准则",
diff --git a/src/sections/Article/index.tsx b/src/sections/Article/index.tsx
index c0df98da..30a17677 100644
--- a/src/sections/Article/index.tsx
+++ b/src/sections/Article/index.tsx
@@ -13,8 +13,8 @@ import styles from './index.module.scss';
 interface Props {
   title: string;
   body: string;
-  authors?: string[] | BlogPostAuthor[];
-  tableOfContents?: TableOfContentsItem[];
+  authors: string[] | BlogPostAuthor[];
+  tableOfContents: TableOfContentsItem[];
   relativePath?: string;
   absolutePath?: string;
   editPath?: string;
@@ -22,6 +22,7 @@ interface Props {
   previous?: PaginationInfo;
   blog?: boolean;
   date?: string;
+  extraLinks?: JSX.Element[];
   children?: React.ReactNode;
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   extraComponents?: Record<string, (...any: any[]) => JSX.Element | null>;
@@ -54,6 +55,7 @@ const Article = ({
   blog,
   date,
   children,
+  extraLinks = [],
   extraComponents = {},
   childrenPosition = 'after',
 }: Props): JSX.Element => (
@@ -77,6 +79,7 @@ const Article = ({
           relativePath={relativePath}
           editPath={editPath}
         />
+        {extraLinks}
         <ArticleComponents.Pagination previous={previous} next={next} />
       </>
     )}
diff --git a/src/templates/api.tsx b/src/templates/api.tsx
index 92f4f6d5..9243bf2f 100644
--- a/src/templates/api.tsx
+++ b/src/templates/api.tsx
@@ -76,6 +76,13 @@ const Api = ({
           previous={previous}
           absolutePath={`https://github.com/nodejs/node/edit/main/doc/api/${title}.md`}
           authors={[]}
+          extraLinks={[
+            <ApiComponents.JsonLink
+              key={0}
+              version={version}
+              fileName={title}
+            />,
+          ]}
           extraComponents={components}
           childrenPosition="before"
         >


Test patch:
diff --git a/src/components/ApiComponents/Components/__tests__/__snapshots__/index.test.tsx.snap b/src/components/ApiComponents/Components/__tests__/__snapshots__/index.test.tsx.snap
index bbd11954..7d687837 100644
--- a/src/components/ApiComponents/Components/__tests__/__snapshots__/index.test.tsx.snap
+++ b/src/components/ApiComponents/Components/__tests__/__snapshots__/index.test.tsx.snap
@@ -31,3 +31,34 @@ exports[`ApiComponents Components renders H5 component correctly 1`] = `
   />
 </div>
 `;
+
+exports[`ApiComponents Components renders JsonLink component correctly 1`] = `
+<div>
+  <div
+    class="json"
+  >
+    <a
+      href="https://nodejs.org/docs/latest-v18.x/api/cli.json"
+    >
+      <span>
+        View as JSON
+      </span>
+      <svg
+        aria-hidden="true"
+        class="svg-inline--fa fa-robot "
+        data-icon="robot"
+        data-prefix="fas"
+        focusable="false"
+        role="img"
+        viewBox="0 0 640 512"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <path
+          d="M320 0c17.7 0 32 14.3 32 32V96H480c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H160c-35.3 0-64-28.7-64-64V160c0-35.3 28.7-64 64-64H288V32c0-17.7 14.3-32 32-32zM208 384c-8.8 0-16 7.2-16 16s7.2 16 16 16h32c8.8 0 16-7.2 16-16s-7.2-16-16-16H208zm96 0c-8.8 0-16 7.2-16 16s7.2 16 16 16h32c8.8 0 16-7.2 16-16s-7.2-16-16-16H304zm96 0c-8.8 0-16 7.2-16 16s7.2 16 16 16h32c8.8 0 16-7.2 16-16s-7.2-16-16-16H400zM264 256c0-22.1-17.9-40-40-40s-40 17.9-40 40s17.9 40 40 40s40-17.9 40-40zm152 40c22.1 0 40-17.9 40-40s-17.9-40-40-40s-40 17.9-40 40s17.9 40 40 40zM48 224H64V416H48c-26.5 0-48-21.5-48-48V272c0-26.5 21.5-48 48-48zm544 0c26.5 0 48 21.5 48 48v96c0 26.5-21.5 48-48 48H576V224h16z"
+          fill="currentColor"
+        />
+      </svg>
+    </a>
+  </div>
+</div>
+`;
diff --git a/src/components/ApiComponents/Components/__tests__/index.test.tsx b/src/components/ApiComponents/Components/__tests__/index.test.tsx
index 10198407..7d3391f7 100644
--- a/src/components/ApiComponents/Components/__tests__/index.test.tsx
+++ b/src/components/ApiComponents/Components/__tests__/index.test.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import { render } from '@testing-library/react';
-import { ApiLink, H5, H4, H3 } from '..';
+import { ApiLink, H5, H4, H3, JsonLink } from '..';
 
 describe('ApiComponents Components', (): void => {
   it('renders ApiLink component correctly', () => {
@@ -28,4 +28,9 @@ describe('ApiComponents Components', (): void => {
     const { container } = render(<H3 id={id} />);
     expect(container).toMatchSnapshot();
   });
+
+  it('renders JsonLink component correctly', () => {
+    const { container } = render(<JsonLink fileName="cli" version="v18" />);
+    expect(container).toMatchSnapshot();
+  });
 });
diff --git a/src/sections/Article/__tests__/index.test.tsx b/src/sections/Article/__tests__/index.test.tsx
index 67fc6d1d..19701f40 100644
--- a/src/sections/Article/__tests__/index.test.tsx
+++ b/src/sections/Article/__tests__/index.test.tsx
@@ -63,7 +63,7 @@ describe('Article component', () => {
     const { container } = render(
       <Article
         title={title}
-        tableOfContents={tableOfContents?.items}
+        tableOfContents={tableOfContents?.items || []}
         body={body}
         next={next}
         previous={previous}
@@ -93,7 +93,7 @@ describe('Article component', () => {
     const { container } = render(
       <Article
         title={title}
-        tableOfContents={tableOfContents?.items}
+        tableOfContents={tableOfContents?.items || []}
         body={body}
         next={next}
         previous={previous}
@@ -120,7 +120,7 @@ describe('Article component', () => {
     const { container } = render(
       <Article
         title={title}
-        tableOfContents={tableOfContents?.items}
+        tableOfContents={tableOfContents?.items || []}
         body={body}
         next={next}
         previous={previous}
@@ -176,7 +176,7 @@ describe('Article component', () => {
     render(
       <Article
         title={title}
-        tableOfContents={tableOfContents?.items}
+        tableOfContents={tableOfContents?.items || []}
         body={body}
         next={next}
         previous={previous}
@@ -202,7 +202,7 @@ describe('Article component', () => {
     const { container } = render(
       <Article
         title={title}
-        tableOfContents={tableOfContents?.items}
+        tableOfContents={tableOfContents?.items || []}
         body={body}
         next={next}
         previous={previous}
diff --git a/util-node/__tests__/__snapshots__/getNodeReleasesData.test.ts.snap b/util-node/__tests__/__snapshots__/getNodeReleasesData.test.ts.snap
index ce14f1a2..17d0491e 100644
--- a/util-node/__tests__/__snapshots__/getNodeReleasesData.test.ts.snap
+++ b/util-node/__tests__/__snapshots__/getNodeReleasesData.test.ts.snap
@@ -1,3 +1,3 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`getNodeReleasesData should retrieve data from correct URL 1`] = `"{"nodeReleasesData":[{"fullVersion":"vv0.8","codename":"v0.8","isLts":false,"status":"Pending","initialRelease":"","ltsStart":"","maintenanceStart":"","endOfLife":""},{"fullVersion":"vv0.10","codename":"v0.10","isLts":false,"status":"Pending","initialRelease":"","ltsStart":"","maintenanceStart":"","endOfLife":""},{"fullVersion":"v0.8","version":"v0.8","codename":"v0.8","isLts":false,"status":"End-of-life","initialRelease":"2012-06-25","ltsStart":"","maintenanceStart":"","endOfLife":"2014-07-31"},{"fullVersion":"v0.10","version":"v0.10","codename":"v0.10","isLts":false,"status":"Current","initialRelease":"2013-03-11","ltsStart":"","maintenanceStart":"","endOfLife":"9999-01-01"}],"apiAvailableVersions":["v18"]}"`;
+exports[`getNodeReleasesData should retrieve data from correct URL 1`] = `"{"nodeReleasesData":[{"fullVersion":"vv0.8","codename":"v0.8","isLts":false,"status":"Pending","initialRelease":"","ltsStart":"","maintenanceStart":"","endOfLife":""},{"fullVersion":"vv0.10","codename":"v0.10","isLts":false,"status":"Pending","initialRelease":"","ltsStart":"","maintenanceStart":"","endOfLife":""},{"fullVersion":"v0.8","version":"v0.8","codename":"v0.8","isLts":false,"status":"End-of-life","initialRelease":"2012-06-25","ltsStart":"","maintenanceStart":"","endOfLife":"2014-07-31"},{"fullVersion":"v0.10","version":"v0.10","codename":"v0.10","isLts":false,"status":"Current","initialRelease":"2013-03-11","ltsStart":"","maintenanceStart":"","endOfLife":"9999-01-01"}],"apiAvailableVersions":["v18","v19"]}"`;