Skip to content

Commit 688791a

Browse files
authored
feat: api reference updates and agentic abilities (#197)
1 parent 8ac789d commit 688791a

1,492 files changed

Lines changed: 389333 additions & 678675 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: update-api-docs
2+
3+
# Regenerates content/api when a new @nativescript/core version is released.
4+
#
5+
# Triggered by a repository_dispatch sent from NativeScript/NativeScript when
6+
# a core release tag (e.g. "9.0.21-core") is pushed — see the
7+
# notify_docs_core_release.yml workflow in that repo. Can also be run
8+
# manually for any published version.
9+
10+
on:
11+
repository_dispatch:
12+
types: [core-release]
13+
workflow_dispatch:
14+
inputs:
15+
version:
16+
description: '@nativescript/core version to generate docs for'
17+
required: false
18+
default: 'latest'
19+
20+
# Needed by peter-evans/create-pull-request (push branch + open PR)
21+
permissions:
22+
contents: write
23+
pull-requests: write
24+
25+
jobs:
26+
regenerate:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v4
30+
- name: Setup Node
31+
uses: actions/setup-node@v4
32+
with:
33+
node-version: 22.14.0
34+
- name: Resolve target version
35+
run: |
36+
VERSION="${{ github.event.client_payload.version || inputs.version || 'latest' }}"
37+
echo "CORE_VERSION=$VERSION" >> "$GITHUB_ENV"
38+
- name: Install dependencies
39+
run: yarn
40+
- name: Update @nativescript/core
41+
run: yarn add -D @nativescript/core@$CORE_VERSION
42+
- name: Regenerate API reference
43+
run: yarn generate:api-docs
44+
env:
45+
# Used for the GitHub tree lookup that validates "Defined in" source links
46+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47+
- name: Open PR if the API changed
48+
uses: peter-evans/create-pull-request@v6
49+
with:
50+
commit-message: 'chore(api): regenerate API reference for @nativescript/core@${{ env.CORE_VERSION }}'
51+
title: 'chore(api): regenerate API reference (@nativescript/core@${{ env.CORE_VERSION }})'
52+
body: |
53+
Automated regeneration of `content/api` for `@nativescript/core@${{ env.CORE_VERSION }}`.
54+
55+
Generated with `yarn generate:api-docs`.
56+
branch: chore/update-api-docs
57+
delete-branch: true

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ node_modules
44
# content/api/**/*
55
.vitepress/dist
66
.vitepress/cache
7+
tmp/
8+
.wrangler/
79

810
explore/
911

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# generated API reference (yarn generate:api-docs)
2+
content/api/
3+
content/public/api-index.json

.textlintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# generated API reference (yarn generate:api-docs)
2+
content/api/**

.vitepress/config.mts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { defineConfig } from 'vitepress'
2-
import apiSidebar from '../content/api/sidebar.json'
2+
import llmstxt from 'vitepress-plugin-llms'
3+
import typedocSidebar from '../content/api/typedoc-sidebar.json'
34
import mainSidebar from '../content/sidebar'
45
import uiSidebar from '../content/ui/sidebar'
56
import pluginsSidebar from '../content/plugins/sidebar'
@@ -12,6 +13,14 @@ import { SiteMap } from './genSitemap.mjs'
1213
const isDev = process.env.NODE_ENV !== 'production'
1314
const branch = process.env.CF_PAGES_BRANCH ?? 'main'
1415

16+
const apiSidebar = [
17+
{
18+
text: 'API Reference',
19+
link: '/api/',
20+
},
21+
...typedocSidebar,
22+
]
23+
1524
const sitemap = new SiteMap()
1625
const baseUrl = 'https://docs.nativescript.org'
1726
function toUrl(path: string) {
@@ -45,6 +54,16 @@ export default defineConfig({
4554
ssr: {
4655
noExternal: ['@nativescript/vitepress-theme'],
4756
},
57+
plugins: [
58+
llmstxt({
59+
domain: 'https://docs.nativescript.org',
60+
title: 'NativeScript',
61+
description:
62+
'NativeScript empowers you to access native platform APIs from JavaScript directly. Develop iOS, Android and visionOS apps with TypeScript, Angular, Vue, React, Svelte or Solid.',
63+
// also emit /index.md for the home page (default skips it)
64+
excludeIndexPage: false,
65+
}),
66+
],
4867
},
4968
themeConfig: {
5069
editLink: {
@@ -72,7 +91,21 @@ export default defineConfig({
7291
},
7392
markdown: {
7493
headers: true,
75-
theme: "github-dark"
94+
theme: "github-dark",
95+
config(md) {
96+
// Inject the "Copy page" button (markdown/LLM/MCP actions) at the top
97+
// of every page body, right below the theme-rendered title.
98+
md.core.ruler.push('copy-page-button', (state) => {
99+
// only inject into full page renders (not inline snippets like
100+
// custom container titles), and only for actual doc pages
101+
if (state.inlineMode) return
102+
if (!state.env?.relativePath) return
103+
if (state.env?.frontmatter?.copyPage === false) return
104+
const token = new state.Token('html_block', '', 0)
105+
token.content = '<CopyPageButton />\n'
106+
state.tokens.unshift(token)
107+
})
108+
},
76109
},
77110
async transformPageData(pageData, { siteConfig }) {
78111
// const contributors = await githubAuthors.getAuthorsForFilePath(
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
<script setup lang="ts">
2+
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
3+
import { useData } from 'vitepress'
4+
5+
const { page } = useData()
6+
7+
const SITE_ORIGIN = 'https://docs.nativescript.org'
8+
const MCP_URL = `${SITE_ORIGIN}/mcp`
9+
10+
const open = ref(false)
11+
const copied = ref(false)
12+
const root = ref<HTMLElement | null>(null)
13+
14+
// mirrors the vitepress-plugin-llms output layout: "dir/index.md" twins are
15+
// written to "/dir.md"; the root "index.md" keeps its name
16+
const mdPath = computed(() => {
17+
const rel = '/' + page.value.relativePath
18+
if (rel !== '/index.md' && rel.endsWith('/index.md')) {
19+
return rel.slice(0, -'/index.md'.length) + '.md'
20+
}
21+
return rel
22+
})
23+
const mdUrl = computed(() => SITE_ORIGIN + mdPath.value)
24+
25+
const chatGptUrl = computed(
26+
() =>
27+
'https://chatgpt.com/?hints=search&q=' +
28+
encodeURIComponent(`Read ${mdUrl.value} so I can ask questions about it.`)
29+
)
30+
const claudeUrl = computed(
31+
() =>
32+
'https://claude.ai/new?q=' +
33+
encodeURIComponent(`Read ${mdUrl.value} so I can ask questions about it.`)
34+
)
35+
36+
const cursorDeeplink = computed(() => {
37+
const config = btoa(JSON.stringify({ url: MCP_URL }))
38+
return `cursor://anysphere.cursor-deeplink/mcp/install?name=nativescript&config=${config}`
39+
})
40+
const vscodeDeeplink = computed(() => {
41+
const config = JSON.stringify({
42+
name: 'nativescript',
43+
type: 'http',
44+
url: MCP_URL,
45+
})
46+
return `vscode:mcp/install?${encodeURIComponent(config)}`
47+
})
48+
49+
async function copyMarkdown() {
50+
try {
51+
const res = await fetch(mdPath.value + location.search)
52+
const text = res.ok ? await res.text() : mdUrl.value
53+
await navigator.clipboard.writeText(text)
54+
} catch {
55+
await navigator.clipboard.writeText(mdUrl.value)
56+
}
57+
copied.value = true
58+
setTimeout(() => (copied.value = false), 2000)
59+
open.value = false
60+
}
61+
62+
async function copyMcpConfig() {
63+
const config = {
64+
mcpServers: {
65+
nativescript: { url: MCP_URL },
66+
},
67+
}
68+
await navigator.clipboard.writeText(JSON.stringify(config, null, 2))
69+
copied.value = true
70+
setTimeout(() => (copied.value = false), 2000)
71+
open.value = false
72+
}
73+
74+
function onClickOutside(event: MouseEvent) {
75+
if (root.value && !root.value.contains(event.target as Node)) {
76+
open.value = false
77+
}
78+
}
79+
80+
onMounted(() => document.addEventListener('click', onClickOutside))
81+
onBeforeUnmount(() => document.removeEventListener('click', onClickOutside))
82+
</script>
83+
84+
<template>
85+
<div ref="root" class="copy-page">
86+
<div class="copy-page-group">
87+
<button class="copy-page-main" type="button" @click="copyMarkdown">
88+
<svg
89+
class="copy-page-icon"
90+
viewBox="0 0 16 16"
91+
fill="none"
92+
stroke="currentColor"
93+
stroke-width="1.5"
94+
aria-hidden="true"
95+
>
96+
<rect x="5" y="5" width="8" height="9" rx="1.5" />
97+
<path d="M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-5A1.5 1.5 0 0 0 3 3.5v7A1.5 1.5 0 0 0 4.5 12H5" />
98+
</svg>
99+
{{ copied ? 'Copied!' : 'Copy page' }}
100+
</button>
101+
<button
102+
class="copy-page-toggle"
103+
type="button"
104+
aria-label="More copy options"
105+
:aria-expanded="open"
106+
@click="open = !open"
107+
>
108+
<svg
109+
class="copy-page-icon"
110+
viewBox="0 0 16 16"
111+
fill="none"
112+
stroke="currentColor"
113+
stroke-width="1.5"
114+
aria-hidden="true"
115+
>
116+
<path d="M4 6l4 4 4-4" />
117+
</svg>
118+
</button>
119+
</div>
120+
121+
<div v-if="open" class="copy-page-menu">
122+
<button type="button" class="copy-page-item" @click="copyMarkdown">
123+
<span class="copy-page-item-title">Copy page as Markdown</span>
124+
<span class="copy-page-item-desc">Copy this page as Markdown for LLMs</span>
125+
</button>
126+
<a class="copy-page-item" :href="mdPath" target="_blank" rel="noopener" @click="open = false">
127+
<span class="copy-page-item-title">View as Markdown</span>
128+
<span class="copy-page-item-desc">Open this page as plain Markdown</span>
129+
</a>
130+
<a class="copy-page-item" :href="chatGptUrl" target="_blank" rel="noopener" @click="open = false">
131+
<span class="copy-page-item-title">Open in ChatGPT</span>
132+
<span class="copy-page-item-desc">Ask questions about this page</span>
133+
</a>
134+
<a class="copy-page-item" :href="claudeUrl" target="_blank" rel="noopener" @click="open = false">
135+
<span class="copy-page-item-title">Open in Claude</span>
136+
<span class="copy-page-item-desc">Ask questions about this page</span>
137+
</a>
138+
<div class="copy-page-divider" />
139+
<a class="copy-page-item" :href="cursorDeeplink" @click="open = false">
140+
<span class="copy-page-item-title">Install MCP in Cursor</span>
141+
<span class="copy-page-item-desc">Add the NativeScript docs MCP server</span>
142+
</a>
143+
<a class="copy-page-item" :href="vscodeDeeplink" @click="open = false">
144+
<span class="copy-page-item-title">Install MCP in VS Code</span>
145+
<span class="copy-page-item-desc">Add the NativeScript docs MCP server</span>
146+
</a>
147+
<button type="button" class="copy-page-item" @click="copyMcpConfig">
148+
<span class="copy-page-item-title">Copy MCP config</span>
149+
<span class="copy-page-item-desc">For Claude Code, Windsurf and others</span>
150+
</button>
151+
</div>
152+
</div>
153+
</template>
154+
155+
<style scoped>
156+
.copy-page {
157+
position: relative;
158+
display: inline-block;
159+
margin: 0.25rem 0 1rem;
160+
font-size: 0.8125rem;
161+
line-height: 1;
162+
}
163+
164+
.copy-page-group {
165+
display: inline-flex;
166+
align-items: stretch;
167+
border: 1px solid rgba(128, 128, 128, 0.35);
168+
border-radius: 8px;
169+
overflow: hidden;
170+
}
171+
172+
.copy-page-main,
173+
.copy-page-toggle {
174+
display: inline-flex;
175+
align-items: center;
176+
gap: 0.375rem;
177+
padding: 0.45rem 0.65rem;
178+
background: transparent;
179+
color: inherit;
180+
cursor: pointer;
181+
font: inherit;
182+
font-weight: 500;
183+
}
184+
185+
.copy-page-toggle {
186+
border-left: 1px solid rgba(128, 128, 128, 0.35);
187+
padding: 0.45rem 0.45rem;
188+
}
189+
190+
.copy-page-main:hover,
191+
.copy-page-toggle:hover,
192+
.copy-page-item:hover {
193+
background: rgba(128, 128, 128, 0.12);
194+
}
195+
196+
.copy-page-icon {
197+
width: 14px;
198+
height: 14px;
199+
flex: none;
200+
}
201+
202+
.copy-page-menu {
203+
position: absolute;
204+
z-index: 30;
205+
top: calc(100% + 4px);
206+
left: 0;
207+
min-width: 280px;
208+
padding: 0.25rem;
209+
border: 1px solid rgba(128, 128, 128, 0.35);
210+
border-radius: 10px;
211+
background: var(--copy-page-menu-bg, #fff);
212+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
213+
}
214+
215+
:global(html.dark) .copy-page-menu {
216+
--copy-page-menu-bg: #1b1b1f;
217+
}
218+
219+
.copy-page-item {
220+
display: flex;
221+
flex-direction: column;
222+
gap: 0.15rem;
223+
width: 100%;
224+
padding: 0.45rem 0.55rem;
225+
border-radius: 6px;
226+
background: transparent;
227+
color: inherit;
228+
cursor: pointer;
229+
font: inherit;
230+
text-align: left;
231+
text-decoration: none;
232+
}
233+
234+
.copy-page-item-title {
235+
font-weight: 500;
236+
}
237+
238+
.copy-page-item-desc {
239+
font-size: 0.72rem;
240+
opacity: 0.65;
241+
}
242+
243+
.copy-page-divider {
244+
margin: 0.25rem 0;
245+
border-top: 1px solid rgba(128, 128, 128, 0.25);
246+
}
247+
</style>

.vitepress/theme/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import Theme from "@nativescript/vitepress-theme";
22
import "@nativescript/vitepress-theme/theme/style.css";
3+
import CopyPageButton from "./CopyPageButton.vue";
34

45
export default {
5-
...Theme(),
6+
...Theme((ctx) => {
7+
ctx.app.component("CopyPageButton", CopyPageButton);
8+
}),
69
};

0 commit comments

Comments
 (0)